Памятка по системному дизайну
Выбор правильной архитектуры = Выбор правильных сражений + Управление компромиссами
Перевод: https://gist.github.com/vasanthk/485d1c25737e8e72759f
Основные шаги
- Уточнить и согласовать масштаб системы
- Варианты использования (описание последовательностей событий, которые в совокупности приводят к полезному действию системы)
- Кто будет использовать систему?
- Как они будут ее использовать?
- Ограничения
- В основном определите ограничения по обработке трафика и данных в масштабе.
- Масштаб системы (запросы в секунду, типы запросов, объем записываемых данных в секунду, объем считываемых данных в секунду)
- Особые системные требования, такие как многопоточность, ориентация на чтение или запись.
- Проектирование архитектуры высокого уровня (абстрактный дизайн)
- Набросайте важные компоненты и связи между ними, не вдаваясь в детали.
- Уровень сервиса приложений (обслуживает запросы)
- Перечислите различные необходимые сервисы.
- Уровень хранения данных
- Например, масштабируемая система обычно включает веб-сервер (балансировщик нагрузки, load balancer), сервис (разделение сервисов, service partition), базу данных (кластер баз данных master/slave) и системы кэширования.
- Проектирование компонентов
- Компоненты + конкретные API, необходимые для каждого из них.
- Объектно-ориентированный дизайн для функциональности.
- Сопоставление функций с модулями: один сценарий для одного модуля.
- Рассмотрите отношения между модулями:
- Некоторые функции должны иметь уникальный экземпляр (Одиночки, Singletons)
- Основной объект может состоять из многих других объектов (композиция, composition)
- Один объект является другим объектом (наследование, inheritance)
- Проектирование схемы базы данных.
- Понимание узких мест
- Возможно, вашей системе нужен балансировщик нагрузки и множество машин за ним для обработки пользовательских запросов.
- Или, возможно, данных так много, что вам нужно распределить базу данных на несколько машин. Каковы некоторые недостатки, возникающие при этом?
- Слишком ли медленная база данных и нуждается ли она в кэшировании в памяти?
- Масштабирование абстрактного дизайна
- Вертикальное масштабирование (vertical scaling)
- Масштабирование путем добавления большей мощности (CPU, RAM) к существующей машине.
- Горизонтальное масштабирование (horizontal scaling)
- Масштабирование путем добавления большего количества машин в пул ресурсов.
Кэширование (Caching)
Балансировка нагрузки помогает масштабироваться горизонтально на постоянно растущем числе серверов, но кэширование позволит вам гораздо эффективнее использовать уже имеющиеся ресурсы, а также сделает возможными иначе недостижимые требования к продукту.
- Кэширование приложений требует явной интеграции в код приложения. Обычно оно проверяет, есть ли значение в кэше; если нет, извлекает значение из базы данных.
- Кэширование базы данных, как правило, «бесплатно». Когда вы включаете базу данных, вы получаете некоторый уровень настройки по умолчанию, который обеспечит определенную степень кэширования и производительности.
- Кэши в памяти (in-memory caches) наиболее мощны с точки зрения чистой производительности. Это потому, что они хранят весь набор данных в памяти, а доступ к RAM на порядки быстрее, чем к диску. Например, Memcached или Redis.
Примеры:
- Предварительный расчет результатов (например, количество посещений с каждого реферального домена за предыдущий день)
- Предварительное создание дорогостоящих индексов (например, предлагаемые истории на основе истории кликов пользователя)
- Хранение копий часто запрашиваемых данных в более быстром бэкенде (например, Memcache вместо PostgreSQL)
Балансировка нагрузки (Load balancing)
Публичные серверы масштабируемого веб-сервиса скрыты за балансировщиком нагрузки. Этот балансировщик нагрузки равномерно распределяет нагрузку (запросы от ваших пользователей) на вашу группу/кластер серверов приложений.
Типы:
- Умный клиент (трудно сделать идеально)
- Аппаратные балансировщики нагрузки (дорого, но надежно)
- Программные балансировщики нагрузки (гибридные — подходят для большинства систем)
Репликация базы данных (Database replication)
Репликация базы данных — это частое электронное копирование данных из базы данных на одном компьютере или сервере в базу данных на другом, чтобы все пользователи имели доступ к одному уровню информации. Результатом является распределенная база данных, в которой пользователи могут получить доступ к данным, относящимся к их задачам, не мешая работе других. Реализация репликации базы данных с целью устранения неоднозначности или несогласованности данных между пользователями известна как нормализация.
Партиционирование базы данных (Database partitioning)
Партиционирование реляционных данных обычно относится к разложению ваших таблиц либо по строкам (горизонтально), либо по столбцам (вертикально).
Map-Reduce
Для достаточно небольших систем вы часто можете обойтись специальными запросами к SQL-базе данных, но этот подход может не масштабироваться тривиально, когда количество хранимых данных или нагрузка на запись требует шардинга вашей базы данных, и обычно требует выделенных подчиненных узлов для выполнения этих запросов (в этот момент, возможно, вы предпочтете использовать систему, разработанную для анализа больших объемов данных, вместо борьбы с вашей базой данных).
Добавление слоя map-reduce позволяет выполнять интенсивные операции с данными и/или обработкой за разумное время. Вы можете использовать его для расчета предлагаемых пользователей в социальном графе или для создания аналитических отчетов. Например, Hadoop, и, возможно, Hive или HBase.
Платформенный слой (Сервисы) (Platform Layer (Services))
Разделение платформы и веб-приложения позволяет масштабировать части независимо. Если вы добавляете новый API, вы можете добавить серверы платформы без добавления ненужной мощности для уровня веб-приложения.
Добавление платформенного слоя может быть способом повторного использования вашей инфраструктуры для нескольких продуктов или интерфейсов (веб-приложение, API, приложение для iPhone и т.д.) без написания слишком большого количества избыточного шаблонного кода для работы с кэшами, базами данных и т.д.
Ключевые темы для проектирования системы
- Параллелизм (Concurrency)
- Понимаете ли вы потоки, взаимоблокировку и голодание? Знаете ли вы, как распараллеливать алгоритмы? Понимаете ли вы согласованность и когерентность?
- Сетевое взаимодействие (Networking)
- Примерно понимаете ли вы IPC и TCP/IP? Знаете ли вы разницу между пропускной способностью и задержкой, и когда каждый фактор является релевантным?
- Абстракция (Abstraction)
- Вы должны понимать системы, на которых вы строите. Знаете ли вы примерно, как работают ОС, файловая система и база данных? Знаете ли вы о различных уровнях кэширования в современной ОС?
- Производительность в реальном мире (Real-World Performance)
- Вы должны быть знакомы со скоростью всего, что может делать ваш компьютер, включая относительную производительность RAM, диска, SSD и вашей сети.
- Оценка (Estimation)
- Оценка, особенно в форме приблизительного расчета, важна, потому что она помогает вам сузить список возможных решений только до тех, которые осуществимы. Тогда вам нужно написать только несколько прототипов или микро-бенчмарков.
- Доступность и надежность (Availability & Reliability)
- Думаете ли вы о том, как вещи могут выйти из строя, особенно в распределенной среде? Знаете ли вы, как проектировать систему для борьбы с сетевыми сбоями? Понимаете ли вы долговечность?
Соображения по проектированию системы веб-приложений:
- Безопасность (CORS)
- Использование CDN
- Сеть доставки контента (CDN) — это система распределенных серверов (сеть), которая доставляет веб-страницы и другой веб-контент пользователю на основе географического расположения пользователя, происхождения веб-страницы и сервера доставки контента.
- Эта услуга эффективна для ускорения доставки контента веб-сайтов с высоким трафиком и веб-сайтов с глобальным охватом. Чем ближе сервер CDN географически к пользователю, тем быстрее контент будет доставлен пользователю.
- CDN также обеспечивают защиту от больших всплесков трафика.
- Полнотекстовый поиск (Full Text Search)
- Использование Sphinx/Lucene/Solr — которые достигают быстрых поисковых ответов, потому что вместо прямого поиска по тексту они ищут по индексу.
- Автономная поддержка/Прогрессивное улучшение
- Service Workers
- Web Workers
- Серверный рендеринг (Server Side rendering)
- Асинхронная загрузка активов (Lazy load items)
- Минимизация сетевых запросов (Http2 + bundling/sprites и т.д.)
- Продуктивность разработчиков/Инструментарий
- Доступность (Accessibility)
- Интернационализация
- Отзывчивый дизайн (Responsive design)
- Совместимость браузеров
Рабочие компоненты архитектуры фронтенда
- Код
- HTML5/WAI-ARIA
- Стандарты и организация кода CSS/Sass
- Объектно-ориентированный подход (как объекты разбиваются и собираются вместе)
- JS фреймворки/организация/техники оптимизации производительности
- Доставка активов — Фронтенд операции
- Документация
- Документы по внедрению
- Руководство по стилю/Библиотека шаблонов
- Диаграммы архитектуры (поток кода, цепочка инструментов)
- Тестирование
- Тестирование производительности
- Визуальная регрессия
- Модульное тестирование
- Сквозное тестирование
- Процесс
- Git Workflow
- Управление зависимостями (npm, Bundler, Bower)
- Системы сборки (Grunt/Gulp)
- Процесс развертывания
- Непрерывная интеграция (Travis CI, Jenkins)