Перевод на русский https://github.com/donnemartin/system-design-primer
  • Python 75.4%
  • Shell 18.8%
  • CSS 5.3%
  • JavaScript 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-30 23:48:05 +03:00
.forgejo/workflows fix(ci): диагностика шага Release - длина токена, HTTP-код и тело ответа 2026-08-30 23:48:05 +03:00
images Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
resources Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
solutions Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
.gitattributes Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
.gitignore PDF: убрать дублирующий титульный блок, самоочистка временных файлов, *.pdf в gitignore 2026-08-30 15:21:28 +03:00
CONTRIBUTING.md Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
epub-metadata.yaml Настройка сборки EPUB на русском языке 2026-08-30 12:23:26 +03:00
generate-cheatsheet.sh Шпаргалка: компактный PDF-справочник на 1 лист А4 + сборка в релизном пайплайне 2026-08-30 18:01:04 +03:00
generate-epub.sh Настройка сборки EPUB на русском языке 2026-08-30 12:23:26 +03:00
generate-pdf.sh Шпаргалка: компактный PDF-справочник на 1 лист А4 + сборка в релизном пайплайне 2026-08-30 18:01:04 +03:00
LICENSE.txt Русский перевод System Design Primer 2026-08-30 12:13:12 +03:00
md_transform.py Шпаргалка: компактный PDF-справочник на 1 лист А4 + сборка в релизном пайплайне 2026-08-30 18:01:04 +03:00
pdf-cheatsheet.css Шпаргалка: компактный PDF-справочник на 1 лист А4 + сборка в релизном пайплайне 2026-08-30 18:01:04 +03:00
pdf-footer.js Пайплайн релизов: PDF вместо EPUB (pandoc+weasyprint в CI, markdown-pdf локально) 2026-08-30 13:02:57 +03:00
pdf-style.css PDF: внутренние ссылки-переходы, контроль разрывов страниц, масштабирование картинок (weasyprint по умолчанию) 2026-08-30 15:13:41 +03:00
README.md chore: удаление ссылок на переводы и шаблона pull request 2026-08-30 22:38:24 +03:00

Введение в проектирование систем (The System Design Primer)


Мотивация

Узнайте, как проектировать системы большого масштаба.

Подготовьтесь к собеседованию по проектированию систем.

Как научиться проектировать системы большого масштаба

Изучение того, как проектировать масштабируемые системы, поможет вам стать лучше инженером.

Проектирование систем — обширная тема. В сети огромное количество разрозненных ресурсов о принципах проектирования систем.

Этот репозиторий — упорядоченная коллекция ресурсов, которая поможет вам научиться строить системы большого масштаба.

Учитесь у сообщества open source

Это проект с открытым исходным кодом, который постоянно обновляется.

Вклады приветствуются!

Подготовка к собеседованию по проектированию систем

Помимо кодировочных собеседований, проектирование систем — обязательная часть технического интервью во многих технологических компаниях.

Практикуйтесь на типичных вопросах собеседования по проектированию систем и сравнивайте свои решения с образцовыми: обсуждения, код и схемы.

Дополнительные темы для подготовки к собеседованию:

Карточки Anki


Предоставленные наборы карточек Anki используют интервальное повторение, чтобы помочь вам запомнить ключевые концепции проектирования систем.

Отлично подходят для использования в дороге.

Ресурс для программирования: Интерактивные задачи по кодированию

Ищете ресурсы, которые помогут подготовиться к собеседованию по кодированию?


Загляните в «родственный» репозиторий Interactive Coding Challenges, где есть дополнительный набор карточек Anki:

Как внести вклад

Учитесь у сообщества.

Свободно отправляйте pull request'ы, чтобы помочь:

  • Исправлять ошибки
  • Улучшать разделы
  • Добавлять новые разделы
  • Переводить

Материалы, которым нужна доработка, вынесены в раздел «в разработке».

Ознакомьтесь с правилами внесения вклада.

Список тем по проектированию систем

Краткие описания различных тем проектирования систем, включая плюсы и минусы. Всё — это компромисс.

Каждый раздел содержит ссылки на более глубокие материалы.


Памятка для изучения

Рекомендуемые темы для повторения в зависимости от ваших сроков подготовки к собеседованию (короткие, средние, длительные).

Imgur

В: Для собеседования мне нужно знать всё из этого?

О: Нет, чтобы подготовиться к собеседованию, не нужно знать всё из этого.

То, что вас спросят на собеседовании, зависит от таких факторов, как:

  • Сколько у вас опыта
  • Каков ваш технический бэкграунд
  • На какие позиции вы претендуете
  • В каких компаниях вы проходите собеседование
  • Удача

От более опытных кандидатов обычно ожидают большего знания проектирования систем. От архитекторов или тимлидов могут ожидать больше, чем от рядовых разработчиков. Ведущие технологические компании, скорее всего, проводят один или несколько раундов собеседования по дизайну.

Начинайте широко и углубляйтесь в нескольких областях. Полезно немного разбираться в различных ключевых темах проектирования систем. Адаптируйте следующую памятку под ваши сроки, опыт, позиции, на которые вы претендуете, и компании, в которых вы проходите собеседование.

  • Короткие сроки - Цель — широта в темах по проектированию систем. Практикуйтесь, решая некоторые вопросы собеседования.
  • Средние сроки - Цель — широта и некоторая глубина в темах по проектированию систем. Практикуйтесь, решая много вопросов собеседования.
  • Длительные сроки - Цель — широта и больше глубины в темах по проектированию систем. Практикуйтесь, решая большинство вопросов собеседования.
Короткие Средние Длительные
Прочитать темы по проектированию систем, чтобы получить общее представление о том, как работают системы 👍 👍 👍
Прочитать несколько статей в инженерных блогах компаний, в которых вы проходите собеседование 👍 👍 👍
Прочитать несколько архитектур реальных систем 👍 👍 👍
Повторить как подходить к вопросу на собеседовании по проектированию систем 👍 👍 👍
Разобрать вопросы собеседования по проектированию систем с решениями Некоторые Много Большинство
Разобрать вопросы собеседования по объектно-ориентированному дизайну с решениями Некоторые Много Большинство
Повторить дополнительные вопросы собеседования по проектированию систем Некоторые Много Большинство

Как подходить к вопросам системного дизайна на собеседовании

Как подойти к решению вопроса по системному дизайну на собеседовании.

Собеседование по системному дизайну — это открытая беседа. Ожидается, что именно вы будете её вести.

Вы можете использовать следующие шаги, чтобы направлять обсуждение. Чтобы закрепить этот процесс, проработайте раздел Вопросы по системному дизайну с решениями с помощью этих шагов.

Шаг 1: Определите сценарии использования, ограничения и допущения

Соберите требования и определите рамки задачи. Задавайте вопросы, чтобы уточнить сценарии использования и ограничения. Обсудите допущения.

  • Кто будет пользоваться системой?
  • Как они будут её использовать?
  • Сколько будет пользователей?
  • Что делает система?
  • Каковы входные данные и результат работы системы?
  • Какой объём данных мы ожидаем обработать?
  • Сколько запросов в секунду мы ожидаем?
  • Каково ожидаемое соотношение числа чтений и записей?

Шаг 2: Создайте высокоуровневый дизайн

Опишите высокоуровневый дизайн со всеми важными компонентами.

  • Схематично изобразите основные компоненты и связи между ними
  • Обоснуйте свои идеи

Шаг 3: Спроектируйте ключевые компоненты

Разберите каждый ключевой компонент в деталях. Например, если вас попросили спроектировать сервис сокращения URL, обсудите:

  • Генерация и хранение хэша полного URL
    • MD5 и Base62
    • Коллизии хэшей
    • SQL или NoSQL
    • Схема базы данных
  • Преобразование хэшированного URL в полный URL
    • Поиск в базе данных
  • API и объектно-ориентированный дизайн

Шаг 4: Масштабируйте дизайн

Учитывая ограничения, выявите и устраните узкие места. Например, понадобятся ли вам следующие средства для решения проблем масштабируемости?

  • Балансировщик нагрузки
  • Горизонтальное масштабирование
  • Кэширование
  • Шардирование базы данных

Обсудите возможные решения и компромиссы. Всё — это компромисс. Устраняйте узкие места, опираясь на принципы проектирования масштабируемых систем.

Расчёты «на салфетке»

Вас могут попросить выполнить приблизительную оценку вручную. За следующими материалами обратитесь к Приложению:

Источник(и) и дополнительное чтение

Ознакомьтесь со следующими ссылками, чтобы лучше понять, чего ожидать:

Вопросы по системному дизайну с решениями

Типичные вопросы по системному дизайну на собеседовании с примерами обсуждения, кода и диаграммами.

Решения связаны с содержимым папки solutions/.

Вопрос
Спроектируйте Pastebin.com (или Bit.ly) Решение
Спроектируйте ленту и поиск Twitter (или ленту и поиск Facebook) Решение
Спроектируйте веб-краулер Решение
Спроектируйте Mint.com Решение
Спроектируйте структуры данных для социальной сети Решение
Спроектируйте хранилище «ключ-значение» для поисковой системы Решение
Спроектируйте функцию Amazon с рейтингом продаж по категориям Решение
Спроектируйте систему, масштабирующуюся до миллионов пользователей в AWS Решение
Добавить вопрос по системному дизайну Внести вклад

