- Python 75.4%
- Shell 18.8%
- CSS 5.3%
- JavaScript 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
release / Build PDF & Release (push) Failing after 2m15s
|
||
| .forgejo/workflows | ||
| images | ||
| resources | ||
| solutions | ||
| .gitattributes | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| epub-metadata.yaml | ||
| generate-cheatsheet.sh | ||
| generate-epub.sh | ||
| generate-pdf.sh | ||
| LICENSE.txt | ||
| md_transform.py | ||
| pdf-cheatsheet.css | ||
| pdf-footer.js | ||
| pdf-style.css | ||
| README.md | ||
Введение в проектирование систем (The System Design Primer)
Мотивация
Узнайте, как проектировать системы большого масштаба.
Подготовьтесь к собеседованию по проектированию систем.
Как научиться проектировать системы большого масштаба
Изучение того, как проектировать масштабируемые системы, поможет вам стать лучше инженером.
Проектирование систем — обширная тема. В сети огромное количество разрозненных ресурсов о принципах проектирования систем.
Этот репозиторий — упорядоченная коллекция ресурсов, которая поможет вам научиться строить системы большого масштаба.
Учитесь у сообщества open source
Это проект с открытым исходным кодом, который постоянно обновляется.
Вклады приветствуются!
Подготовка к собеседованию по проектированию систем
Помимо кодировочных собеседований, проектирование систем — обязательная часть технического интервью во многих технологических компаниях.
Практикуйтесь на типичных вопросах собеседования по проектированию систем и сравнивайте свои решения с образцовыми: обсуждения, код и схемы.
Дополнительные темы для подготовки к собеседованию:
- Памятка для изучения
- Как подходить к вопросу на собеседовании по проектированию систем
- Вопросы собеседования по проектированию систем, с решениями
- Вопросы собеседования по объектно-ориентированному дизайну, с решениями
- Дополнительные вопросы собеседования по проектированию систем
Карточки Anki
Предоставленные наборы карточек Anki используют интервальное повторение, чтобы помочь вам запомнить ключевые концепции проектирования систем.
- Набор «Проектирование систем»
- Набор «Упражнения по проектированию систем»
- Набор «Упражнения по объектно-ориентированному дизайну»
Отлично подходят для использования в дороге.
Ресурс для программирования: Интерактивные задачи по кодированию
Ищете ресурсы, которые помогут подготовиться к собеседованию по кодированию?
Загляните в «родственный» репозиторий Interactive Coding Challenges, где есть дополнительный набор карточек Anki:
Как внести вклад
Учитесь у сообщества.
Свободно отправляйте pull request'ы, чтобы помочь:
- Исправлять ошибки
- Улучшать разделы
- Добавлять новые разделы
- Переводить
Материалы, которым нужна доработка, вынесены в раздел «в разработке».
Ознакомьтесь с правилами внесения вклада.
Список тем по проектированию систем
Краткие описания различных тем проектирования систем, включая плюсы и минусы. Всё — это компромисс.
Каждый раздел содержит ссылки на более глубокие материалы.
- Темы по проектированию систем: начните отсюда
- Производительность против масштабируемости
- Латентность против пропускной способности
- Доступность против согласованности
- Модели согласованности
- Модели обеспечения доступности
- Система доменных имён
- Сеть доставки контента
- Балансировщик нагрузки
- Обратный прокси (веб-сервер)
- Прикладной уровень
- База данных
- Кэш
- Асинхронность
- Коммуникация
- Безопасность
- Приложение
- В разработке
- Благодарности
- Контактная информация
- Лицензия
Памятка для изучения
Рекомендуемые темы для повторения в зависимости от ваших сроков подготовки к собеседованию (короткие, средние, длительные).
В: Для собеседования мне нужно знать всё из этого?
О: Нет, чтобы подготовиться к собеседованию, не нужно знать всё из этого.
То, что вас спросят на собеседовании, зависит от таких факторов, как:
- Сколько у вас опыта
- Каков ваш технический бэкграунд
- На какие позиции вы претендуете
- В каких компаниях вы проходите собеседование
- Удача
От более опытных кандидатов обычно ожидают большего знания проектирования систем. От архитекторов или тимлидов могут ожидать больше, чем от рядовых разработчиков. Ведущие технологические компании, скорее всего, проводят один или несколько раундов собеседования по дизайну.
Начинайте широко и углубляйтесь в нескольких областях. Полезно немного разбираться в различных ключевых темах проектирования систем. Адаптируйте следующую памятку под ваши сроки, опыт, позиции, на которые вы претендуете, и компании, в которых вы проходите собеседование.
- Короткие сроки - Цель — широта в темах по проектированию систем. Практикуйтесь, решая некоторые вопросы собеседования.
- Средние сроки - Цель — широта и некоторая глубина в темах по проектированию систем. Практикуйтесь, решая много вопросов собеседования.
- Длительные сроки - Цель — широта и больше глубины в темах по проектированию систем. Практикуйтесь, решая большинство вопросов собеседования.
| Короткие | Средние | Длительные | |
|---|---|---|---|
| Прочитать темы по проектированию систем, чтобы получить общее представление о том, как работают системы | 👍 | 👍 | 👍 |
| Прочитать несколько статей в инженерных блогах компаний, в которых вы проходите собеседование | 👍 | 👍 | 👍 |
| Прочитать несколько архитектур реальных систем | 👍 | 👍 | 👍 |
| Повторить как подходить к вопросу на собеседовании по проектированию систем | 👍 | 👍 | 👍 |
| Разобрать вопросы собеседования по проектированию систем с решениями | Некоторые | Много | Большинство |
| Разобрать вопросы собеседования по объектно-ориентированному дизайну с решениями | Некоторые | Много | Большинство |
| Повторить дополнительные вопросы собеседования по проектированию систем | Некоторые | Много | Большинство |
Как подходить к вопросам системного дизайна на собеседовании
Как подойти к решению вопроса по системному дизайну на собеседовании.
Собеседование по системному дизайну — это открытая беседа. Ожидается, что именно вы будете её вести.
Вы можете использовать следующие шаги, чтобы направлять обсуждение. Чтобы закрепить этот процесс, проработайте раздел Вопросы по системному дизайну с решениями с помощью этих шагов.
Шаг 1: Определите сценарии использования, ограничения и допущения
Соберите требования и определите рамки задачи. Задавайте вопросы, чтобы уточнить сценарии использования и ограничения. Обсудите допущения.
- Кто будет пользоваться системой?
- Как они будут её использовать?
- Сколько будет пользователей?
- Что делает система?
- Каковы входные данные и результат работы системы?
- Какой объём данных мы ожидаем обработать?
- Сколько запросов в секунду мы ожидаем?
- Каково ожидаемое соотношение числа чтений и записей?
Шаг 2: Создайте высокоуровневый дизайн
Опишите высокоуровневый дизайн со всеми важными компонентами.
- Схематично изобразите основные компоненты и связи между ними
- Обоснуйте свои идеи
Шаг 3: Спроектируйте ключевые компоненты
Разберите каждый ключевой компонент в деталях. Например, если вас попросили спроектировать сервис сокращения URL, обсудите:
- Генерация и хранение хэша полного URL
- Преобразование хэшированного URL в полный URL
- Поиск в базе данных
- API и объектно-ориентированный дизайн
Шаг 4: Масштабируйте дизайн
Учитывая ограничения, выявите и устраните узкие места. Например, понадобятся ли вам следующие средства для решения проблем масштабируемости?
- Балансировщик нагрузки
- Горизонтальное масштабирование
- Кэширование
- Шардирование базы данных
Обсудите возможные решения и компромиссы. Всё — это компромисс. Устраняйте узкие места, опираясь на принципы проектирования масштабируемых систем.
Расчёты «на салфетке»
Вас могут попросить выполнить приблизительную оценку вручную. За следующими материалами обратитесь к Приложению:
- Использование расчётов «на салфетке»
- Таблица степеней двойки
- Числовые значения латентности, которые должен знать каждый программист
Источник(и) и дополнительное чтение
Ознакомьтесь со следующими ссылками, чтобы лучше понять, чего ожидать:
- Как успешно пройти собеседование по системному дизайну
- Собеседование по системному дизайну
- Введение в собеседования по архитектуре и системному дизайну
- Шаблон собеседования по системному дизайну
Вопросы по системному дизайну с решениями
Типичные вопросы по системному дизайну на собеседовании с примерами обсуждения, кода и диаграммами.
Решения связаны с содержимым папки
solutions/.
| Вопрос | |
|---|---|
| Спроектируйте Pastebin.com (или Bit.ly) | Решение |
| Спроектируйте ленту и поиск Twitter (или ленту и поиск Facebook) | Решение |
| Спроектируйте веб-краулер | Решение |
| Спроектируйте Mint.com | Решение |
| Спроектируйте структуры данных для социальной сети | Решение |
| Спроектируйте хранилище «ключ-значение» для поисковой системы | Решение |
| Спроектируйте функцию Amazon с рейтингом продаж по категориям | Решение |
| Спроектируйте систему, масштабирующуюся до миллионов пользователей в AWS | Решение |
| Добавить вопрос по системному дизайну | Внести вклад |
Спроектируйте Pastebin.com (или Bit.ly)
Посмотреть упражнение и решение
Спроектируйте ленту и поиск Twitter (или ленту и поиск Facebook)
Посмотреть упражнение и решение
Спроектируйте веб-краулер
Посмотреть упражнение и решение
Спроектируйте Mint.com
Посмотреть упражнение и решение
Спроектируйте структуры данных для социальной сети
Посмотреть упражнение и решение
Спроектируйте хранилище «ключ-значение» для поисковой системы
Посмотреть упражнение и решение
Спроектируйте функцию Amazon с рейтингом продаж по категориям
Посмотреть упражнение и решение
Спроектируйте систему, масштабирующуюся до миллионов пользователей в AWS
Посмотреть упражнение и решение
Вопросы по объектно-ориентированному дизайну с решениями
Типичные вопросы по объектно-ориентированному дизайну на собеседовании с примерами обсуждения, кода и диаграммами.
Решения связаны с содержимым папки
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 раздаются статические файлы — 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-серверам не приходилось выполнять эти потенциально дорогостоящие операции
- Убирает необходимость устанавливать сертификаты X.509 на каждом сервере
- Персистентность сессий — выдавать куки и маршрутизировать запросы конкретного клиента на один и тот же инстанс, если веб-приложения не ведут учёт сессий
Чтобы защититься от отказов, обычно разворачивают несколько балансировщиков нагрузки, либо в режиме активно-пассивного, либо в режиме активно-активного.
Балансировщики нагрузки могут маршрутизировать трафик на основе различных метрик, включая:
- Случайный выбор
- Наименее загруженный сервер
- Сессия/куки
- Round robin или weighted round robin
- Слой 4
- Слой 7
Балансировка нагрузки на 4-м уровне
Балансировщики нагрузки 4-го уровня смотрят на информацию транспортного слоя, чтобы решить, как распределять запросы. Как правило, это исходный и конечный IP-адреса и порты в заголовке, но не содержимое пакета. Балансировщики 4-го уровня пересылают сетевые пакеты к upstream-серверу и от него, выполняя трансляцию сетевых адресов (Network Address Translation (NAT)).
Балансировка нагрузки на 7-м уровне
Балансировщики нагрузки 7-го уровня смотрят на прикладной слой, чтобы решить, как распределять запросы. Это может включать содержимое заголовка, сообщения и кук. Балансировщики 7-го уровня терминируют сетевой трафик, читают сообщение, принимают решение о балансировке, а затем открывают соединение с выбранным сервером. Например, балансировщик 7-го уровня может направлять видеотрафик на серверы, на которых размещены видео, а более чувствительный трафик по расчётам за услуги пользователей — на усиленные по безопасности серверы.
В ущерб гибкости балансировка на 4-м уровне требует меньше времени и вычислительных ресурсов, чем на 7-м, хотя на современном типичном оборудовании влияние на производительность может быть минимальным.
Горизонтальное масштабирование
Балансировщики нагрузки также помогают с горизонтальным масштабированием, улучшая производительность и доступность. Горизонтальное масштабирование за счёт типовых недорогих машин экономически выгоднее и обеспечивает бо́льшую доступность, чем наращивание мощности одного сервера на более дорогом оборудовании, называемое вертикальным масштабированием. Кроме того, проще искать специалистов, работающих с типовым оборудованием, чем со специализированными корпоративными системами.
Недостаток(и): горизонтальное масштабирование
- Горизонтальное масштабирование вносит сложность и предполагает клонирование серверов
- Серверы должны быть без состояния (stateless): они не должны содержать никаких пользовательских данных, таких как сессии или фотографии профилей
- Сессии можно хранить в централизованном хранилище данных, таком как база данных (SQL, NoSQL) или постоянный кэш (Redis, Memcached)
- Нижестоящим серверам, таким как кэши и базы данных, придётся обрабатывать больше одновременных соединений по мере того, как вышестоящие серверы будут горизонтально масштабироваться
Недостаток(и): балансировщик нагрузки
- Балансировщик нагрузки может стать узким местом по производительности, если у него недостаточно ресурсов или он неправильно настроен.
- Внедрение балансировщика нагрузки для устранения единой точки отказа приводит к увеличению сложности.
- Единственный балансировщик нагрузки — это единая точка отказа; настройка нескольких балансировщиков дополнительно увеличивает сложность.
Источник(и) и дополнительное чтение
- NGINX architecture
- HAProxy architecture guide
- Scalability
- Wikipedia
- Layer 4 load balancing
- Layer 7 load balancing
- ELB listener config
Обратный прокси (веб-сервер)
Реверс-прокси — это веб-сервер, централизующий внутренние сервисы и предоставляющий публике единые интерфейсы. Запросы от клиентов пересылаются на сервер, способный их удовлетворить, после чего реверс-прокси возвращает ответ сервера клиенту.
Дополнительные преимущества включают:
- Повышенная безопасность — скрывать информацию о backend-серверах, блокировать IP по чёрному списку, ограничивать число подключений на одного клиента
- Повышенная масштабируемость и гибкость — клиенты видят только IP-адрес реверс-прокси, что позволяет масштабировать серверы или менять их конфигурацию
- Терминация SSL — расшифровывать входящие запросы и шифровать ответы серверов, чтобы backend-серверам не приходилось выполнять эти потенциально дорогостоящие операции
- Убирает необходимость устанавливать сертификаты X.509 на каждом сервере
- Сжатие — сжимать ответы серверов
- Кэширование — возвращать ответ для закэшированных запросов
- Статический контент — раздавать статический контент напрямую
- HTML/CSS/JS
- Фотографии
- Видео
- И т. д.
Балансировщик нагрузки против обратного прокси
- Внедрение балансировщика нагрузки полезно, когда у вас несколько серверов. Часто балансировщики направляют трафик на набор серверов, выполняющих одну и ту же функцию.
- Реверс-прокси может быть полезен даже при наличии всего одного веб-сервера или application-сервера, открывая преимущества, описанные в предыдущем разделе.
- Решения вроде NGINX и HAProxy поддерживают как реверс-проксирование на 7-м уровне, так и балансировку нагрузки.
Недостаток(и): обратный прокси
- Внедрение реверс-прокси приводит к увеличению сложности.
- Единственный реверс-прокси — это единая точка отказа; настройка нескольких реверс-прокси (например, организация фейловера) дополнительно увеличивает сложность.
Источник(и) и дополнительное чтение
Прикладной слой
Источник: Введение в проектирование систем для масштабирования
Выделение веб-слоя из прикладного слоя (также известного как платформенный слой) позволяет масштабировать и настраивать оба слоя независимо. Добавление нового API приводит к добавлению серверов приложения без необходимости добавлять дополнительные веб-серверы. Принцип единственной ответственности поощряет небольшие автономные сервисы, которые работают совместно. Небольшие команды с небольшими сервисами могут более агрессивно планировать быстрый рост.
Работники (workers) в прикладном слое также помогают обеспечить асинхронность.
Микросервисы
Связанным с этим обсуждением является концепция микросервисов, которую можно описать как набор небольших модульных сервисов, развёртываемых независимо. Каждый сервис работает в отдельном процессе и общается через хорошо определённый лёгкомеханический канал для достижения бизнес-цели. 1
Например, у Pinterest могли быть следующие микросервисы: профиль пользователя, подписчики, лента, поиск, загрузка фото и т. д.
Поиск сервисов (Service Discovery)
Системы вроде Consul, Etcd и Zookeeper могут помочь сервисам находить друг друга, отслеживая зарегистрированные имена, адреса и порты. Проверки здоровья помогают убедиться в работоспособности сервиса и обычно выполняются с помощью HTTP-эндпоинта. В обоих Consul и Etcd есть встроенное хранилище «ключ-значение», которое может оказаться полезным для хранения значений конфигурации и других общих данных.
Недостаток(и): прикладной слой
- Добавление прикладного слоя с слабо связанными сервисами требует другого подхода с точки зрения архитектуры, эксплуатации и процессов (в отличие от монолитной системы).
- Микросервисы могут добавить сложность в части развёртывания и эксплуатации.
Источник(и) и дополнительное чтение
- Intro to architecting systems for scale
- Crack the system design interview
- Service oriented architecture
- Introduction to Zookeeper
- Here's what you need to know about building microservices
База данных
Источник: Масштабирование до первых 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
- Tips for optimizing MySQL queries
- Is there a good reason i see VARCHAR(255) used so often?
- How do null values affect performance?
- Slow query log
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
- Explanation of base terminology
- NoSQL databases a survey and decision guidance
- Scalability
- Introduction to NoSQL
- NoSQL patterns
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.
Источник(и) и дополнительное чтение
- From cache to in-memory data grid
- Scalable system design patterns
- Introduction to architecting systems for scale
- Scalability, availability, stability, patterns
- Scalability
- AWS ElastiCache strategies
- Wikipedia
Асинхронность
Источник: Введение в проектирование систем под масштаб
Асинхронные потоки работы помогают сократить время запросов дорогих операций, которые иначе выполнялись бы в основной линии. Они также помогают делать трудоёмкую работу заранее, например периодически агрегируя данные.
Очереди сообщений
Очереди сообщений принимают, хранят и доставляют сообщения. Если операция слишком медленна, чтобы выполнять её в основной линии, можно использовать очередь сообщений со следующим потоком работы:
- Приложение публикует задание в очередь, затем уведомляет пользователя о статусе задания
- Воркер забирает задание из очереди, обрабатывает его, затем сигнализирует об окончании задания
Пользователь не блокируется, а задание обрабатывается в фоне. За это время клиент может, по желанию, выполнить немного обработки, чтобы создать видимость завершённости задачи. Например, если публикуется твит, он может мгновенно появиться в вашей ленте, но на доставку всем подписчикам может уйти некоторое время.
Redis полезен как простой брокер сообщений, но сообщения могут теряться.
RabbitMQ популярен, но требует от вас поддержки протокола 'AMQP' и управления собственными узлами.
Amazon SQS управляемый, но может иметь высокую латентность, и возможна двукратная доставка сообщений.
Очереди задач
Очереди задач принимают задания и связанные с ними данные, выполняют их, затем доставляют результаты. Они могут поддерживать планирование и использоваться для запуска вычислительно тяжёлых заданий в фоне.
Celery поддерживает планирование и в первую очередь ориентирован на Python.
Обратное давление
Если очереди начинают сильно расти, размер очереди может превысить объём памяти, что приведёт к промахам в кэш, чтениям с диска и ещё большей деградации производительности. Обратное давление помогает ограничивая размер очереди, тем самым поддерживая высокий уровень пропускной способности и хорошее время отклика для заданий, уже находящихся в очереди. Когда очередь заполняется, клиенты получают статус «сервер занят» или HTTP 503, чтобы повторить попытку позже. Клиенты могут повторить запрос позднее, возможно, с экспоненциальной задержкой повторов.
Недостаток(и): асинхронность
- Для сценариев вроде дешёвых вычислений и потоков реального времени лучше подходят синхронные операции, ведь введение очередей добавляет задержки и сложность.
Источник(и) и дополнительное чтение
- It's all a numbers game
- Applying back pressure when overloaded
- Little's law
- What is the difference between a message queue and a task queue?
Коммуникация
Источник: Семислойная модель 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
- Networking for game programming
- Key differences between TCP and UDP protocols
- Difference between TCP and UDP
- Transmission control protocol
- User datagram protocol
- Scaling memcache at Facebook
Вызов удалённых процедур (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
- Do you really know why you prefer REST over RPC
- When are RPC-ish approaches more appropriate than REST?
- REST vs JSON-RPC
- Debunking the myths of RPC and REST
- What are the drawbacks of using REST
- Crack the system design interview
- Thrift
- Why REST for internal use and not 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 круговых поездок в секунду внутри одного центра обработки данных
Цифры задержек в визуализации
Источник(и) и дополнительное чтение
- Latency numbers every programmer should know - 1
- Latency numbers every programmer should know - 2
- Проектирование, уроки и советы по построению крупных распределённых систем
- Советы по инженерии ПО из опыта построения распределённых систем большого масштаба
Дополнительные вопросы по проектированию систем для собеседований
Распространённые вопросы по проектированию систем на собеседованиях со ссылками на материалы о том, как решать каждый из них.
| Вопрос | Ссылка(и) |
|---|---|
| Спроектируйте сервис синхронизации файлов, как 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 |
Корпоративные архитектуры
Инженерные блоги компаний
Архитектуры компаний, в которые вы идёте на собеседование.
Вопросы, которые вам зададут, могут быть из той же предметной области.
- Airbnb Engineering
- Atlassian Developers
- AWS Blog
- Bitly Engineering Blog
- Box Blogs
- Cloudera Developer Blog
- Dropbox Tech Blog
- Engineering at Quora
- Ebay Tech Blog
- Evernote Tech Blog
- Etsy Code as Craft
- Facebook Engineering
- Flickr Code
- Foursquare Engineering Blog
- GitHub Engineering Blog
- Google Research Blog
- Groupon Engineering Blog
- Heroku Engineering Blog
- Hubspot Engineering Blog
- High Scalability
- Instagram Engineering
- Intel Software Blog
- Jane Street Tech Blog
- LinkedIn Engineering
- Microsoft Engineering
- Microsoft Python Engineering
- Netflix Tech Blog
- Paypal Developer Blog
- Pinterest Engineering Blog
- Reddit Blog
- Salesforce Engineering Blog
- Slack Engineering Blog
- Spotify Labs
- Stripe Engineering Blog
- Twilio Engineering Blog
- Twitter Engineering
- Uber Engineering Blog
- Yahoo Engineering Blog
- Yelp Engineering Blog
- Zynga Engineering Blog
Источник(и) и дополнительное чтение
Хотите добавить блог? Чтобы не дублировать работу других, рассмотрите возможность добавления блога вашей компании в следующий репозиторий:
В разработке
Хотите добавить раздел или помочь завершить один из незавершённых? Contribute!
- Распределённые вычисления с MapReduce
- Согласованное хэширование (consistent hashing)
- Scatter gather (распределение и сбор)
- Contribute
Благодарности
Признания авторов и источники указаны по всему этому репозиторию.
Отдельная благодарность:
- Hired in tech
- Cracking the coding interview
- High scalability
- checkcheckzz/system-design-interview
- shashank88/system_design
- mmcgrana/services-engineering
- System design cheat sheet
- A distributed systems reading list
- Cracking the system design interview
Контактная информация
Свяжитесь со мной, чтобы обсудить любые проблемы, вопросы или комментарии.
Мою контактную информацию можно найти на моей странице GitHub.
Лицензия
Я предоставляю код и ресурсы в этом репозитории под открытой лицензией. Поскольку это мой личный репозиторий, лицензию на мой код и ресурсы вы получаете от меня лично, а не от моего работодателя (Facebook).
Copyright 2017 Donne Martin
Creative Commons Attribution 4.0 International License (CC BY 4.0)
http://creativecommons.org/licenses/by/4.0/







