UPD. Оригинальная статья достаточно старая — 2010 года. Сейчас ситуация выглядит по-другому.
В декабре 2010 у Reddit-а было 829М просмотров и 119 серверов.
В конце 2011 года — 2,07B просмотров и 240 серверов.
Спасибо potomushto за актуализацию.
UPD 2. Поправил схему для людей с проблемами цветовосприятия. Спасибо second_pilot и spiritedflow
Стив Хаффман, один из создателей Reddit, рассказал на презентации, чему они научились, пока строили и развивали Reddit до 7,5 млн пользователей в месяц, 270 миллионов просмотров страниц в месяц и более 20 серверов баз данных.
Стив уточнил, что большинство полученных уроков были очевидными, поэтому в презентации не будет радикально новых идей. Но у Стива огромный опыт, и если он не смог увидеть эти грабли, то возможно, вам стоит обратить внимание на эти «очевидные вещи».
Каждый из 7 уроков будет рассмотрен в соответствующей секции.
Наиболее интересным пунктом архитектуры Reddit является «Урок 6 — сохраняйте избыточные данные». Основная идея очень проста — мы достигаем скорости, сделав предрасчет всего и закешировав его. Reddit использует предрасчет по максимуму. Складывается впечатление, что все что вы видите на Reddit, было вычислено заранее и закешировано, вне зависимости от того, сколько версий данных им приходится хранить. Например, они кешируют все 15 способов сортировки сообщений (горячие, новые, лучшие старые, эта недели и т.п.) для списка сообщений, как только кто-то добавит ссылку. Обычные разработчики побоятся делать настолько экстремальный кеш, считая его пустой тратой ресурсов. Но команда Reddit думает, что лучше потратить немного ресурсов, чем тормозить. Тратить дисковое пространство и память лучше, чем заставлять пользователей ждать. Так что, если вы стеснялись использовать предрасчет и кеширование по максимуму, у вас есть хороший прецедент.
Суть урока проста — автоматически перезапускайте упавшие или сбойнувшие сервисы.
Проблема с использованием выделенных серверов заключается в том, что вы постоянно отвечаете за их поддержку. Когда ваш сервис падает, вы должны починить его прямо сейчас, даже в 2 часа ночи. Это создает постоянное фоновое напряжение в вашей жизни. Вы должны постоянно таскать с собой компьютер, и вы знаете, что в любой момент кто-то может позвонить, чтобы сообщить об очередной катастрофе. Которую придется разгребать. Такой подход делает жизнь несносной.
Один из методов решения этой проблемы — перезапустить сервис, который умер или стал вести себя некорректно. Reddit использует супервизоров для перезапуска приложений. Специальные программы мониторинга убивают процессы, которые съедают слишком много памяти, процессорного времени или просто подвисли. Вместо беспокойств — просто перезапустите систему. Конечно, вам придется прочитать логи, чтобы понять причину падения. Но подобный подход позволит сохранить вам спокойствие и рассудок.
Суть урока — группируйте похожие процессы и данные на разных машинах.
Выполнять слишком много действий на одной машине потребует большого переключения контекстов для задач. Попробуйте сделать так, чтобы каждый ваш сервер обслуживал определенный тип данных определенным образом. Это значит, что все ваши индексы попадут в кеш, и не будут из него вываливаться. Держите похожие данные как можно ближе друг к другу. Не используйте Python-овские потоки. Они тормозят. Разработчики Reddit разделили все на несколько сервисов. Сервисами являются проверка на спам, обработка картинок и кеширование запросов. Это позволяет легко разнести их на несколько машин. Таким образом они решили проблему взаимодействий процессов. А когда эта проблема решена, архитектура становится чище, и расти становится проще.
Суть урока — не волнуйтесь насчет схемы.
Разработчики Reddit, потратили кучу времени, беспокоясь структуре данных и их нормализации. Изменения схемы становились все дороже и дороже по мере роста. Добавление одной колонки к 10 миллионам строк требовало кучу блокировок, и очень плохо работало. Для масштабирования и резервного копирования в Reddit использовали репликацию. Обновление схема и поддержка репликации — тяжкий труд. Иногда приходилось перезапускать репликацию, и резервное копирование могло не работать целый день. Релизы также доставляли проблемы, потому что приходилось следить за тем, чтобы обновление ПО и обновление схемы БД прошли одновременно.
Вместо этого, они используют Таблицу Сущностей и Таблицу Данных. В Reddit-e все является сущностью — пользователи, ссылки, комментарии, подфорумы, награды и т.п. Сущности разделяют несколько общих атрибутов, например голоса за\против, тип, дата создания. Таблица Данных содержит 3 колонки — thing id, key, value. По строке на каждый атрибут. Есть строка для заголовка, для ссылки, автора, голосов за спам и т.д. Теперь, при добавлении новой возможности им не приходится волноваться о структуре базы данных. Не надо добавлять новые таблицы для новых сущностей или волноваться об обновлениях. Легче в разработке и сопровождении. Цена — невозможность использовать классные реляционные возможности. Нельзя использовать join-ы и вы должны вручную обеспечивать целостность данных. Вам не надо беспокоиться о внешних ключах при join-ах, или о том, как разделить данные. В целом, получилось неплохо. Беспокойства о реляционных базах данных остались в прошлом.
Цель каждого сервера простая — обрабатывать запрос любого типа. И пока Reddit рос, им пришлось использовать все больше машин, и уже нельзя было полагаться на кеш сервера приложений. Изначально они дублировали состояние каждого сервера приложений, что было пустой тратой оперативной памяти. Они не могли использовать memcached, поскольку держали в памяти огромное количество мелких данных, что не давало прироста в скорости. Они переписали сервис для поддержки memcache и больше не хранят состояние в серверах приложений. Даже если сервера приложений падают — жизнь не останавливается. И масштабирование теперь просто вопрос добавления новых серверов.
Суть урока — используйте memcache для всего.
Reddit исопльзует memcache для:
Теперь они хранят все данные в Memcachedb, а не Postgres. Это аналог memcache, но сохраняет данные на диск. Очень быстрое решение. Все запросы генерируются одним и тем же куском кода и кешируются в memcache. Измененные пароли, ссылки кешируются на 20 минут или около того. То же самое можно сказать про капчи. Они используют такой же подход для ссылок, которые не хотят хранить вечно.
Они встроили в свой фреймворк мемоизацию. Вычисляемые результаты тоже кешируются: нормализированные страницы, списки и все остальное.
Они ограничивают количество запросов используя memcache + ограниченное время жизни запроса. Неплохой способ, чтобы защитить вашу систему от атак. Без подобной подсистемы, любой недобросовестный пользователь мог бы положить системы. Не фен-шуй. Поэтому для пользователей и индексаторов они хранят данные в memcache. Если пользователь совершает повторное обращение меньше чем за секунду — от отфутболивается. Обычные пользователи не кликают так быстро, поэтому они ничего не замечают. Индексатор Гугла будет обрабатывать вас так часто, как вы позволите, поэтому когда все начинает тормозить, просто ограничьте частоту запросов. И система начнет работать спокойнее, не создавая неудобств для пользователей.
Все в Reddit-е это список. Главная странице, личные сообщения, страница комментариев. Все они просчитаны заранее и помещены в кеш. Когда вы получаете список, он берется из кеша. Каждая ссылка и каждый комментарий скорее всего сохранены в 100 разных вариаций. Например ссылка с 2 голосами, созданная 30 секунд назад ренедерится и сохраняется отдельно. Через 30 секунд она рендерится снова. И так далее. Каждый кусочек HTML приходит из кеша. Поэтому на рендеринг страниц процессорное время не тратится. Если все начнет тормозить — просто добавьте больше кеша.
Когда им приходитя работать с их неконсистентной базой данных, они используют memcache как глобальную блокировку. Работает, хоть это и не лучший вариант.
Суть урока: чтобы добиться максимальной скорости — просчитайте все заранее и закешируйте результат.
Гарантированный способ сделать медленный веб сайт — иметь нормализованную базу данных, обращаться к ней по требованию, и потом сгенерировать HTML. Это занимает вечность даже для одного запроса. Поэтому, если у вас есть данные, которые могут отображаться в нескольких форматах, ссылки на главной странице, во входящих сообщениях, профилях, храните все эти представления отдельно. Но когда кто-то приходит и обращается к данным — они уже готовы.
У каждого списка может быть 15 различных порядков сортировки(горячие, новые, лучшие, старые, текущая неделя). Когда кто-то добавляет новую ссылку, они пересчитывают все списки, которых это может касаться. На первый взгляд это выглядит слишком растратно, но лучше потратиться сначала, чем тормозить. Тратить попусту дисковое пространство и память — лучше, чем заставлять пользователя ждать.
Суть урока: сделайте минимум по серверной части, и скажите пользователю, что все готово.
Если вам необходимо что-то сделать, делайте это тогда, когда пользователь вас не ждет. Поставьте задание в очередь. Когда пользователь голосует на Reddit, обновляются списки, карма пользователя и множество других вещей. Поэтому при голосовании обновляется база данных, чтобы отметить факт голосования. После этого задание ставится в очередь, и задание знает все 20 вещей, которые необходимо обновить. Когда пользователь вернется, все необходимые данные будут закешированы.
Что Reddit делает в фоновом режиме:
Нет никакой необходимости делать эти вещи, пока пользователь вас ждет. Например, когда Reddit стал популярным, попытки накрутки рейтинга участились. Поэтому они тратят много серверного времени для обнаружения таких ситуаций. Работа этого сервиса в фоне не мешает пользователям голосовать дальше.
Ниже предоставлена диаграмма архитектуры:
![](https://habrastorage.org/r/w780q1/storage2/be6/4d9/6e3/be64d96e3b34f09e4484afb29df34793.jpg)
Синие стрелки обозначают, что происходит при получении запроса. Допустим, кто-то оставляет ссылку или голосует. Эти данные идут в кеш, главную базу данных, и в очередь работ. Результат возвращается пользователю. Остальные вещи, которые происходят в оффлайне, представлены желтыми стрелками. Сервисы типа Spam, Precomputer, и Thumnailer получают задания из очереди, выполняют их, и обновляют базу данных. Основная изюминка технологического решения — RabbitMQ.
P.S. Очень любопытно сравнить уроки Reddit с практиками проектирования приложений на Erlang. Let it fail, Supervision tree, mnesia. Русский перевод документации к OTP можно посмотретьздесь.
P.P.S. Есть идея перевести пару глав из RabbitMQ in Action. Насколько такое будет интересно?
В декабре 2010 у Reddit-а было 829М просмотров и 119 серверов.
В конце 2011 года — 2,07B просмотров и 240 серверов.
Спасибо potomushto за актуализацию.
UPD 2. Поправил схему для людей с проблемами цветовосприятия. Спасибо second_pilot и spiritedflow
Стив Хаффман, один из создателей Reddit, рассказал на презентации, чему они научились, пока строили и развивали Reddit до 7,5 млн пользователей в месяц, 270 миллионов просмотров страниц в месяц и более 20 серверов баз данных.
Стив уточнил, что большинство полученных уроков были очевидными, поэтому в презентации не будет радикально новых идей. Но у Стива огромный опыт, и если он не смог увидеть эти грабли, то возможно, вам стоит обратить внимание на эти «очевидные вещи».
Каждый из 7 уроков будет рассмотрен в соответствующей секции.
- Падайте часто
- Разделение сервисов
- Открытая схема данных
- Избегайте хранения состояний
- Memcache
- Сохраняйте избыточные данные
- Выполняйте максимум работы в фоновом режиме
Наиболее интересным пунктом архитектуры Reddit является «Урок 6 — сохраняйте избыточные данные». Основная идея очень проста — мы достигаем скорости, сделав предрасчет всего и закешировав его. Reddit использует предрасчет по максимуму. Складывается впечатление, что все что вы видите на Reddit, было вычислено заранее и закешировано, вне зависимости от того, сколько версий данных им приходится хранить. Например, они кешируют все 15 способов сортировки сообщений (горячие, новые, лучшие старые, эта недели и т.п.) для списка сообщений, как только кто-то добавит ссылку. Обычные разработчики побоятся делать настолько экстремальный кеш, считая его пустой тратой ресурсов. Но команда Reddit думает, что лучше потратить немного ресурсов, чем тормозить. Тратить дисковое пространство и память лучше, чем заставлять пользователей ждать. Так что, если вы стеснялись использовать предрасчет и кеширование по максимуму, у вас есть хороший прецедент.
Урок 1: Падайте часто
Суть урока проста — автоматически перезапускайте упавшие или сбойнувшие сервисы.
Проблема с использованием выделенных серверов заключается в том, что вы постоянно отвечаете за их поддержку. Когда ваш сервис падает, вы должны починить его прямо сейчас, даже в 2 часа ночи. Это создает постоянное фоновое напряжение в вашей жизни. Вы должны постоянно таскать с собой компьютер, и вы знаете, что в любой момент кто-то может позвонить, чтобы сообщить об очередной катастрофе. Которую придется разгребать. Такой подход делает жизнь несносной.
Один из методов решения этой проблемы — перезапустить сервис, который умер или стал вести себя некорректно. Reddit использует супервизоров для перезапуска приложений. Специальные программы мониторинга убивают процессы, которые съедают слишком много памяти, процессорного времени или просто подвисли. Вместо беспокойств — просто перезапустите систему. Конечно, вам придется прочитать логи, чтобы понять причину падения. Но подобный подход позволит сохранить вам спокойствие и рассудок.
Урок 2: Разделение сервисов
Суть урока — группируйте похожие процессы и данные на разных машинах.
Выполнять слишком много действий на одной машине потребует большого переключения контекстов для задач. Попробуйте сделать так, чтобы каждый ваш сервер обслуживал определенный тип данных определенным образом. Это значит, что все ваши индексы попадут в кеш, и не будут из него вываливаться. Держите похожие данные как можно ближе друг к другу. Не используйте Python-овские потоки. Они тормозят. Разработчики Reddit разделили все на несколько сервисов. Сервисами являются проверка на спам, обработка картинок и кеширование запросов. Это позволяет легко разнести их на несколько машин. Таким образом они решили проблему взаимодействий процессов. А когда эта проблема решена, архитектура становится чище, и расти становится проще.
Урок 3: Открытая схема базы данных
Суть урока — не волнуйтесь насчет схемы.
Разработчики Reddit, потратили кучу времени, беспокоясь структуре данных и их нормализации. Изменения схемы становились все дороже и дороже по мере роста. Добавление одной колонки к 10 миллионам строк требовало кучу блокировок, и очень плохо работало. Для масштабирования и резервного копирования в Reddit использовали репликацию. Обновление схема и поддержка репликации — тяжкий труд. Иногда приходилось перезапускать репликацию, и резервное копирование могло не работать целый день. Релизы также доставляли проблемы, потому что приходилось следить за тем, чтобы обновление ПО и обновление схемы БД прошли одновременно.
Вместо этого, они используют Таблицу Сущностей и Таблицу Данных. В Reddit-e все является сущностью — пользователи, ссылки, комментарии, подфорумы, награды и т.п. Сущности разделяют несколько общих атрибутов, например голоса за\против, тип, дата создания. Таблица Данных содержит 3 колонки — thing id, key, value. По строке на каждый атрибут. Есть строка для заголовка, для ссылки, автора, голосов за спам и т.д. Теперь, при добавлении новой возможности им не приходится волноваться о структуре базы данных. Не надо добавлять новые таблицы для новых сущностей или волноваться об обновлениях. Легче в разработке и сопровождении. Цена — невозможность использовать классные реляционные возможности. Нельзя использовать join-ы и вы должны вручную обеспечивать целостность данных. Вам не надо беспокоиться о внешних ключах при join-ах, или о том, как разделить данные. В целом, получилось неплохо. Беспокойства о реляционных базах данных остались в прошлом.
Урок 4: Избегайте хранения состояний
Цель каждого сервера простая — обрабатывать запрос любого типа. И пока Reddit рос, им пришлось использовать все больше машин, и уже нельзя было полагаться на кеш сервера приложений. Изначально они дублировали состояние каждого сервера приложений, что было пустой тратой оперативной памяти. Они не могли использовать memcached, поскольку держали в памяти огромное количество мелких данных, что не давало прироста в скорости. Они переписали сервис для поддержки memcache и больше не хранят состояние в серверах приложений. Даже если сервера приложений падают — жизнь не останавливается. И масштабирование теперь просто вопрос добавления новых серверов.
Урок 5: Memcache
Суть урока — используйте memcache для всего.
Reddit исопльзует memcache для:
- Данных базы данных
- Сессионных данные
- Сгенерированных страницх
- Мемоизации (кеширование ранее вычисленных результатов) внутренних функций
- Ограничения на количество запросов
- Хранения предрасчитанных списков и страниц
- Глобальных блокировок
Теперь они хранят все данные в Memcachedb, а не Postgres. Это аналог memcache, но сохраняет данные на диск. Очень быстрое решение. Все запросы генерируются одним и тем же куском кода и кешируются в memcache. Измененные пароли, ссылки кешируются на 20 минут или около того. То же самое можно сказать про капчи. Они используют такой же подход для ссылок, которые не хотят хранить вечно.
Они встроили в свой фреймворк мемоизацию. Вычисляемые результаты тоже кешируются: нормализированные страницы, списки и все остальное.
Они ограничивают количество запросов используя memcache + ограниченное время жизни запроса. Неплохой способ, чтобы защитить вашу систему от атак. Без подобной подсистемы, любой недобросовестный пользователь мог бы положить системы. Не фен-шуй. Поэтому для пользователей и индексаторов они хранят данные в memcache. Если пользователь совершает повторное обращение меньше чем за секунду — от отфутболивается. Обычные пользователи не кликают так быстро, поэтому они ничего не замечают. Индексатор Гугла будет обрабатывать вас так часто, как вы позволите, поэтому когда все начинает тормозить, просто ограничьте частоту запросов. И система начнет работать спокойнее, не создавая неудобств для пользователей.
Все в Reddit-е это список. Главная странице, личные сообщения, страница комментариев. Все они просчитаны заранее и помещены в кеш. Когда вы получаете список, он берется из кеша. Каждая ссылка и каждый комментарий скорее всего сохранены в 100 разных вариаций. Например ссылка с 2 голосами, созданная 30 секунд назад ренедерится и сохраняется отдельно. Через 30 секунд она рендерится снова. И так далее. Каждый кусочек HTML приходит из кеша. Поэтому на рендеринг страниц процессорное время не тратится. Если все начнет тормозить — просто добавьте больше кеша.
Когда им приходитя работать с их неконсистентной базой данных, они используют memcache как глобальную блокировку. Работает, хоть это и не лучший вариант.
Урок 6: Сохраняйте избыточные данные
Суть урока: чтобы добиться максимальной скорости — просчитайте все заранее и закешируйте результат.
Гарантированный способ сделать медленный веб сайт — иметь нормализованную базу данных, обращаться к ней по требованию, и потом сгенерировать HTML. Это занимает вечность даже для одного запроса. Поэтому, если у вас есть данные, которые могут отображаться в нескольких форматах, ссылки на главной странице, во входящих сообщениях, профилях, храните все эти представления отдельно. Но когда кто-то приходит и обращается к данным — они уже готовы.
У каждого списка может быть 15 различных порядков сортировки(горячие, новые, лучшие, старые, текущая неделя). Когда кто-то добавляет новую ссылку, они пересчитывают все списки, которых это может касаться. На первый взгляд это выглядит слишком растратно, но лучше потратиться сначала, чем тормозить. Тратить попусту дисковое пространство и память — лучше, чем заставлять пользователя ждать.
Урок 7: Делайте максимум работы в фоновом режиме
Суть урока: сделайте минимум по серверной части, и скажите пользователю, что все готово.
Если вам необходимо что-то сделать, делайте это тогда, когда пользователь вас не ждет. Поставьте задание в очередь. Когда пользователь голосует на Reddit, обновляются списки, карма пользователя и множество других вещей. Поэтому при голосовании обновляется база данных, чтобы отметить факт голосования. После этого задание ставится в очередь, и задание знает все 20 вещей, которые необходимо обновить. Когда пользователь вернется, все необходимые данные будут закешированы.
Что Reddit делает в фоновом режиме:
- Кешируют списки
- Обрабатывают картинки
- Обнаруживают читеров
- Удаляют спам
- Вычисляют награды
- Обновляют поисковый индекс
Нет никакой необходимости делать эти вещи, пока пользователь вас ждет. Например, когда Reddit стал популярным, попытки накрутки рейтинга участились. Поэтому они тратят много серверного времени для обнаружения таких ситуаций. Работа этого сервиса в фоне не мешает пользователям голосовать дальше.
Ниже предоставлена диаграмма архитектуры:
![](https://habrastorage.org/storage2/be6/4d9/6e3/be64d96e3b34f09e4484afb29df34793.jpg)
Синие стрелки обозначают, что происходит при получении запроса. Допустим, кто-то оставляет ссылку или голосует. Эти данные идут в кеш, главную базу данных, и в очередь работ. Результат возвращается пользователю. Остальные вещи, которые происходят в оффлайне, представлены желтыми стрелками. Сервисы типа Spam, Precomputer, и Thumnailer получают задания из очереди, выполняют их, и обновляют базу данных. Основная изюминка технологического решения — RabbitMQ.
P.S. Очень любопытно сравнить уроки Reddit с практиками проектирования приложений на Erlang. Let it fail, Supervision tree, mnesia. Русский перевод документации к OTP можно посмотретьздесь.
P.P.S. Есть идея перевести пару глав из RabbitMQ in Action. Насколько такое будет интересно?