Спроектируйте Pastebin.com (или Bit.ly)

Посмотреть упражнение и решение

Imgur

Спроектируйте ленту и поиск Twitter (или ленту и поиск Facebook)

Посмотреть упражнение и решение

Imgur

Спроектируйте веб-краулер

Посмотреть упражнение и решение

Imgur

Спроектируйте Mint.com

Посмотреть упражнение и решение

Imgur

Спроектируйте структуры данных для социальной сети

Посмотреть упражнение и решение

Imgur

Спроектируйте хранилище «ключ-значение» для поисковой системы

Посмотреть упражнение и решение

Imgur

Спроектируйте функцию Amazon с рейтингом продаж по категориям

Посмотреть упражнение и решение

Imgur

Спроектируйте систему, масштабирующуюся до миллионов пользователей в AWS

Посмотреть упражнение и решение

Imgur

Вопросы по объектно-ориентированному дизайну с решениями

Типичные вопросы по объектно-ориентированному дизайну на собеседовании с примерами обсуждения, кода и диаграммами.

Решения связаны с содержимым папки solutions/.

Примечание: этот раздел находится в разработке

Вопрос
Спроектируйте хэш-таблицу Решение
Спроектируйте кэш с вытеснением давно не использовавшихся элементов (LRU) Решение
Спроектируйте колл-центр Решение
Спроектируйте колоду игральных карт Решение
Спроектируйте парковку Решение
Спроектируйте сервер чата Решение
Спроектируйте циклический массив Внести вклад
Добавить вопрос по объектно-ориентированному дизайну Внести вклад

Темы системного дизайна: начните отсюда

Вы новичок в системном дизайне?

Сначала вам необходимо базовое представление об общепринятых принципах: что они собой представляют, как применяются и каковы их плюсы и минусы.

Шаг 1: Просмотрите видеолекцию о масштабируемости

Лекция о масштабируемости в Гарварде

  • Охваченные темы:
    • Вертикальное масштабирование
    • Горизонтальное масштабирование
    • Кэширование
    • Балансировка нагрузки
    • Репликация базы данных
    • Партиционирование базы данных

Шаг 2: Прочитайте статью о масштабируемости

Масштабируемость

Дальнейшие шаги

Далее мы рассмотрим высокоуровневые компромиссы:

  • Производительность vs масштабируемость
  • Латентность vs пропускная способность
  • Доступность vs согласованность

Помните, что всё есть компромисс.

Затем мы перейдём к более конкретным темам, таким как DNS, CDN и балансировщики нагрузки.

Производительность и масштабируемость

Сервис считается масштабируемым, если его производительность растёт пропорционально добавляемым ресурсам. Обычно рост производительности означает обслуживание большего объёма работы, но это может также означать способность обрабатывать более крупные единицы работы, например при увеличении наборов данных.1

Другой способ посмотреть на производительность и масштабируемость:

  • Если у вас проблема с производительностью, ваша система медленна для одного пользователя.
  • Если у вас проблема с масштабируемостью, ваша система быстра для одного пользователя, но медленна под высокой нагрузкой.

Источник(и) и дополнительное чтение

Латентность и пропускная способность

Латентность — время выполнения какого-либо действия или получения результата.

Пропускная способность — количество таких действий или результатов за единицу времени.

Обычно следует стремиться к максимальной пропускной способности при допустимой латентности.

Источник(и) и дополнительное чтение

Доступность и согласованность

Теорема CAP


Источник: CAP theorem revisited

В распределённой компьютерной системе можно обеспечить только две из следующих гарантий:

  • Согласованность — каждое обращение на чтение получает самое свежее значение записи или ошибку
  • Доступность — каждый запрос получает ответ, без гарантии, что в нём содержится самая свежая версия информации
  • Толерантность к разделению — система продолжает работу при произвольном разделении из-за сбоев сети

Сети ненадёжны, поэтому вам придётся поддерживать толерантность к разделению. Придётся сделать программный компромисс между согласованностью и доступностью.

CP — согласованность и толерантность к разделению

Ожидание ответа от узла в разделе может привести к ошибке тайм-аута. CP — хороший выбор, если потребности вашего бизнеса требуют атомарных чтений и записей.

AP — доступность и толерантность к разделению

Ответы возвращают наиболее легко доступную версию данных, имеющуюся на любом узле, которая может оказаться не самой последней. Записям может потребоваться некоторое время, чтобы распространиться после разрешения раздела.

AP — хороший выбор, если бизнес допускает конечную согласованность, или когда системе необходимо продолжать работу несмотря на внешние ошибки.

Источник(и) и дополнительное чтение

Паттерны согласованности

При наличии нескольких копий одних и тех же данных мы сталкиваемся с выбором того, как их синхронизировать, чтобы клиенты имели согласованное представление о данных. Вспомните определение согласованности из теоремы CAP — каждое обращение на чтение получает самое свежее значение записи или ошибку.

Слабая согласованность

После записи обращения на чтение могут увидеть её, а могут и нет. Применяется подход «как получится».

Такой подход встречается в системах вроде memcached. Слабая согласованность хорошо работает в сценариях реального времени, таких как VoIP, видеочат и мультиплеерные игры в реальном времени. Например, если вы разговариваете по телефону и связь пропадает на несколько секунд, то, когда соединение восстановится, вы не услышите то, что было сказано во время обрыва связи.

Конечная согласованность

После записи обращения на чтение рано или поздно увидят её (обычно в течение миллисекунд). Данные реплицируются асинхронно.

Такой подход встречается в системах вроде DNS и электронной почты. Конечная согласованность хорошо работает в высокодоступных системах.

Сильная согласованность

После записи обращения на чтение увидят её. Данные реплицируются синхронно.

Такой подход встречается в файловых системах и RDBMS. Сильная согласованность хорошо работает в системах, которым нужны транзакции.

Источник(и) и дополнительное чтение

Паттерны доступности

Существуют два взаимодополняющих паттерна для обеспечения высокой доступности: фейловер (fail-over) и репликация.

Фейловер (Fail-over)

Активно-пассивный

При активно-пассивном фейловере между активным сервером и пассивным сервером, находящимся в режиме ожидания, отправляются сигналы жизни (heartbeat). Если heartbeat прерывается, пассивный сервер забирает IP-адрес активного и возобновляет обслуживание.

Длительность простоя определяется тем, находится ли пассивный сервер уже в работе в режиме «горячего» ожидания или ему нужно запуститься из «холодного» резерва. Обработку трафика выполняет только активный сервер.

Активно-пассивный фейловер также называют фейловером мастер-реплика (master-slave).

Активно-активный

В режиме активно-активного оба сервера управляют трафиком, распределяя нагрузку между собой.

Если серверы обращены наружу, то DNS должен знать публичные IP-адреса обоих серверов. Если серверы внутренние, то приложение должно знать о обоих серверах.

Активно-активный фейловер также называют фейловером мастер-мастер (master-master).

Недостаток(и): фейловер

  • Fail-over требует дополнительного оборудования и повышенной сложности.
  • Возможна потеря данных, если активная система выйдет из строя до того, как вновь записанные данные смогут быть реплицированы на пассивную.

Репликация

Master-slave и master-master

Эта тема обсуждается подробнее в разделе Database:

Доступность в цифрах

Доступность часто выражают через аптайм (или даунтайм) — долю времени, в течение которого сервис доступен. Обычно доступность измеряют количеством девяток — сервис с доступностью 99,99% описывается как имеющий четыре девятки.

Доступность 99,9% — три девятки

Duration Acceptable downtime
Downtime per year 8h 45min 57s
Downtime per month 43m 49.7s
Downtime per week 10m 4.8s
Downtime per day 1m 26.4s

Доступность 99,99% — четыре девятки

Duration Acceptable downtime
Downtime per year 52min 35.7s
Downtime per month 4m 23s
Downtime per week 1m 5s
Downtime per day 8.6s

Доступность при параллельном и последовательном соединении

Если сервис состоит из нескольких компонентов, подверженных отказам, то общая доступность сервиса зависит от того, подключены ли компоненты последовательно или параллельно.

Последовательно

Общая доступность снижается, когда два компонента с доступностью < 100% соединены последовательно:

Availability (Total) = Availability (Foo) * Availability (Bar)

Если у обоих Foo и Bar по отдельности доступность 99,9%, их общая доступность в последовательном соединении составит 99,8%.

Параллельно

Общая доступность возрастает, когда два компонента с доступностью < 100% соединены параллельно:

Availability (Total) = 1 - (1 - Availability (Foo)) * (1 - Availability (Bar))

Если у обоих Foo и Bar по отдельности доступность 99,9%, их общая доступность в параллельном соединении составит 99,9999%.

Система доменных имён (Domain name system)


Источник: презентация о безопасности DNS

Система доменных имён (DNS) преобразует доменное имя, например www.example.com, в IP-адрес.

