Шпаргалка по System Design Blueprint
Разработка надежной, масштабируемой системы - это нетривиальная задача. Понимание ключевых концепций и компонентов может сделать этот процесс плавнее. В этой статье мы рассмотрим основные компоненты дизайна системы в виде шпаргалки, которая поможет разработчикам проектировать системы различной сложности.
1️⃣ Принципы проектирования системы
1.1: Модульность
Разделение системы на более мелкие, управляемые модули помогает уменьшить сложность, улучшить maintainability и дает возможность повторного использования.
1.2: 🖼️ Абстракция
Скрытие деталей реализации и показ только необходимых функций помогает упростить сложные системы и способствует модульности.
1.3: 📚 Layering
Разбивка системы на слои, каждый из которых обеспечивает определенный набор функций, способствует разделению задач и улучшает maintainability.
1.4: 📈 Scalability
Проектирование систем, которые способны справляться с пиком нагрузок путем добавления дополнительных инстансов (горизонтальное масштабирование) или добавление вычислительных мощностей (вертикальное масштабирование).
1.5: 💯 Performance
Оптимизация времени ответа, пропускной способности и использования ресурсов системы является важным для проектирования хороших систем.
1.6: 🔒 Безопасность
Гарантия конфиденциальности, целостности и доступности системы путем реализации соответствующих мер и практик безопасности.
1.7: 🛡️ Fault Tolerance и устойчивость
Проектирование систем, которые способны выдерживать сбои и восстанавливаться после ошибок, обеспечивает надежность и доступность.
2️⃣ Ключевые компоненты в System Design
2.1: 🌐 DNS (Domain Name System)
DNS - это иерархическая и децентрализованная система именования для компьютеров, сервисов или других ресурсов, подключенных к Интернету или частной сети. Он переводит доменные имена, понятные для человека (например, www.example.com), в IP-адреса, что позволяет пользователям более эффективно получать доступ к веб-сайтам и сервисам.
2.2: 🔀 Load Balancing
Load balancing относится к распределению сетевого трафика по нескольким серверам для того, чтобы ни один сервер не был перегружен. Этот подход улучшает доступность, надежность и производительность системы. Существуют следующие алгоритмы балансировки нагрузки:
- Round Robin
- Least Connections
- Sticky Sessions
- Client-side random load balancing
- Weighted Round Robin
- Weighted Response Time
- Улучшенные варианты Least Connections (Locality-Based Least Connection Scheduling и Locality-Based Least Connection Scheduling с Replication Scheduling)
- Destination Hash Scheduling и Source Hash Scheduling
- Fixed Weighting
2.3: 🔗 API Gateway
API Gateway – это сервер, который действует как посредник между клиентами и сервисами в распределенной системе. Он управляет и маршрутизирует запросы, применяет политики безопасности и предоставляет дополнительные функции, такие как кэширование, ведение журналов и мониторинг.
2.4: 🌍 Content Delivery Network (CDN)
Content Delivery Network (CDN) - это сеть серверов, распределенных по разным локациям, предназначенных для доставки контента пользователям с низким latency и высокой пропускной способностью. CDN кэширует контент на серверах, самых близких к юзерам, улучшая производительность системы и уменьшая нагрузку на основные серверы.
Традиционый CDN
Это самый распространенный тип CDN, который основан на сети географически распределенных серверов, которые кэшируют и доставляют контент. Вот как работает CDN:
- Пользователь запрашивает контент с веб-сайта.
- Запрос направляется на ближайший DNS-сервер, который сопоставляет доменное имя с IP-адресом и перенаправляет запрос на ближайший CDN server.
- CDN server проверяет кэш на наличие копии запрашиваемого контента. Если контент доступен, сервер доставляет его пользователю.
- Если контент недоступен в кэше, CDN server запрашивает оригинальный сервер для получения контента.
- Оригинальный сервер доставляет контент CDN serve'у, который кэширует копию контента для будущих запросов.
- CDN server доставляет контент пользователю.
- При следующем запросе на тот же контент, запрос направляется на ближайший CDN server, который может доставлять контент напрямую из своего кэша, улучшая производительность и снижая задержку.
Push CDN
Этот тип CDN работает путем активной передачи контента на CDN server'ы до того, как его запросят конечные пользователи. Программное обеспечение, большие медиафайлы и другие данные.
Video CDN
Этот CDN специально разработан для доставки видео контента и предлагает функции адаптивного стриминга и транскодинга в реальном времени. Очень полезно для улучшения опыта просмотра видео, вставки рекламы и тд.
Private CDN
Этот тип CDN предназначен для удовлетворения конкретных потребностей отдельной организации. В отличие от традиционной CDN, частная CDN обычно принадлежит и управляется организацией, а не предоставляется сторонним поставщиком. Эта CDN полезна для обеспечения безопасности доставки контента, оптимизации производительности и соблюдения требований и нормативных актов.
2.5: 📨 Message Queue
Message Queue (очередь сообщений) – облегчает коммуникацию между компонентами распределенной системы, временно храня сообщения в очереди. Асинхронно обрабатывают сообщения и помогают разделить компоненты, улучшая масштабируемость и устойчивость системы к ошибкам.
2.6: 🔌 Протоколы коммуникации
В system design используются различные протоколы коммуникации, такие как HTTP/HTTPS, WebSocket и gRPC. Эти протоколы имеют свои преимущества и недостатки, а выбор зависит от факторов, таких как задержка, безопасность и требования к передаче данных. Подробнее обсуждаем некоторые из них в разделе 4.
2.7: 💾 Cache
Кэширование – используют для временного хранения данных и ускорения запросов в будущем. Например, если вы часто заходите на сайт, то ваш браузер может кэшировать его страницы, чтобы при следующем посещении сайта он загружался быстрее. Таким образом, кэширование помогает сократить время ожидания, нагрузку на сервер и расходы на передачу данных.
- In-memory Caching: кэширование в памяти хранит данные кэша в памяти приложения, обеспечивая более быстрый доступ. Эта стратегия полезна для нагруженных приложений, которые обрабатывают большой объем операций чтения.
- Cache Sharding: Шардинг это техника, которая делит большой кэш на более мелкие разделы, их можно хранить на разных серверах. Это может помочь распределить нагрузку и уменьшить риск единой точки отказа. Каждый шард отвечает за определенный sub-set данных, обращающихся к конкретному ключу.
- Distributed caching: Distributed cache позволяет кэшировать данные на нескольких серверах, что может помочь уменьшить нагрузку на любой один сервер и улучшить общую производительность системы. Распределенные системы кэширования могут быть дополнительно разделены на replicated и partitioned кэширование. Replicated кэширование хранит копию данных на нескольких серверах, в то время как partitioned кэширование делит данные на фрагменты и хранит их на разных серверах.
- Content Delivery Networks (CDNs): это серверы, распределенные по всему миру. Они могут кэшировать и доставлять пользовательский контент на основе его географического расположения. Подробнее CDN мы разбирали выше в пункте 2.4.
2.8: 💽 Базы данных
Выбор подходящей базы данных для системы зависит от структуры данных, масштабируемости, consistency и latency. Распространенные типы баз данных включают реляционные базы данных (например, MySQL, PostgreSQL), NoSQL базы данных (например, MongoDB, Cassandra) и NewSQL базы данных (например, Cockroach DB, Google Spanner).
Статья для дополнительного изучения: Roadmap для Data инженеров
2.9: 🔄 Техники репликации
Репликация данных - это процесс копирования и распространения данных с одного узла на другой, чтобы обеспечить их доступность и защиту от потери. Репликация играет важную роль в обеспечении высокой доступности, защиты данных и масштабируемости.
Существует три типа репликации: synchronous (синхронная), asynchronous (асинхронная) и semi-synchronous (полу-синхронная) репликация. Каждый из них имеет свои преимущества и недостатки, и выбор конкретной технологии зависит от требований к системе.
Синхронная репликация - это метод репликации, при котором запись в основной базе данных считается завершенной только после того, как она будет записана во все реплики. Это означает, что все изменения данных будут отображаться во всех копиях данных в реальном времени, что обеспечивает высокую достоверность данных и надежность системы. Однако этот подход может привести к снижению производительности, так как каждый запрос на запись должен ждать подтверждения от всех узлов репликации.
Асинхронная репликация - это метод репликации, при котором изменения данных сначала записываются в основную базу данных, а затем передаются на реплики. Этот подход может обеспечить более высокую производительность, так как запись в основной базе данных не блокируется ожиданием подтверждения от всех узлов репликации. Однако это также означает, что реплики могут отставать от основной базы данных на некоторое время, что может привести к возникновению проблем при восстановлении после сбоев.
Полу-синхронная репликация - это комбинация синхронной и асинхронной репликации. При этом изменения данных сначала записываются в основную базу данных и синхронно передаются на несколько узлов репликации, а затем асинхронно передаются на остальные узлы. Это позволяет удовлетворить требования к достоверности данных и производительности системы.
В зависимости от требований к системе, можно выбрать наиболее подходящий метод репликации. Синхронная репликация обеспечивает высокую достоверность данных, но может снизить производительность. Асинхронная репликация, напротив, обеспечивает более высокую производительность, но может привести к возникновению задержек и потери данных при сбоях. Полу-синхронная репликация, в свою очередь, является компромиссом между синхронной и асинхронной репликацией, обеспечивая как достоверность данных, так и производительность.
2.10: 🔑 Генерация ключей в распределенной системе
Генерация уникальных идентификаторов в распределенной системе необходима для обеспечения согласованности и целостности данных.
Стандартный подход в не distributed системе выглядит следующим образом:
Так же один из вариантов генерировать timestamp. Из минусов при распределенных запросах система может генерировать одни и те же ID.
Рассмотрим какие требования часто выдвигают к ID для распределенных систем:
Функциональные требования:
- Идентификаторы должны иметь размер не более 64 бита.
- Генерация уникальных идентификаторов должна происходить последовательно по всему кластеру.
- Необходимо генерировать более 10 000 уникальных идентификаторов в секунду.
Non-Functional Requirements
- Высокая производительность.
- Low latency, включая Geo-Latency.
- Высокая доступность.
- Устойчивость к сбоям.
- Легкость масштабирования.
Таблица сравнения подходов к генерации ID:
В рамках этой статьи не будем рассматривать более подробно каждый из подходов, лишь скажем, что тут нет единого решения, у каждого из подходов есть свои trade-offs. По этому выбор за вами, так же можно создать собственное решение, помните что готовые решения проверены временем и сообществом, а ваши велосипеды только в будущем будут наступать на грабли.
3️⃣ Загрузка видео и изображений chunk'aми с использованием Signed URL
В этом разделе мы рассмотрим, как загружать видео и изображения файлы порциями, используя Signed URL. Этот метод может значительно повысить эффективность и надежность загрузки файлов, особенно в ситуациях, когда условия сети не идеальны.
3.1: 🔐 Что такое Signed URL
Signed URL – это специально созданные адреса, которые предоставляют временный, безопасный доступ к определенному ресурсу, например, объекту в облачном хранилище. Эти URL-адреса содержат аутентификационную подпись, которая позволяет пользователю выполнить определенное действие, такое как загрузка или скачивание файла, на ограниченный период времени. Популярные облачные сервисы хранения, такие как Amazon S3 и Google Cloud Storage, поддерживают генерацию подписанных URL-адресов. Ниже пример того, как может выглядеть подписанный URL-адрес:
https://example-bucket.s3.amazonaws.com/my-file.txt?\
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20220407%2Fus-east-1%2Fs3%2Faws4_request&\
X-Amz-Date=20220407T123456Z&\
X-Amz-Expires=3600&\
X-Amz-SignedHeaders=host&\
X-Amz-Signature=a9c8a7d1644c7b351ef3034f4a1b4c9047e891c7203eb3a9f29d8c7a74676d88
3.2: 🎥 Загрузка файлов виде chunk'ов
Загрузка больших файлов в одном запросе может привести к таймаутам, высокому потреблению памяти и повышенному риску отказа из-за нестабильности сети. Вместо этого разбиение больших файлов на более мелкие кусочки и последовательная или параллельная загрузка их может улучшить эффективность и надежность загрузки. Этот подход называется "chunked" или "multipart" upload.
3.3: 🔗 Комбинация Signed URL и chunk'ов
Для загрузки видео и изображений в чанками с использованием подписанных URL необходимо выполнить следующие шаги
- Разделите файл на более мелкие части: Разбейте большой файл на более мелкие части на стороне клиента, обычно с помощью JavaScript. Размер каждой части может варьироваться, но важно найти баланс между количеством запросов и размером каждой части, чтобы оптимизировать производительность загрузки.
- Запросите подписанные URL для каждого чанка: Отправьте запрос на ваш сервер, чтобы сгенерировать подписанный URL для каждой части файла. Сервер должен создать подписанный URL с соответствующими разрешениями и временем истечения срока действия и вернуть его клиенту.
- Загрузите части файла с использованием подписанных URL: Используя подписанные URL, загрузите каждую часть в облачное хранилище. В зависимости от желаемого уровня параллелизма и условий сети, эти загрузки могут выполняться последовательно или параллельно.
- Подтвердите успешную загрузку и соберите файл: Когда все части будут успешно загружены, уведомите сервер, чтобы подтвердить завершение процесса загрузки. Затем сервер может объединить части в исходный файл и выполнить любую необходимую обработку или проверку.
- Обрабатывайте Error'ы: Если какая-то часть не загрузится, повторите загрузку с использованием нового подписанного URL или реализуйте стратегию обработки ошибок, чтобы обеспечить плавную загрузку всех кусочков исходного файла.
Используя подписанные URL и загрузку файлов частями, разработчики могут эффективно и безопасно обрабатывать загрузку больших видео и изображений, повышая надежность и производительность своих систем.
4️⃣ Chat и Streaming протоколы
4.1: 📡 RTMP (Real-Time Messaging Protocol) RTMP server
→ client
RTMP - протокол, разработанный компанией Adobe Systems для потоковой передачи аудио, видео и данных в Интернете. Он широко используется в приложениях для видеостриминга и обеспечивает связь с низкой задержкой между клиентами и серверами. Однако, из-за своей зависимости от Flash Player, его популярность в последние годы убывает.
4.2: 🗜️ WebRTC (Web Real-Time Communication) peer
↔ peer
WebRTC - это проект с открытым исходным кодом, позволяющий реализовать передачу аудио, видео и данных в реальном времени в веб-браузерах и мобильных приложениях. Он поддерживает соединения между узлами "pear-to-pear", что позволяет снизить задержки и нагрузку на серверы. WebRTC широко используется в видеоконференциях, онлайн-играх и других приложениях, требующих real-time communication.
4.3: 🌐 WebSocket client
↔ server
.
WebSocket - это протокол обмена данными, который обеспечивает двустороннюю, полнодуплексную связь между клиентом и сервером через одние длительный коннекшн. Благодаря своей низкой задержке и эффективности обмена данными, WebSocket часто используется для приложений реального времени, таких как чаты, уведомления и live апдейты.
4.4: 📩 SSE (Server-Sent Events) client
← server
Server-Sent Events (SSE) - это технология, которая позволяет серверам отправлять обновления клиенту по HTTP-соединению. Она разработана для односторонней, реального времени связи от сервера к клиенту, что делает ее подходящей для приложений, таких как live updates, news feeds, и нотификации. SSE схоже на вебсокеты, но в отличии от веб сокетов, клиент не отправляет серверу сообщений, а только принимает от сервера.
4.5: 🔁 HTTP Short Polling request
→ response
→ wait
Short polling - это повторная отправка клиентом HTTP-запросов на сервер для проверки наличия новых обновлений. Хотя это просто в реализации (делаем один и тот же запрос по таймеру), short polling может привести к высокой нагрузке на сервер и увеличенной задержке из-за постоянных опросов, особенно когда обновлений не так много.
4.6: 🔁 HTTP Long Polling request
→ wait
→ response
Long Polling – это улучшенный вариант Short Polling, при котором клиент отправляет запрос на сервер, а сервер удерживает запрос открытым, пока новые данные не станут доступны. Этот подход сокращает количество запросов и уменьшает нагрузку на сервер, но все еще может страдать от проблем с задержкой и требует тщательного управления ресурсами сервера. На данном этапе предпочтительнее юзать SSE из раздела 4.4 вместо Long polling.
4.7: ↩️ Webhook service
→ notify
→ target URL
Webhooks - это пользовательские HTTP коллбеки, вызываемые определенными событиями в системе. Когда событие происходит, сервис делает HTTP-запрос на URL, настроенный для webhook'а. Этот подход позволяет эффективно осуществлять коммуникацию между разными системами или сервисами, основанную на событиях.
5️⃣ Общие компоненты при System Design
В этой секции обсудим некоторые стандартные компоненты, которые часто встречаются в современных системах. Понимание этих компонентов может помочь разработчикам интегрировать их в свои системы.
5.1: 💰 Payment Service
Сервисы оплаты обрабатывают транзакции между клиентами и бизнесами. Интеграция сервиса оплаты важный аспект для E-commerce и платформ с подпиской. Популярные провайдеры сервисов оплаты: Stripe, PayPal и Square. Эти сервисы обычно предоставляют API для безопасных транзакций и управления регулярными платежами, возвратами и т.д.
5.2: 📊 Analytic Service
Сервисы аналитики позволяют собирать, обрабатывать и визуализировать данные, помогая бизнесам принимать обоснованные решения. Эти сервисы могут отслеживать поведение пользователей, контролировать производительность системы и анализировать тенденции. Несколько популярных провайдеров аналитики: Google Analytics, Mixpanel и Amplitude. Интеграция сервисов аналитики в систему может помочь бизнесам оптимизировать свои предложения и улучшить опыт пользователей.
5.3: 📊 Сервис уведомлений
Сервисы уведомлений информируют пользователей об обновлениях, оповещениях и важной информации. Эти сервисы могут доставлять уведомления через различные каналы, такие как электронная почта, SMS и пуш-уведомления. Примеры провайдеров сервисов уведомлений: Firebase Cloud Messaging (FCM), Amazon Simple Notification Service (SNS) и Twilio.
5.4: 🔍 Поиск
Интеграция мощного компонента поиска существенна для систем с большим объемом данных или контента. Сервис поиска должен обеспечивать быстрый, релевантный и масштабируемый поиск. Elasticsearch, Apache Solr и Amazon CloudSearch являются популярными выборами для реализации функционала поиска. Эти сервисы обычно поддерживают поиск по полному тексту, частичный поиск и фильтрацию, что позволяет пользователям быстро и эффективно находить нужную информацию.
5.5: 💡 Сервис рекомендаций
Сервисы рекомендаций используют алгоритмы, чтобы предоставлять персонализированные рекомендации пользователям на основе их.
6️⃣ Лучшие практики System Design
6.1: 📝 Сбор требований
Сбор требований является критическим этапом при построении архитектуры системы для solution architect. Ниже приведены несколько шагов, которые помогут вам собрать нужную информацию и принять правильные решения:
- Понимание целей бизнеса: Начните с того, чтобы выяснить, какие цели должна достигнуть создаваемая система. Определите, что должна обеспечить система, какие бизнес-процессы должна поддерживать, какие проблемы должна решать и т.д. Это поможет вам понять, какие требования должна удовлетворять система.
- Изучение требований пользователей: Вы должны понимать, кто будут главными пользователями системы и как они будут использовать ее. Взаимодействуйте с BA и product owner'ами.
- Определение нефункциональных требований: Нефункциональные требования определяют, как система должна работать и какую производительность она должна иметь. Это включает в себя такие вещи, как надежность, масштабируемость, производительность, безопасность и т.д. Подумайте, какие требования нужны для удовлетворения целей бизнеса.
- Документирование требований: Необходимо составить список всех требований и их приоритетов. Это поможет вам понять, что должна делать система, чтобы достигнуть целей бизнеса. Опишите возможные ограничения, которые могут повлиять на их реализацию.
- Проверка требований: Необходимо убедиться, что все требования были правильно поняты и правильно описаны. Сделайте ревью требований с заказчиком и другими заинтересованными сторонами, чтобы убедиться, что все требования удовлетворяют их потребности и ожидания.
- Управление изменениями: После утверждения требований, может возникнуть необходимость изменений в процессе работы над проектом. Убедитесь, что у вас есть процедура управления изменениями, чтобы все изменения были правильно документированы и проанализированы на их влияние на проект.
- Построение прототипов: Для больших или сложных проектов, может быть полезным создание прототипов, которые позволят проверить работоспособность и удовлетворение требований. Прототипы могут помочь выявить недостатки и проблемы, которые могут быть исправлены до начала работы над проектом.
6.2: 🧩 Шаблоны проектирования
Используйте уже готовые подходы и шаблоны проектирования и референс-архитектуры, это позволит решать задачи эффективнее и не городить велосипедов. Неколько полезных ресурсов:
- Статьи по шаблонам проектирования и программирования
- Статьи про архитектрурные решения
- Статьи с обзором как построена IT архитектура в крупных компаниях
- Шаблоны проектирования Cloud-based и микросервисных приложений
- Алгоритмы, которые вы должны знать перед System Design Interview
- Каталог паттернов для архитектуры корпоративных приложений (PoEAA)
- Шаблоны проектирования "банды четырёх (GoF)"
- Антипаттерны в программировании и проектировании архитектуры
6.3: 📖 Документация
Не забывайте про документацию, система должна документироваться не только в начале разработки, но и при внесении изменений, при инвестигейтах и PoC'шках нужно так же документировать результат.
6.4: 🔄 Итеративный дизайн
Совершенствуйте свой дизайн через несколько итераций и обратную связь, позволяя ему развиваться и улучшаться.
6.5: 🧪 Тестирование и проверка
Проверьте свой дизайн на соответствие требованиям и проведите тестирование, чтобы выявить и устранить потенциальные проблемы.
Ресурсы для изучения:
Создание системы - это сложный процесс, который требует глубокого понимания различных компонентов, протоколов и техник. В этом блоге мы рассмотрели такие важные темы, как DNS, балансировка нагрузки, API Gateway, обработка видео и изображений, кэширование, базы данных, генерация уникальных ID, общие компоненты, такие как платежные и рекомендательные сервисы, а также чат и протоколы потоковой передачи.
Используя эти знания, разработчики могут создавать масштабируемые, эффективные и надежные системы, которые удовлетворяют различным требованиям и обеспечивают позитивный опыт пользователя. Важно помнить, что создание системы - это итеративный процесс, и постоянное улучшение является ключевым фактором в построении и поддержании успешных приложений.