DNS иерархична, на верхнем уровне находится несколько авторитетных серверов. Ваш роутер или ISP предоставляет информацию о том, к каким DNS-серверам обращаться при поиске. Серверы DNS более низкого уровня кешируют соответствия, которые могут устаревать из-за задержек распространения (пропагации) в DNS. Результаты DNS также могут кешироваться вашим браузером или ОС в течение определённого периода времени, задаваемого временем жизни (time to live (TTL)).

  • Запись NS (name server) — задаёт DNS-серверы для вашего домена/поддомена.
  • Запись MX (mail exchange) — задаёт почтовые серверы для приёма сообщений.
  • Запись A (address) — указывает имя на IP-адрес.
  • CNAME (canonical) — указывает имя на другое имя или CNAME (example.com на www.example.com) либо на запись A.

Сервисы вроде CloudFlare и Route 53 предоставляют управляемые DNS-сервисы. Некоторые DNS-сервисы умеют маршрутизировать трафик различными способами:

  • Weighted round robin
    • Не пропускать трафик на серверы, находящиеся на обслуживании
    • Сбалансировать нагрузку между кластерами разного размера
    • A/B-тестирование
  • Latency-based
  • Geolocation-based

Недостаток(и): DNS

  • Обращение к DNS-серверу вносит небольшую задержку, хотя она смягчается кэшированием, описанным выше.
  • Управление DNS-серверами может быть сложным и обычно осуществляется правительствами, ISP и крупными компаниями.
  • На DNS-сервисы в последнее время неоднократно совершались атаки DDoS, из-за которых пользователи не могли получить доступ к сайтам вроде Twitter, не зная IP-адрес(ов) Twitter.

Источник(и) и дополнительное чтение

Сеть доставки контента (Content delivery network)


Источник: зачем нужна CDN

Сеть доставки контента (CDN) — глобально распределённая сеть прокси-серверов, обслуживающая контент из местностей ближе к пользователю. Как правило, из CDN раздаются статические файлы — HTML/CSS/JS, фотографии и видео, хотя некоторые CDN, например CloudFront от Amazon, поддерживают и динамический контент. Разрешение доменного имени сайта сообщает клиентам, к какому серверу обращаться.

Раздача контента из CDN может существенно повысить производительность двумя способами:

  • Пользователи получают контент из дата-центров рядом с ними
  • Вашим серверам не приходится обслуживать запросы, которые удовлетворяет CDN

Push-CDN

Push-CDN получает новый контент всякий раз, когда на вашем сервере происходят изменения. Вы полностью отвечаете за предоставление контента: загружаете его непосредственно в CDN и переписываете URL так, чтобы они указывали на CDN. Можно настроить, когда контент истекает и когда обновляется. Контент загружается только когда он новый или изменился — это минимизирует трафик, но максимизирует занимаемое хранилище.

Хорошо подходят push-CDN сайты с небольшим объёмом трафика или сайты с контентом, который редко обновляется. Контент размещается в CDN один раз, вместо того чтобы регулярно подгружаться заново.

Pull-CDN

Pull-CDN тянет новый контент с вашего сервера, когда контент запрашивает первый пользователь. Вы оставляете контент на своём сервере и переписываете URL так, чтобы они указывали на CDN. Из-за этого запрос выполняется медленнее, пока контент не будет закэширован в CDN.

Время жизни (time-to-live (TTL)) определяет, как долго контент хранится в кэше. Pull-CDN минимизируют занятое место на CDN, но могут создавать избыточный трафик, если файлы истекают и подтягиваются раньше, чем фактически изменятся.

Хорошо подходят pull-CDN сайты с большим трафиком, поскольку нагрузка распределяется более равномерно, а на CDN остаётся только недавно запрашиваемый контент.

Недостаток(и): CDN

  • Стоимость CDN может быть значительной в зависимости от трафика, однако её следует сопоставить с дополнительными расходами, которые вы понесёте, не используя CDN.
  • Контент может устареть, если он будет обновлён до истечения TTL.
  • Для CDN требуется изменять URL статического контента так, чтобы они указывали на CDN.

Источник(и) и дополнительное чтение

Балансировщик нагрузки


Источник: паттерны масштабируемой архитектуры систем

Балансировщики нагрузки распределяют входящие клиентские запросы по вычислительным ресурсам, таким как application-серверы и базы данных. В каждом случае балансировщик нагрузки возвращает ответ от вычислительного ресурса соответствующему клиенту. Балансировщики нагрузки эффективно решают следующие задачи:

  • Предотвращают поступление запросов на нездоровые серверы
  • Предотвращают перегрузку ресурсов
  • Помогают устранить единую точку отказа

Балансировщики нагрузки можно реализовать на оборудовании (дорого) или с помощью ПО, такого как HAProxy.

Дополнительные преимущества включают:

  • Терминация SSL — расшифровывать входящие запросы и шифровать ответы серверов, чтобы backend-серверам не приходилось выполнять эти потенциально дорогостоящие операции
  • Персистентность сессий — выдавать куки и маршрутизировать запросы конкретного клиента на один и тот же инстанс, если веб-приложения не ведут учёт сессий

Чтобы защититься от отказов, обычно разворачивают несколько балансировщиков нагрузки, либо в режиме активно-пассивного, либо в режиме активно-активного.

Балансировщики нагрузки могут маршрутизировать трафик на основе различных метрик, включая:

Балансировка нагрузки на 4-м уровне

Балансировщики нагрузки 4-го уровня смотрят на информацию транспортного слоя, чтобы решить, как распределять запросы. Как правило, это исходный и конечный IP-адреса и порты в заголовке, но не содержимое пакета. Балансировщики 4-го уровня пересылают сетевые пакеты к upstream-серверу и от него, выполняя трансляцию сетевых адресов (Network Address Translation (NAT)).

Балансировка нагрузки на 7-м уровне

Балансировщики нагрузки 7-го уровня смотрят на прикладной слой, чтобы решить, как распределять запросы. Это может включать содержимое заголовка, сообщения и кук. Балансировщики 7-го уровня терминируют сетевой трафик, читают сообщение, принимают решение о балансировке, а затем открывают соединение с выбранным сервером. Например, балансировщик 7-го уровня может направлять видеотрафик на серверы, на которых размещены видео, а более чувствительный трафик по расчётам за услуги пользователей — на усиленные по безопасности серверы.

В ущерб гибкости балансировка на 4-м уровне требует меньше времени и вычислительных ресурсов, чем на 7-м, хотя на современном типичном оборудовании влияние на производительность может быть минимальным.

Горизонтальное масштабирование

Балансировщики нагрузки также помогают с горизонтальным масштабированием, улучшая производительность и доступность. Горизонтальное масштабирование за счёт типовых недорогих машин экономически выгоднее и обеспечивает бо́льшую доступность, чем наращивание мощности одного сервера на более дорогом оборудовании, называемое вертикальным масштабированием. Кроме того, проще искать специалистов, работающих с типовым оборудованием, чем со специализированными корпоративными системами.

Недостаток(и): горизонтальное масштабирование

  • Горизонтальное масштабирование вносит сложность и предполагает клонирование серверов
    • Серверы должны быть без состояния (stateless): они не должны содержать никаких пользовательских данных, таких как сессии или фотографии профилей
    • Сессии можно хранить в централизованном хранилище данных, таком как база данных (SQL, NoSQL) или постоянный кэш (Redis, Memcached)
  • Нижестоящим серверам, таким как кэши и базы данных, придётся обрабатывать больше одновременных соединений по мере того, как вышестоящие серверы будут горизонтально масштабироваться

Недостаток(и): балансировщик нагрузки

  • Балансировщик нагрузки может стать узким местом по производительности, если у него недостаточно ресурсов или он неправильно настроен.
  • Внедрение балансировщика нагрузки для устранения единой точки отказа приводит к увеличению сложности.
  • Единственный балансировщик нагрузки — это единая точка отказа; настройка нескольких балансировщиков дополнительно увеличивает сложность.

Источник(и) и дополнительное чтение

Обратный прокси (веб-сервер)


Источник: Wikipedia

Реверс-прокси — это веб-сервер, централизующий внутренние сервисы и предоставляющий публике единые интерфейсы. Запросы от клиентов пересылаются на сервер, способный их удовлетворить, после чего реверс-прокси возвращает ответ сервера клиенту.

Дополнительные преимущества включают:

  • Повышенная безопасность — скрывать информацию о backend-серверах, блокировать IP по чёрному списку, ограничивать число подключений на одного клиента
  • Повышенная масштабируемость и гибкость — клиенты видят только IP-адрес реверс-прокси, что позволяет масштабировать серверы или менять их конфигурацию
  • Терминация SSL — расшифровывать входящие запросы и шифровать ответы серверов, чтобы backend-серверам не приходилось выполнять эти потенциально дорогостоящие операции
  • Сжатие — сжимать ответы серверов
  • Кэширование — возвращать ответ для закэшированных запросов
  • Статический контент — раздавать статический контент напрямую
    • HTML/CSS/JS
    • Фотографии
    • Видео
    • И т. д.

Балансировщик нагрузки против обратного прокси

  • Внедрение балансировщика нагрузки полезно, когда у вас несколько серверов. Часто балансировщики направляют трафик на набор серверов, выполняющих одну и ту же функцию.
  • Реверс-прокси может быть полезен даже при наличии всего одного веб-сервера или application-сервера, открывая преимущества, описанные в предыдущем разделе.
  • Решения вроде NGINX и HAProxy поддерживают как реверс-проксирование на 7-м уровне, так и балансировку нагрузки.

Недостаток(и): обратный прокси

  • Внедрение реверс-прокси приводит к увеличению сложности.
  • Единственный реверс-прокси — это единая точка отказа; настройка нескольких реверс-прокси (например, организация фейловера) дополнительно увеличивает сложность.

Источник(и) и дополнительное чтение

Прикладной слой


Источник: Введение в проектирование систем для масштабирования

Выделение веб-слоя из прикладного слоя (также известного как платформенный слой) позволяет масштабировать и настраивать оба слоя независимо. Добавление нового API приводит к добавлению серверов приложения без необходимости добавлять дополнительные веб-серверы. Принцип единственной ответственности поощряет небольшие автономные сервисы, которые работают совместно. Небольшие команды с небольшими сервисами могут более агрессивно планировать быстрый рост.

Работники (workers) в прикладном слое также помогают обеспечить асинхронность.

Микросервисы

Связанным с этим обсуждением является концепция микросервисов, которую можно описать как набор небольших модульных сервисов, развёртываемых независимо. Каждый сервис работает в отдельном процессе и общается через хорошо определённый лёгкомеханический канал для достижения бизнес-цели. 1

Например, у Pinterest могли быть следующие микросервисы: профиль пользователя, подписчики, лента, поиск, загрузка фото и т. д.

Поиск сервисов (Service Discovery)

Системы вроде Consul, Etcd и Zookeeper могут помочь сервисам находить друг друга, отслеживая зарегистрированные имена, адреса и порты. Проверки здоровья помогают убедиться в работоспособности сервиса и обычно выполняются с помощью HTTP-эндпоинта. В обоих Consul и Etcd есть встроенное хранилище «ключ-значение», которое может оказаться полезным для хранения значений конфигурации и других общих данных.

Недостаток(и): прикладной слой

  • Добавление прикладного слоя с слабо связанными сервисами требует другого подхода с точки зрения архитектуры, эксплуатации и процессов (в отличие от монолитной системы).
  • Микросервисы могут добавить сложность в части развёртывания и эксплуатации.

Источник(и) и дополнительное чтение

База данных


Источник: Масштабирование до первых 10 миллионов пользователей

Реляционная система управления базами данных (RDBMS)

Реляционная база данных, подобная SQL, представляет собой собрание элементов данных, организованных в таблицы.

ACID — это набор свойств транзакций реляционной базы данных.

  • Атомарность — каждая транзакция выполняется полностью или не выполняется вовсе
  • Согласованность — любая транзакция переводит базу данных из одного корректного состояния в другое
  • Изолированность — параллельное выполнение транзакций даёт тот же результат, что и их последовательное выполнение
  • Долговечность — как только транзакция зафиксирована, она сохранится

Существует много техник масштабирования реляционной базы данных: репликация мастер-реплик, мастер-мастер репликация, федерация, шардирование, денормализация и настройка SQL.

Репликация мастер-реплик

Мастер обслуживает чтения и записи, реплицируя записи на один или несколько репликов, которые обслуживают только чтения. Реплики также могут реплицироваться на дополнительные реплики в древовидной структуре. Если мастер выходит из строя, система может продолжать работу в режиме только для чтения, пока один из репликов не будет назначен мастером или не будет выделен новый мастер.


Источник: Масштабируемость, доступность, стабильность, паттерны

Недостаток(и): репликация мастер-реплик
  • Требуется дополнительная логика для назначения репликации мастеру.
  • О пунктах, касающихся обоих вариантов — мастер-реплик и мастер-мастер, см. Недостаток(и): репликация.

Репликация мастер-мастер

Оба мастера обслуживают чтения и записи и координируются между собой при записях. Если выходит из строя любой из мастеров, система может продолжать работу и с чтением, и с записью.


Источник: Масштабируемость, доступность, стабильность, паттерны

Недостаток(и): репликация мастер-мастер
  • Вам понадобится балансировщик нагрузки или вам придётся изменить логику приложения, чтобы определить, куда писать.
  • Большинство систем мастер-мастер либо имеют слабую согласованность (нарушают ACID), либо имеют повышенную задержку записи из-за синхронизации.
  • Разрешение конфликтов играет всё большую роль по мере добавления узлов записи и роста задержек.
  • О пунктах, касающихся обоих вариантов — мастер-реплик и мастер-мастер, см. Недостаток(и): репликация.
Недостаток(и): репликация
  • Возможна потеря данных, если мастер выйдет из строя до того, как вновь записанные данные будут реплицированы на другие узлы.
  • Записи воспроизводятся на репликах чтения. Если записей много, реплики чтения могут занять переработкой записей и не смогут выполнять столько же чтений.
  • Чем больше реплик чтения, тем больше приходится реплицировать, что приводит к большему отставанию репликации.
  • В некоторых системах запись на мастер может порождать несколько потоков для параллельной записи, тогда как реплики чтения поддерживают только последовательную запись в одном потоке.
  • Репликация добавляет больше оборудования и дополнительную сложность.
Источник(и) и дополнительное чтение: репликация

Федерация


Источник: Масштабирование до первых 10 миллионов пользователей

Федерация (или функциональная партиционировка) разделяет базы данных по функциям. Например, вместо единой монолитной базы данных у вас могло бы быть три базы данных: форумы, пользователи и продукты, что приведёт к меньшему трафику чтения и записи в каждую базу данных и, следовательно, к меньшему отставанию репликации. Меньшие базы данных позволяют вместить в память больше данных, что, в свою очередь, приводит к большему количеству попаданий в кэш благодаря улучшению локальности кэша. Без единого центрального мастера, сериализующего записи, вы можете писать параллельно, увеличивая пропускную способность.

Недостаток(и): федерация
  • Федерация неэффективна, если ваша схема требует огромных функций или таблиц.
  • Вам нужно обновить логику приложения, чтобы определить, из какой базы данных читать и в какую писать.
  • Объединение данных из двух баз данных сложнее с помощью соединения серверов.
  • Федерация добавляет больше оборудования и дополнительную сложность.
Источник(и) и дополнительное чтение: федерация

Шардирование


Источник: Масштабируемость, доступность, стабильность, паттерны

Шардирование распределяет данные по разным базам данных так, что каждая база может управлять только подмножеством данных. Возьмём, к примеру, базу данных пользователей: по мере того как число пользователей растёт, в кластер добавляются новые шарды.

Подобно преимуществам федерации, шардирование приводит к уменьшению трафика чтения и записи, снижению объёма репликации и росту числа попаданий в кэш. Также уменьшается размер индексов, что, как правило, улучшает производительность за счёт более быстрых запросов. Если выходит из строя один шард, остальные продолжают работать, хотя вам стоит добавить какую-нибудь форму репликации, чтобы избежать потери данных. Как и в федерации, здесь нет единого центрального мастера, сериализующего записи, что позволяет выполнять записи параллельно и повышать пропускную способность.

Частые способы шардирования таблицы пользователей — по первой букве фамилии пользователя или по его географическому положению.

Недостаток(и): шардирование
  • Вам нужно обновить логику приложения, чтобы она работала со шардами, что может привести к сложным SQL-запросам.
  • Распределение данных внутри шарда может стать несбалансированным. Например, группа активных пользователей на одном шарде может привести к большей нагрузке на этот шард по сравнению с другими.
    • Перераспределение нагрузки добавляет дополнительную сложность. Функция шардирования на основе консистентного хэширования может уменьшить количество перемещаемых данных.
  • Объединение данных из нескольких шардов сложнее.
  • Шардирование добавляет больше оборудования и дополнительную сложность.
Источник(и) и дополнительное чтение: шардирование

Денормализация

Денормализация призвана улучшить производительность чтений ценой некоторого ухудшения производительности записей. Избыточные копии данных записываются в несколько таблиц, чтобы избежать дорогостоящих объединений. Некоторые RDBMS, такие как PostgreSQL и Oracle, поддерживают виртуальные представления, которые берут на себя работу по хранению избыточной информации и поддержанию согласованности её копий.

Когда данные распределяются с помощью таких техник, как федерация и шардирование, управление объединениями между центрами данных ещё более усложняет систему. Денормализация может позволить обойти необходимость в столь сложных объединениях.

В большинстве систем число чтений может превалировать над числом записей в 100:1 или даже в 1000:1. Чтение, приводящее к сложному объединению в базе данных, может быть очень дорогим, отнимая значительное время на операции с диском.

Недостаток(и): денормализация
  • Данные дублируются.
  • Ограничения (constraints) помогают поддерживать согласованность дублированных копий информации, что повышает сложность проектирования базы данных.
  • Денормализованная база данных под высокой нагрузкой записями может работать хуже, чем её нормализованный аналог.
Источник(и) и дополнительное чтение: денормализация

Настройка SQL

Настройка SQL — обширная тема, и было написано много книг в качестве справочников.

Важно делать бенчмаркинг и профилирование, чтобы смоделировать и выявить узкие места.

  • Бенчмаркинг — моделирование ситуаций с высокой нагрузкой с помощью инструментов, таких как ab.
  • Профилирование — включение инструментов, таких как журнал медленных запросов, чтобы помочь отслеживать проблемы с производительностью.

Бенчмаркинг и профилирование могут указать на следующие оптимизации.

Приведите схему в порядок
  • MySQL пишет на диск непрерывными блоками для быстрого доступа.
  • Используйте CHAR вместо VARCHAR для полей фиксированной длины.
    • CHAR фактически обеспечивает быстрый случайный доступ, тогда как при использовании VARCHAR необходимо находить конец строки перед переходом к следующей.
  • Используйте TEXT для крупных блоков текста, таких как записи блога. TEXT также позволяет выполнять булевы поиски. Использование поля TEXT приводит к тому, что на диске хранится указатель, используемый для нахождения блока текста.
  • Используйте INT для больших чисел вплоть до 2^32 или 4 миллиардов.
  • Используйте DECIMAL для валют, чтобы избежать ошибок представления чисел с плавающей точкой.
  • Избегайте хранения больших BLOBS, вместо этого храните адрес, откуда объект можно получить.
  • VARCHAR(255) — максимальное количество символов, которое можно подсчитать 8-битным числом, что часто максимально использует байт в некоторых RDBMS.
  • Устанавливайте ограничение NOT NULL там, где это уместно, чтобы улучшить производительность поиска.
Используйте хорошие индексы
  • Столбцы, по которым вы выполняете запросы (SELECT, GROUP BY, ORDER BY, JOIN), могут обрабатываться быстрее с использованием индексов.
  • Индексы обычно представлены самоупорядочивающимся B-деревом, которое поддерживает данные в отсортированном виде и позволяет выполнять поиск, последовательный доступ, вставку и удаление за логарифмическое время.
  • Размещение индекса может удерживать данные в памяти, требуя больше места.
  • Записи тоже могут замедлиться, поскольку индекс также должен обновляться.
  • При загрузке большого количества данных может быть быстрее отключить индексы, загрузить данные, а затем перестроить индексы.
Избегайте дорогостоящих объединений
Разбивайте таблицы на разделы
  • Разбивайте таблицу, перемещая горячие точки в отдельную таблицу, чтобы помогать ей оставаться в памяти.
Настраивайте кэш запросов
Источник(и) и дополнительное чтение: настройка SQL

NoSQL

NoSQL представляет собой собрание элементов данных, представленных в хранилище «ключ-значение», документном хранилище, хранилище широких столбцов или графовой базе данных. Данные денормализованы, а объединения обычно выполняются в коде приложения. Большинство NoSQL-хранилищ лишены истинных ACID-транзакций и делают ставку на конечную согласованность.

BASE часто используется для описания свойств NoSQL-баз данных. В сравнении с теоремой CAP BASE ставит доступность выше согласованности.

  • Фундаментальная доступность — система гарантирует доступность.
  • Мягкое состояние — состояние системы может меняться со временем, даже без внешнего воздействия.
  • Конечная согласованность — система станет согласованной за определённый период времени при условии, что в течение этого периода система не получает внешних воздействий.

Помимо выбора между SQL или NoSQL, полезно понимать, какой тип NoSQL-базы данных лучше всего подходит для вашего случая(случаев) использования. В следующем разделе мы рассмотрим хранилища «ключ-значение», документные хранилища, хранилища широких столбцов и графовые базы данных.

Хранилище «ключ-значение»

Абстракция: хеш-таблица

Хранилище «ключ-значение» обычно обеспечивает чтение и запись за O(1) и зачастую работает на основе памяти или SSD. Хранилища данных могут хранить ключи в лексикографическом порядке, что позволяет эффективно извлекать диапазоны ключей. Хранилища «ключ-значение» могут позволять сохранять метаданные вместе со значением.

Хранилища «ключ-значение» обеспечивают высокую производительность и часто используются для простых моделей данных или для быстро меняющихся данных, например для слоя кэша в оперативной памяти. Поскольку они предлагают лишь ограниченный набор операций, сложность перекладывается на прикладной слой, если нужны дополнительные операции.

Хранилище «ключ-значение» служит основой для более сложных систем, таких как документное хранилище, а в некоторых случаях — и графовая база данных.

Источник(и) и дополнительное чтение: хранилище «ключ-значение»

Документное хранилище

Абстракция: хранилище «ключ-значение», в котором в качестве значений хранятся документы

Документное хранилище построено вокруг документов (XML, JSON, бинарных и т. д.), где документ хранит всю информацию о данном объекте. Документные хранилища предоставляют API или язык запросов для выполнения запросов на основе внутренней структуры самого документа. Примечание: многие хранилища «ключ-значение» включают функции для работы с метаданными значения, что размывает границу между этими двумя типами хранилищ.

В зависимости от реализации документы организовываются по коллекциям, тегам, метаданным или директориям. Хотя документы могут быть организованы или сгруппированы вместе, у документов могут быть совершенно разные поля.

Некоторые документные хранилища, такие как MongoDB и CouchDB, также предоставляют похожий на SQL язык для выполнения сложных запросов. DynamoDB поддерживает как пары ключ-значение, так и документы.

Документные хранилища обеспечивают высокую гибкость и часто используются для работы с периодически меняющимися данными.

Источник(и) и дополнительное чтение: документное хранилище

Хранилище широких столбцов


Источник: SQL & NoSQL, краткая история

Абстракция: вложенная карта ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>

Базовой единицей данных в хранилище широких столбцов является столбец (пара имя/значение). Столбцы могут группироваться в семейства столбцов (аналогично SQL-таблице). Сверхсемейства столбцов группируют семейства столбцов. Каждый столбец можно получить независимо по ключу строки, а столбцы с одинаковым ключом строки образуют строку. Каждое значение содержит временную метку для версионирования и разрешения конфликтов.

Google представил Bigtable как первое хранилище широких столбцов, повлиявшее на HBase с открытым исходным кодом, часто используемый в экосистеме Hadoop, и на Cassandra от Facebook. Хранилища вроде BigTable, HBase и Cassandra хранят ключи в лексикографическом порядке, что позволяет эффективно извлекать выбранные диапазоны ключей.

Хранилища широких столбцов обеспечивают высокую доступность и высокую масштабируемость. Они часто используются для очень больших наборов данных.

Источник(и) и дополнительное чтение: хранилище широких столбцов

Графовая база данных


Источник: Графовая база данных

Абстракция: граф

В графовой базе данных каждый узел является записью, а каждая дуга — отношением между двумя узлами. Графовые базы данных оптимизированы для представления сложных отношений со множеством внешних ключей или отношениями «многие ко многим».

Графовые базы данных обеспечивают высокую производительность для моделей данных со сложными отношениями, например социальных сетей. Они относительно новые и пока не получили широкого распространения; инструменты разработки и ресурсы может быть сложнее найти. Многими графами можно пользоваться только через REST API.

Источник(и) и дополнительное чтение: граф

Источник(и) и дополнительное чтение: NoSQL

SQL или NoSQL


Источник: Переход с RDBMS на NoSQL

Причины выбрать SQL:

  • Структурированные данные
  • Строгая схема
  • Реляционные данные
  • Необходимость сложных объединений
  • Транзакции
  • Чёткие паттерны масштабирования
  • Более устоявшаяся область: разработчики, сообщество, код, инструменты и т. д.
  • Очень быстрый поиск по индексу

Причины выбрать NoSQL:

  • Полуструктурированные данные
  • Динамическая или гибкая схема
  • Нереляционные данные
  • Отсутствие необходимости в сложных объединениях
  • Хранение многих ТБ (или ПБ) данных
  • Очень интенсивная рабочая нагрузка с большими объёмами данных
  • Очень высокая пропускная способность для IOPS

Примеры данных, хорошо подходящих для NoSQL:

  • Быстрый приём данных clickstream и журналов событий
  • Данные leaderboards или систем оценивания
  • Временные данные, например корзина покупок
  • Часто используемые («горячие») таблицы
  • Таблицы метаданных/справочники
Источник(и) и дополнительное чтение: SQL или NoSQL

Кэш


Источник: Паттерны проектирования масштабируемых систем

Кеширование ускоряет загрузку страниц и позволяет снизить нагрузку на ваши серверы и базы данных. В этой модели диспетчер сначала проверяет, поступало ли такое же запрос ранее, и пытается вернуть сохранённый результат, чтобы избежать фактического выполнения запроса.

База данных часто выигрывает от равномерного распределения чтений и записей по своим партициям. Популярные записи могут нарушать равномерность, создавая узкие места. Размещение кэша перед базой данных помогает сгладить неравномерную нагрузку и всплески трафика.

Кэширование на стороне клиента

Кэш может находиться на стороне клиента (ОС или браузер), на стороне сервера или в отдельном слое кэша.

Кэширование в CDN

CDN считаются одним из видов кэша.

Кэширование на веб-сервере

Обратные прокси и кэши вроде Varnish могут напрямую отдавать статический и динамический контент. Веб-серверы тоже умеют кешировать запросы и возвращать ответы без обращения к серверам приложения.

Кэширование в базе данных

В стандартной конфигурации ваша база данных обычно уже включает какой-то уровень кеширования, оптимизированный под типовые сценарии использования. Подстройка этих настроек под конкретный паттерн нагрузки может дополнительно повысить производительность.

Кэширование в приложении

Кэши в оперативной памяти, такие как Memcached и Redis, — это хранилища «ключ-значение» между вашим приложением и системой хранения данных. Поскольку данные размещены в RAM, работа с ними гораздо быстрее, чем с типичными базами данных, где данные лежат на диске. Памяти меньше, чем места на диске, поэтому алгоритмы невалидации кэша, такие как least recently used (LRU), помогают очищать «холодные» записи и держать «горячие» данные в RAM.

У Redis есть дополнительные возможности:

  • Опция персистентности
  • Встроенные структуры данных, например упорядоченные множества и списки

Существует несколько уровней кеширования, которые делятся на две общие категории: запросы к базе данных и объекты:

  • Уровень строк
  • Уровень запросов
  • Полностью собранные сериализуемые объекты
  • Полностью отрендеренный HTML

Как правило, стоит избегать файлового кеширования, поскольку оно усложняет клонирование и автомасштабирование.

Кэширование на уровне запросов к базе данных

Каждый раз, когда вы обращаетесь к базе данных, возьмите хеш запроса в качестве ключа и положите результат в кэш. У такого подхода есть проблемы с истечением срока действия:

  • Сложно удалить закэшированный результат сложного запроса
  • Если изменился один фрагмент данных, например ячейка таблицы, нужно удалить все закэшированные запросы, которые могли включать изменённую ячейку

Кэширование на уровне объектов

Относитесь к данным как к объектам, как вы делаете в коде приложения. Пусть ваше приложение собирает набор данных из базы данных в экземпляр класса или структуру(ы) данных:

  • Удаляйте объект из кэша, если изменились его исходные данные
  • Позволяет асинхронную обработку: воркеры собирают объекты, потребляя самый свежий закэшированный объект

Что можно кешировать:

  • Сеансы пользователей
  • Полностью отрендеренные веб-страницы
  • Потоки активности
  • Графовые данные пользователей

Когда обновлять кэш

Поскольку в кэше можно хранить лишь ограниченное количество данных, нужно выбрать стратегию обновления кэша, лучшую для вашего сценария использования.

Кэширование обходом (Cache-aside)


Источник: От кэша к in-memory data grid

Приложение отвечает за чтение и запись в хранилище. Кэш не взаимодействует с хранилищем напрямую. Приложение выполняет следующие действия:

  • Ищет запись в кэше; если её нет — cache miss
  • Загружает запись из базы данных
  • Добавляет запись в кэш
  • Возвращает запись
def get_user(self, user_id):
    user = cache.get("user.{0}", user_id)
    if user is None:
        user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)
        if user is not None:
            key = "user.{0}".format(user_id)
            cache.set(key, json.dumps(user))
    return user

Обычно именно так используют Memcached.

Последующие чтения данных, добавленных в кэш, быстры. Cache-aside также называют ленивой загрузкой (lazy loading). Кешируются только запрошенные данные, что не даёт заполнять кэш ненужным содержимым.

Недостаток(и): cache-aside
  • Каждый cache miss означает три хождения, что может заметно увеличивать задержку.
  • Данные могут устареть, если их обновляют в базе данных. С этим справляются, задавая время жизни (TTL), которое принудительно обновляет запись кэша, или используя write-through.
  • При отказе узла он заменяется новым, пустым, что увеличивает латентность.

Запись сквозь кэш (Write-through)


Источник: Масштабируемость, доступность, стабильность, паттерны

Приложение использует кэш как основное хранилище данных: читает и пишет в него, а кэш отвечает за чтение и запись в базу данных:

  • Приложение добавляет/обновляет запись в кэше
  • Кэш синхронно записывает запись в хранилище данных
  • Возврат управления

Код приложения:

set_user(12345, {"foo":"bar"})

Код кэша:

def set_user(user_id, values):
    user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
    cache.set(user_id, user)

Write-through — медленная операция в целом из-за записи, но последующие чтения только что записанных данных быстры. Как правило, пользователи лучше переносят задержки при обновлении данных, чем при их чтении. Данные в кэше не устаревают.

Недостаток(и): write through
  • Когда из-за отказа или масштабирования создаётся новый узел, он не будет кешировать записи, пока они не будут обновлены в базе данных. Это можно смягчить сочетанием cache-aside и write through.
  • Большинство записанных данных, возможно, никогда не будут прочитаны; это можно уменьшить с помощью TTL.

Отложенная запись (Write-behind / write-back)


Источник: Масштабируемость, доступность, стабильность, паттерны

При write-behind приложение выполняет следующее:

  • Добавляет/обновляет запись в кэше
  • Асинхронно записывает запись в хранилище данных, повышая производительность записи
Недостаток(и): write-behind
  • Если кэш упадёт до того, как его содержимое попадёт в хранилище, возможна потеря данных.
  • Реализовать write-behind сложнее, чем cache-aside или write-through.

Предварительное обновление (Refresh-ahead)


Источник: От кэша к in-memory data grid

Можно настроить кэш так, чтобы он автоматически обновлял недавно используемую запись ещё до истечения её срока действия.

Refresh-ahead может дать меньшую задержку, чем read-through, если кэш точно предсказывает, какие записи, вероятно, понадобятся в будущем.

Недостаток(и): refresh-ahead
  • Неточное предсказание того, какие записи, вероятно, понадобятся в будущем, может привести к снижению производительности по сравнению с отсутствием refresh-ahead.

Недостаток(и): кэш

  • Нужно поддерживать согласованность между кэшами и источником истины, таким как база данных, через невалидацию кэша.
  • Невалидация кэша — сложная задача: появляется дополнительная сложность с тем, когда обновлять кэш.
  • Нужны изменения в приложении, например добавление Redis или memcached.

Источник(и) и дополнительное чтение

Асинхронность


Источник: Введение в проектирование систем под масштаб

Асинхронные потоки работы помогают сократить время запросов дорогих операций, которые иначе выполнялись бы в основной линии. Они также помогают делать трудоёмкую работу заранее, например периодически агрегируя данные.

Очереди сообщений

Очереди сообщений принимают, хранят и доставляют сообщения. Если операция слишком медленна, чтобы выполнять её в основной линии, можно использовать очередь сообщений со следующим потоком работы:

  • Приложение публикует задание в очередь, затем уведомляет пользователя о статусе задания
  • Воркер забирает задание из очереди, обрабатывает его, затем сигнализирует об окончании задания

Пользователь не блокируется, а задание обрабатывается в фоне. За это время клиент может, по желанию, выполнить немного обработки, чтобы создать видимость завершённости задачи. Например, если публикуется твит, он может мгновенно появиться в вашей ленте, но на доставку всем подписчикам может уйти некоторое время.

Redis полезен как простой брокер сообщений, но сообщения могут теряться.

RabbitMQ популярен, но требует от вас поддержки протокола 'AMQP' и управления собственными узлами.

Amazon SQS управляемый, но может иметь высокую латентность, и возможна двукратная доставка сообщений.

Очереди задач

Очереди задач принимают задания и связанные с ними данные, выполняют их, затем доставляют результаты. Они могут поддерживать планирование и использоваться для запуска вычислительно тяжёлых заданий в фоне.

Celery поддерживает планирование и в первую очередь ориентирован на Python.

Обратное давление

Если очереди начинают сильно расти, размер очереди может превысить объём памяти, что приведёт к промахам в кэш, чтениям с диска и ещё большей деградации производительности. Обратное давление помогает ограничивая размер очереди, тем самым поддерживая высокий уровень пропускной способности и хорошее время отклика для заданий, уже находящихся в очереди. Когда очередь заполняется, клиенты получают статус «сервер занят» или HTTP 503, чтобы повторить попытку позже. Клиенты могут повторить запрос позднее, возможно, с экспоненциальной задержкой повторов.

Недостаток(и): асинхронность

  • Для сценариев вроде дешёвых вычислений и потоков реального времени лучше подходят синхронные операции, ведь введение очередей добавляет задержки и сложность.

Источник(и) и дополнительное чтение

Коммуникация


Источник: Семислойная модель OSI

Протокол передачи гипертекста (HTTP)

HTTP — метод кодирования и передачи данных между клиентом и сервером. Это протокол «запрос/ответ»: клиенты посылают запросы, а серверы отвечают соответствующим содержимым и информацией о статусе завершения запроса. HTTP самодостаточен: запросы и ответы могут проходить через множество промежуточных маршрутизаторов и серверов, выполняющих балансировку нагрузки, кеширование, шифрование и сжатие.

Базовый HTTP-запрос состоит из глагола (метода) и ресурса (эндпоинта). Ниже приведены распространённые HTTP-глаголы:

Глагол Описание Идемпотентность* Безопасность Кешируемый
GET Читает ресурс Да Да Да
POST Создаёт ресурс или запускает процесс, обрабатывающий данные Нет Нет Да, если ответ содержит информацию о свежести
PUT Создаёт или заменяет ресурс Да Нет Нет
PATCH Частично обновляет ресурс Нет Нет Да, если ответ содержит информацию о свежести
DELETE Удаляет ресурс Да Нет Нет

*Можно вызывать многократно без разного результата.

HTTP — протокол уровня приложения, опирающийся на протоколы нижних уровней, такие как TCP и UDP.

Источник(и) и дополнительное чтение: HTTP

Протокол управления передачей (TCP)


Источник: Как сделать мультиплеерную игру

TCP — протокол с установлением соединения поверх IP-сети. Соединение устанавливается и разрывается посредством handshake. Все отправленные пакеты гарантированно доходят до получателя в исходном порядке и без искажений благодаря:

Если отправитель не получает корректный ответ, он повторно отправляет пакеты. Если таймаутов было несколько, соединение разрывается. TCP также реализует управление потоком и контроль перегрузки. Эти гарантии вызывают задержки и, как правило, приводят к менее эффективной передаче, чем в UDP.

Для обеспечения высокой пропускной способности веб-серверы могут держать открытыми множество TCP-соединений, что приводит к высокому потреблению памяти. Большое количество открытых соединений между потоками веб-сервера и, скажем, сервером memcached, может быть дорого по ресурсам. Пул соединений может помочь, в дополнение к переходу на UDP там, где это применимо.

TCP полезен для приложений, требующих высокой надёжности, но не критичных ко времени. Примеры: веб-серверы, информация баз данных, SMTP, FTP и SSH.

Используйте TCP вместо UDP, когда:

  • Вам необходимо, чтобы все данные прибыли невредимыми
  • Вы хотите автоматически наилучшим образом оценивать использование пропускной способности сети

Протокол пользовательских датаграмм (UDP)


Источник: Как сделать мультиплеерную игру

UDP не предполагает установки соединения. Гарантии на датаграммы (аналог пакетов) даются только на уровне датаграммы. Датаграммы могут дойти до назначения в неверном порядке или вообще не дойти. UDP не поддерживает контроль перегрузки. Без гарантий, которые обеспечивает TCP, UDP, как правило, эффективнее.

UDP умеет рассылать широковещательно, отправляя датаграммы всем устройствам в подсети. Это полезно для DHCP, поскольку клиент ещё не получил IP-адрес, а без адреса TCP не может организовать потоковую передачу.

UDP менее надёжен, но хорошо подходит для сценариев реального времени: VoIP, видеочаты, стриминг и мультиплеерные игры в реальном времени.

Используйте UDP вместо TCP, когда:

  • Вам нужна минимальная задержка
  • Опоздавшие данные хуже, чем потерянные
  • Вы хотите реализовать собственные средства исправления ошибок

Источник(и) и дополнительное чтение: TCP и UDP

Вызов удалённых процедур (RPC)


Источник: Crack the system design interview

При RPC клиент вызывает выполнение процедуры в другом адресном пространстве, обычно на удалённом сервере. Процедура пишется так, будто это локальный вызов: детали взаимодействия с сервером скрыты от клиентской программы. Удалённые вызовы, как правило, медленнее и менее надёжны, чем локальные, поэтому полезно различать RPC-вызовы и локальные. Среди популярных RPC-фреймворков — Protobuf, Thrift и Avro.

RPC — протокол «запрос-ответ»:

  • Программа клиента — вызывает процедуру client stub. Параметры кладутся в стек, как при локальном вызове процедуры.
  • Процедура client stub — маршалирует (упаковывает) идентификатор процедуры и аргументы в сообщение запроса.
  • Коммуникационный модуль клиентаОС отправляет сообщение от клиента серверу.
  • Коммуникационный модуль сервераОС передаёт входящие пакеты процедуре server stub.
  • Процедура server stub — распаковывает результаты, вызывает процедуру сервера, соответствующую идентификатору процедуры, и передаёт указанные аргументы.
  • Ответ сервера повторяет перечисленные шаги в обратном порядке.

Примеры RPC-вызовов:

GET /someoperation?data=anId

POST /anotheroperation
{
  "data":"anId";
  "anotherdata": "another value"
}

RPC сфокусирован на раскрытии поведения. Для внутренней коммуникации RPC часто выбирают ради производительности, потому что можно вручную создавать нативные вызовы, лучше подходящие под ваши сценарии.

Выбирайте нативную библиотеку (то есть SDK), когда:

  • Вы знаете целевую платформу.
  • Вы хотите контролировать, как осуществляется доступ к вашей «логике».
  • Вы хотите контролировать, как обработка ошибок осуществляется вне вашей библиотеки.
  • Производительность и впечатления конечного пользователя — главная забота.

HTTP API, следующие за REST, чаще используются для публичных API.

Недостаток(и): RPC

  • RPC-клиенты жёстко связываются с реализацией сервиса.
  • Для каждой новой операции или сценария нужно определять новый API.
  • Отладка RPC может быть сложной.
  • Возможно, нельзя сразу воспользоваться существующими технологиями. Например, чтобы убедиться, что RPC-вызовы правильно кешируются на кэширующих серверах вроде Squid, может потребоваться дополнительные усилия.

Перенос репрезентационного состояния (REST)

REST — архитектурный стиль, навязывающий клиент-серверную модель, в которой клиент оперирует набором ресурсов, управляемых сервером. Сервер предоставляет представление ресурсов и действий, которые либо изменяют ресурсы, либо получают новое представление ресурсов. Вся коммуникация должна быть без состояния и кешируемой.

У RESTful-интерфейса четыре качества:

  • Идентификация ресурсов (URI в HTTP) — используйте один и тот же URI независимо от операции.
  • Изменение через представления (глаголы в HTTP) — используйте глаголы, заголовки и тело.
  • Самоописательное сообщение об ошибке (статусный ответ в HTTP) — используйте коды статуса, не изобретайте велосипед.
  • HATEOAS (HTML-интерфейс для HTTP) — ваш веб-сервис должен быть полностью доступен в браузере.

Примеры REST-вызовов:

GET /someresources/anId

PUT /someresources/anId
{"anotherdata": "another value"}

REST сфокусирован на раскрытии данных. Он минимизирует связанность клиент/сервер и часто используется для публичных HTTP API. REST использует более общий и единообразный способ раскрытия ресурсов через URI, представления через заголовки и действий через глаголы, такие как GET, POST, PUT, DELETE и PATCH. Будучи без состояния, REST отлично подходит для горизонтального масштабирования и шардирования.

Недостаток(и): REST

  • Поскольку REST сфокусирован на раскрытии данных, он может плохо подойти, если ресурсы не организованы и не доступны естественной простой иерархией. Например, «вернуть все обновлённые за последний час записи, отвечающие определённому набору событий», трудно выразить в виде пути. В REST это, скорее всего, будет реализовано комбинацией пути URI, параметров запроса и, возможно, тела запроса.
  • REST, как правило, опирается на несколько глаголов (GET, POST, PUT, DELETE и PATCH), что иногда не подходит вашему сценарию. Например, «переместить просроченные документы в архивную папку» может плохо укладываться в эти глаголы.
  • Получение сложных ресурсов с вложенной иерархией требует нескольких хождений между клиентом и сервером, чтобы отрендерить единственное представление, например, получения содержимого записи блога и комментариев к ней. Для мобильных приложений, работающих в переменных сетевых условиях, такие многократные хождения крайне нежелательны.
  • Со временем в ответ API могут добавляться поля, и старые клиенты будут получать все новые поля данных, даже те, которые им не нужны; в результате растёт размер полезной нагрузки и увеличивается латентность.

Сравнение RPC- и REST-вызовов

Операция RPC REST
Регистрация POST /signup POST /persons
Аннулирование регистрации POST /resign
{
"personid": "1234"
}
DELETE /persons/1234
Чтение человека GET /readPerson?personid=1234 GET /persons/1234
Чтение списка предметов человека GET /readUsersItemsList?personid=1234 GET /persons/1234/items
Добавление предмета в список предметов человека POST /addItemToUsersItemsList
{
"personid": "1234";
"itemid": "456"
}
POST /persons/1234/items
{
"itemid": "456"
}
Обновление предмета POST /modifyItem
{
"itemid": "456";
"key": "value"
}
PUT /items/456
{
"key": "value"
}
Удаление предмета POST /removeItem
{
"itemid": "456"
}
DELETE /items/456

Источник: действительно ли вы знаете, почему предпочитаете REST, а не RPC

Источник(и) и дополнительное чтение: REST и RPC

Безопасность

Этот раздел нуждается в обновлении. Рассмотрите возможность внесения вклада!

Безопасность — обширная тема. Если у вас нет значительного опыта, бэкграунда в области безопасности или вы не претендуете на позицию, требующую знаний в этой сфере, вам, вероятно, достаточно знать лишь основы:

  • Шифруйте данные при передаче и при хранении.
  • Дезинфицируйте все пользовательские входные данные и любые параметры ввода, доступные пользователю, чтобы предотвратить XSS и SQL-инъекции.
  • Используйте параметризованные запросы для защиты от SQL-инъекций.
  • Следуйте принципу минимальных привилегий.

Источник(и) и дополнительное чтение

Приложение

Иногда от вас просят сделать «приблизительную оценку» (back-of-the-envelope estimate). Например, может потребоваться определить, сколько времени займёт создание 100 миниатюр изображений с диска или сколько памяти потребуется структуре данных. Таблица степеней двойки и цифры задержек, которые должен знать каждый программист — удобные справочные материалы.

Таблица степеней двойки

Power           Exact Value         Approx Value        Bytes
---------------------------------------------------------------
7                             128
8                             256
10                           1024   1 thousand           1 KB
16                         65,536                       64 KB
20                      1,048,576   1 million            1 MB
30                  1,073,741,824   1 billion            1 GB
32                  4,294,967,296                        4 GB
40              1,099,511,627,776   1 trillion           1 TB

Источник(и) и дополнительное чтение

Цифры задержек, которые должен знать каждый программист

Latency Comparison Numbers
--------------------------
L1 cache reference                           0.5 ns
Branch mispredict                            5   ns
L2 cache reference                           7   ns                      14x L1 cache
Mutex lock/unlock                           25   ns
Main memory reference                      100   ns                      20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy            10,000   ns       10 us
Send 1 KB bytes over 1 Gbps network     10,000   ns       10 us
Read 4 KB randomly from SSD*           150,000   ns      150 us          ~1GB/sec SSD
Read 1 MB sequentially from memory     250,000   ns      250 us
Round trip within same datacenter      500,000   ns      500 us
Read 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memory
HDD seek                            10,000,000   ns   10,000 us   10 ms  20x datacenter roundtrip
Read 1 MB sequentially from 1 Gbps  10,000,000   ns   10,000 us   10 ms  40x memory, 10X SSD
Read 1 MB sequentially from HDD     30,000,000   ns   30,000 us   30 ms 120x memory, 30X SSD
Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms

Notes
-----
1 ns = 10^-9 seconds
1 us = 10^-6 seconds = 1,000 ns
1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns

Полезные метрики, основанные на приведённых выше числах:

  • Последовательное чтение с HDD со скоростью 30 МБ/с
  • Последовательное чтение по Ethernet 1 Гбит/с со скоростью 100 МБ/с
  • Последовательное чтение с SSD со скоростью 1 ГБ/с
  • Последовательное чтение из основной памяти со скоростью 4 ГБ/с
  • 6-7 круговых поездок через всю Землю в секунду
  • 2 000 круговых поездок в секунду внутри одного центра обработки данных

Цифры задержек в визуализации

Источник(и) и дополнительное чтение

Дополнительные вопросы по проектированию систем для собеседований

Распространённые вопросы по проектированию систем на собеседованиях со ссылками на материалы о том, как решать каждый из них.

Вопрос Ссылка(и)
Спроектируйте сервис синхронизации файлов, как Dropbox youtube.com
Спроектируйте поисковую систему, как Google queue.acm.org
stackexchange.com
ardendertat.com
stanford.edu
Спроектируйте масштабируемый веб-краулер, как у Google quora.com
Спроектируйте Google docs code.google.com
neil.fraser.name
Спроектируйте хранилище «ключ-значение», как Redis codecapsule.com
allthingsdistributed.com
Спроектируйте кэш-систему, как Memcached slideshare.net
Спроектируйте систему рекомендаций, как у Amazon hulu.com
ijcai13.org
Спроектируйте аналог tinyurl, как Bitly n00tc0d3r.blogspot.com
Спроектируйте чат-приложение, как WhatsApp highscalability.com
Спроектируйте систему обмена фотографиями, как Instagram highscalability.com
highscalability.com
Спроектируйте функцию ленты новостей Facebook quora.com
quora.com
slideshare.net
Спроектируйте функцию ленты активности (timeline) Facebook facebook.com
highscalability.com
Спроектируйте функцию чата Facebook erlang-factory.com
facebook.com
Спроектируйте функцию поиска по графу, как у Facebook facebook.com
facebook.com
facebook.com
Спроектируйте сеть доставки контента (CDN), как CloudFlare figshare.com
Спроектируйте систему трендов, как у Twitter michael-noll.com
snikolov .wordpress.com
Спроектируйте систему генерации случайных идентификаторов blog.twitter.com
github.com
Верните top-k запросов за промежуток времени cs.ucsb.edu
wpi.edu
Спроектируйте систему, которая обслуживает данные из нескольких центров обработки данных highscalability.com
Спроектируйте онлайн-карточную игру с несколькими игроками indieflashblog.com
buildnewgames.com
Спроектируйте систему сборки мусора stuffwithstuff.com
washington.edu
Спроектируйте лимитер частоты запросов API https://stripe.com/blog/
Спроектируйте фондовую биржу (как NASDAQ или Binance) Jane Street
Golang Implementation
Go Implementation
Добавьте вопрос по проектированию систем Contribute

Архитектуры реальных систем

Статьи о том, как спроектированы системы реального мира.


Источник: ленты Twitter в условиях масштабирования

Не зацикливайтесь на тонких деталях в следующих статьях, вместо этого:

  • Ищите общие принципы, типовые технологии и паттерны в этих статьях
  • Изучайте, какие задачи решает каждый компонент, где он работает хорошо, а где нет
  • Пересматривайте усвоенные уроки
Тип Система Ссылка(и)
Обработка данных MapReduce - распределённая обработка данных от Google research.google.com
Обработка данных Spark - распределённая обработка данных от Databricks slideshare.net
Обработка данных Storm - распределённая обработка данных от Twitter slideshare.net
Хранилище данных Bigtable - распределённая столбцевая база данных от Google harvard.edu
Хранилище данных HBase - open source реализация Bigtable slideshare.net
Хранилище данных Cassandra - распределённая столбцевая база данных от Facebook slideshare.net
Хранилище данных DynamoDB - документная база данных от Amazon harvard.edu
Хранилище данных MongoDB - документная база данных slideshare.net
Хранилище данных Spanner - глобально распределённая база данных от Google research.google.com
Хранилище данных Memcached - распределённая система кэширования в памяти slideshare.net
Хранилище данных Redis - распределённая система кэширования в памяти с персистентностью и типами значений slideshare.net
Файловая система Google File System (GFS) - распределённая файловая система research.google.com
Файловая система Hadoop File System (HDFS) - open source реализация GFS apache.org
Прочее Chubby - служба блокировок для слабосвязанных распределённых систем от Google research.google.com
Прочее Dapper - инфраструктура трассировки распределённых систем research.google.com
Прочее Kafka - pub/sub очередь сообщений от LinkedIn slideshare.net
Прочее Zookeeper - централизованная инфраструктура и службы для обеспечения синхронизации slideshare.net
Добавьте архитектуру Contribute

Корпоративные архитектуры

Компания Ссылка(и)
Amazon Amazon architecture
Cinchcast Producing 1,500 hours of audio every day
DataSift Realtime datamining At 120,000 tweets per second
Dropbox Как мы масштабируем Dropbox
ESPN Operating At 100,000 duh nuh nuhs per second
Google Google architecture
Instagram 14 миллионов пользователей, терабайты фотографий
What powers Instagram
Justin.tv Justin.Tv's live video broadcasting architecture
Facebook Масштабирование memcached в Facebook
TAO: распределённое хранилище данных Facebook для социального графа
Хранение фотографий в Facebook
Как Facebook транслирует live-стримы на 800 000 одновременных зрителей
Flickr Flickr architecture
Mailbox From 0 to one million users in 6 weeks
Netflix A 360 Degree View Of The Entire Netflix Stack
Netflix: что происходит при нажатии кнопки Play?
Pinterest От 0 до десятков миллиардов просмотров страниц в месяц
18 миллионов посетителей, рост в 10 раз, 12 сотрудников
Playfish 50 million monthly users and growing
PlentyOfFish PlentyOfFish architecture
Salesforce Как они обрабатывают 1,3 миллиарда транзакций в день
Stack Overflow Stack Overflow architecture
TripAdvisor 40M посетителей, 200M динамических просмотров страниц, 30TB данных
Tumblr 15 billion page views a month
Twitter Как сделать Twitter в 10 000 процентов быстрее
Хранение 250 миллионов твитов в день с помощью MySQL
150M активных пользователей, 300K QPS, поток 22 MB/S
Timelines at scale
Большие и малые данные в Twitter
Операции в Twitter: масштабирование за пределы 100 миллионов пользователей
Как Twitter обрабатывает 3 000 изображений в секунду
Uber Как Uber масштабирует свою реальновременную торговую платформу
Lessons Learned From Scaling Uber To 2000 Engineers, 1000 Services, And 8000 Git Repositories
WhatsApp The WhatsApp architecture Facebook bought for $19 billion
YouTube YouTube scalability
YouTube architecture

Инженерные блоги компаний

Архитектуры компаний, в которые вы идёте на собеседование.

Вопросы, которые вам зададут, могут быть из той же предметной области.

Источник(и) и дополнительное чтение

Хотите добавить блог? Чтобы не дублировать работу других, рассмотрите возможность добавления блога вашей компании в следующий репозиторий:

В разработке

Хотите добавить раздел или помочь завершить один из незавершённых? Contribute!

  • Распределённые вычисления с MapReduce
  • Согласованное хэширование (consistent hashing)
  • Scatter gather (распределение и сбор)
  • Contribute

Благодарности

Признания авторов и источники указаны по всему этому репозиторию.

Отдельная благодарность:

Контактная информация

Свяжитесь со мной, чтобы обсудить любые проблемы, вопросы или комментарии.

Мою контактную информацию можно найти на моей странице GitHub.

Лицензия

Я предоставляю код и ресурсы в этом репозитории под открытой лицензией. Поскольку это мой личный репозиторий, лицензию на мой код и ресурсы вы получаете от меня лично, а не от моего работодателя (Facebook).

Copyright 2017 Donne Martin

Creative Commons Attribution 4.0 International License (CC BY 4.0)

http://creativecommons.org/licenses/by/4.0/