ТехнофITнес | Никита Ульшин – Telegram
ТехнофITнес | Никита Ульшин
295 subscribers
3 photos
53 links
Подкачивай хард-скиллы и держи техническую форму с регулярными разборами ключевых IT материалов: архитектура, базы данных, производительность и системный дизайн.

По всем вопросам и рекламе: @NikitaUlshin
Download Telegram
Паттерны микросервисов: SAGA

Одна из вещей, которая так прекрасна в монолите — возможность никогда не сталкиваться с eventual consistency. Всё обмазано ACID-транзакциями, всё просто и понятно. Не жизнь, а сказка!

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

Статья описывает паттерн Сага, способы организации саг, возможные аномалии и контрмеры по борьбе с ними.

⭐️ Интересные идеи

➡️ Конечно, существуют распределённые транзакции. Проблема в том, что многие технологии не поддерживают протокол двухфазного коммита, что ограничивает нас в выборе технологий. Плюс, 2PC ещё и очень хрупкий.

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

➡️ Для отката транзакций в сагах используются “компенсирующие транзакции” — специальные шаги, которые возвращают состояние системы в нужную точку.

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

➡️ Оркестрация более понятна и удобна, но создаёт single point of failure. Хореография более надёжна и проста в разработке, но ей гораздо сложнее управлять, а понимание процесса может быть крайне нетривиальной задачей.

➡️ Одна из главных проблем в сагах — отсутствие изолированности, как у классических транзакций. Это вызывает аномалии, в частности “грязные чтения”, “неповторяемые чтения” и “потерянные обновления”.

➡️ Одной из контрмер является semantic lock — пометка сущности как взятой в работу, чтобы её нельзя было изменить повторно. Например, в случае с заказом мы можем пометить его как “*_PENDING”, и другие запросы будут знать, что этот заказ трогать не нужно.

➡️ Главная контрмера против проблем с сагами — не использовать саги грамотный дизайн самих саг. Он позволяет избежать множества проблем. Многие из них можно увидеть и устранить ещё на этапе проектирования саги, просто убрав лишние шаги или изменив порядок действий.

Приятного чтения!

#microservices@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥42👍2
System Design — одна из самых сложных секций на собеседовании

На нём валятся даже инженеры, которые уже не первый год в разработке и не один десяток сервисов написали. Причём чаще всего причина заключается не в том, что они волнуются или действительно чего-то не знают. Чаще всего они просто не понимают, чего от них хотят✖️

Хотя секция дизайна и сложна, к ней тоже можно подготовиться. Я провожу такие секции и собрал чек-лист по подготовке к системному дизайну. Вот, что внутри:

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

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

Чек-лист доступен подписчикам. Жми кнопку ниже — получишь инструкцию, как его получить.
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍21🔥75
Обзор кэширования (с паттернами)

Вчерашний праздник я решил почтить молчанием. Поэтому пост переехал на субботу.

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

Кэш — крутая штука, но только при условии грамотного использования. Неправильное использование кэша может вызвать трудноуловимые (а порой ещё и крайне проблематичные) баги.

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

⭐️ Интересные идеи

➡️ Некоторые паттерны (например, Write Through и Write Back) могут значительно снизить нагрузку на БД, но при этом имеют риски потери данных. Может здорово пригодиться в нагруженных системах, где потери некоторых данных не так критичны.

➡️ Refresh-Ahead — очень интересный паттерн, при котором данные в кэше обновляются асинхронно, что (теоретически) позволяет вообще не ходить в БД. Я использовал этот паттерн в одной из систем пару лет назад — он позволяет круто снизить нагрузку.

➡️ У кэша есть несколько разных стратегий вытеснения, которые могут пригодиться в разных ситуациях. Иногда бывает полезно очистить даже самые “горячие” данные, если “холодные” будут использоваться с большей вероятностью.

Приятного чтения!

#systemdesign@tech_fit #databases@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍433🔥3
Исправляем дублирование запросов к API

Меня безумно порадовала первая же строка этой статьи:

«Первое правило распределённых систем — не превращайте свою систему в распределённую.»


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

Одна из таких проблем — дублирующие запросы к API. Распределённые системы лишены ACID-транзакций (в лучшем случае можно применить сагу), поэтому дублирующие запросы на чувствительные операции могут вызвать трудноустранимые баги. Решением является идемпотентность, которой и посвящена статья.

⭐️ Интересные идеи

➡️ Идемпотентность — это свойство операций, которое позволяет применять их многократно без изменения конечного состояния приложения. Идемпотентны методы GET, PUT, DELETE, HEAD, OPTIONS и TRACE. POST и PATCH не являются идемпотентными.

➡️ Для обеспечения идемпотентности используется отслеживание пар ключ–запрос. Ключ генерируется на клиенте для каждого запроса и называется ключом идемпотентности.

➡️ Для ключа идемпотентности предусмотрен специальный HTTP-заголовок Idempotency-Key. Он принимает строку; в качестве примера спецификация использует UUID.

➡️ Спецификация также описывает обработку ошибок. Указаны три статуса:
🟡400 — не указан ключ идемпотентности
🟡422 — ключ идемпотентности уже использован
🟡409 — запрос с указанным ключом идемпотентности уже обрабатывается

Приятного чтения!

#systemdesign@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥72👍2
Слой абстракции над Key-Value от Netflix

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

В сегодняшней статье разбирается слой абстракции (Data Abstraction Layer, DAL) над Key-Value-хранилищами, разработанный Netflix как способ борьбы с расширением технологического стека хранилищ компании.

Netflix часто применяет самые современные решения в своих системах, но это приводило к тому, что инженерам приходилось постоянно переучиваться на новые технологии — разбираться с гарантиями хранилищ, их подходом к моделированию данных и так далее. Вдобавок приходилось следить за изменениями в нативных API множества БД. Управлять таким адским зоопарком стало очень сложно.

⭐️ Интересные идеи

➡️ В качестве решения инженеры Netflix решили написать свой сервис для работы с KV-хранилищами. Это позволило скрыть нюансы работы с конкретной базой за абстракцией и сделать API более стабильным.

➡️ Основная модель данных хранилища — двухуровневый map. Первый уровень — ID (primary key), второй — сортированный map байтовых пар (SortedMap<bytes, bytes>). Такая структура данных позволяет эффективно закрывать большинство use cases.

➡️ Для физического и логического разделения данных используются namespaces. В namespace также записываются конфигурация доступа к данным и параметры хранилища. Например, можно задать уровень согласованности.

➡️ Для больших кусков данных используется умное разделение на чанки. Если запись >1 МБ, то в основном хранилище хранятся только ID, ключ и метаданные, а сами данные делятся на маленькие чанки и складываются в отдельное хранилище.

➡️ Для пагинации ограничение сделано в байтах, а не в количестве сущностей на страницу. Так инженеры обеспечивают высокий SLO (единицы миллисекунд на операцию чтения страницы в 2 МиБ). Но этот подход создаёт и свои сложности, потому что многие базы поддерживают только «поштучную» пагинацию. Поэтому для них пришлось писать свои костыли.

➡️ Также дополнительно реализована адаптивная пагинация. Поскольку пагинация опирается на объём данных, а не количество сущностей, важную роль начинает играть средний размер сущности в namespace. Поэтому сервис DAL постоянно вычисляет и кэширует это значение, опираясь на него для fine tuning запросов на получение данных.

Приятного чтения!

#highload@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍3🔥31
Внутри S3

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

Это интересно, потому что внутри хранилища Яндекса лежит огромное количество файлов, и точно найдутся разные неудобные паттерны доступа и нагрузки от клиентов. Поэтому разработчики S3 набили много шишек, которыми и поделились в докладе.

⭐️ Интересные идеи

➡️ Инженеры Яндекса разработали свой сервис для работы напрямую с жёсткими дисками. Он держит более 1,000,000 RPS и работает с триллионами файлов. Про него есть отдельный доклад, который я позже обязательно посмотрю и напишу обзор. Для особо любопытных — вот ссылка.

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

➡️ Фоном работают несколько процессов: mover перетаскивает чанки между бакетами, splitter делит жирные чанки на более мелкие. Процессы блокируют чанк на запись, но работают единицы секунд, поэтому негативное влияние на клиента незначительно.

➡️ Для многих внутренних процессов важно корректно вычислять счётчики (тот же расчёт квот), но при подсчёте «в лоб» они обычно страдают от конкурентности. Решением стала очередь счётчиков: каждое изменение складывается в специальную очередь, которую разгребает фоновый процесс. Этот же процесс используется для биллинга, потому что видит все изменения в бакетах.

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

Приятного чтения!

#highload@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥53👍2
Прогрев кэша в стиле Netflix

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

Проблему вызвало масштабирование кластеров кэша: для поднятия нового кластера приходилось делать двойную запись с существующего кластера и затем дать данным в существующем протухнуть. Но такой подход имеет дополнительные косты в виде поддержки двух (дорогущих) кластеров.

Проблем добавляла и инфраструктура AWS, которая регулярно вырубает ноды кэша по каким-то своим причинам, что вызывало сильные просадки по latency (представляете, что будет, если на нагрузках Netflix просто погасить кэш?).

⭐️ Интересные идеи

➡️ В качестве решения была создана инфраструктура прогрева кэша. Она делится на две смысловые части: прогрев реплик и прогрев инстансов.

➡️ Само решение состоит из трёх компонентов: Controller, Dumper, Populator. Controller выполняет роль оркестратора и очищает ресурсы, Dumper создаёт дампы кэша (спасибо, кэп), Populator накатывает дампы на новые реплики.

➡️ Dumper и Populator общаются через SQS-очередь, которая создаётся специально для них контроллером. Dumper заливает данные на S3 и кладёт ID чанка в очередь, Populator вычитывает их и накатывает на ноду. Операция считается завершённой, когда очередь пуста — Controller удаляет её и инстансы Dumper/Populator.

Приятного чтения!

#highload@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍72🔥1
Как архитектура LinkedIn позволяет находить сообщение за 150мс

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

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

⭐️ Интересные идеи

➡️ Основой архитектуры стали два вывода. Во-первых, пользователь может искать только по своим сообщениям, что позволяет строить индекс на основе его инбокса. Во-вторых, не все пользователи пользуются поиском, поэтому имеет смысл строить индекс только для тех, кто это делает (строить индексы — довольно дорого по ресурсам).

➡️ Для хранения сообщений используется KV store RocksDB. Сообщения хранятся в значениях по ключу вида MemberId | ConversationId | MessageId.

➡️ Для поиска строится инвертированный индекс, используется Apache Lucene (которая, например, лежит в основе OpenSearch). Для построения индекса фразы токенизируются и сохраняются в виде карты токен-сообщения.

➡️ Индекс создаётся лениво — когда пользователь делает запрос на поиск. При запросе вытаскиваются все сообщения пользователя из RocksDB и выстраиваются в in-memory индекс, который используется для ускорения дальнейших операций поиска.

➡️ Индексы партиционируются и распределяются по разным нодам, чтобы не перегружать одну. Для координации используется Zookeeper и sticky routing.

➡️ Про TTL индекса статья умалчивает.

Приятного чтения!

#systemdesign@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥42👍2
Тейва Харшани «100 ошибок Go и как их избежать»

Пришло время и в этом канале открыть мою любимую рубрику — обзоры книг!

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

Конечно же, базовые книжки я прочитал ещё на стадии изучения языка. Но с тех пор как-то руки не доходили почитать что-то конкретно про Go — я больше читал про архитектуру, распределённые системы и базы данных. И тут произошло неожиданно приятное событие: ко мне пришли ребята из издательского дома «Питер» и предложили сделать обзор на обновлённое издание книги «100 ошибок Go».

Конечно, я не мог отказаться от обзора очередной интересной книги. Тем более что «100 ошибок Go» — книга не для новичков. Но обо всём по порядку.

⭐️ О чём книга

Как следует из названия, книга посвящена разбору 100 примеров ошибок и неэффективной работы в языке Golang. Глобально ошибки разбиты на смысловые разделы: организация кода, обработка ошибок, конкурентность и так далее.

Что можно узнать из книги:
➡️ Как грамотно использовать интерфейсы
➡️ Как выстрелить себе в ногу, перепутав длину и ёмкость среза
➡️ Чем всё-таки отличается конкурентность от параллелизма
➡️ Как создать race condition с помощью оператора append
➡️ И многое другое :)

⭐️ 3 идеи из книги

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

Называть пакеты в Go нужно ещё тщательнее, чем переменные. Именование пакета должно быть кратким, ёмким и отражать его возможности. Пакеты похожи на namespace из C#, и одновременно не являются ими. Знали бы вы, сколько мы времени на код-ревью тратим, придумывая нейминг пакетов…

Обработка ошибки должна быть выполнена ровно один раз. Знаю-знаю, всегда есть соблазн сделать что-то и передать ошибку дальше, но это не идиоматично. Если код обработал ошибку, то она не должна «лететь» дальше. Является ли дополнительное логирование обработкой — решайте самостоятельно :)

⭐️ Мои впечатления

Книга мне очень понравилась. Она далеко не такая простая и примитивная, как базовые руководства по Go, и посвящена разным хитрым нюансам языка. Некоторые ошибки довольно очевидны, если внимательно пройти A Tour of Go, но многие другие дали мне достаточно интересной пищи для размышлений.

Большой плюс книги — куча интерактивных примеров кода, которые можно запихнуть в Go Playground и поэкспериментировать (я провёл несколько весьма интересных экспериментов с конкурентностью). При этом код написан очень ясно, лаконично и снабжён комментариями, поэтому читать его легко и приятно.

Отдельный плюс — перевод книги. Он достаточно хорош: в процессе чтения я не спотыкался на словах и не ловил ступор. Технические книги в целом переводить непросто, и переводчики «100 ошибок Go» хорошо справились со своей задачей.

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

Приятного чтения!

#обзор_книги@tech_fit

📝 @tech_fit
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥921
Проблема long-tail запросов в распределённых системах

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

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

⭐️ Интересные идеи

➡️ Long-tail запросы могут ухудшать общие метрики системы и негативно влиять на пользовательский опыт. В больших системах это может быть очень дорого, а где-то и вообще недопустимо.

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

➡️ Стратегий борьбы много — выбирать нужно под себя. В частности, упоминаются кэширование, оптимизация обработки, асинхронная обработка, применение circuit breaker и другие.

Приятного чтения!

#highload@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍4🔥32
Техника хеджирования для борьбы с long-tail запросами

Проблеме long-tail запросов была посвящена предыдущая статья. В том числе, там были перечислены некоторые стандартные техники борьбы с такими запросами.

Google изобрёл ещё один интересный подход под названием “хеджирование запросов”. Суть его заключается в том, что клиент отправляет один и тот же запрос ко всем узлам и, получив первый ответ, отменяет все остальные запросы. Этому паттерну и посвящена сегодняшняя статья.

⭐️ Интересные идеи

➡️ Паттерн в первую очередь направлен на получение приемлемой latency. К примеру: у нас есть 20 нод, у каждой P99 составляет 1 секунду. С вероятностью 18,2% мы получим запрос длительностью >1 секунды. Хеджирование позволяет значительно снизить эту вероятность.

➡️ Хеджирование никак не связано с падением сервисов и не обрабатывает подобные ситуации.

➡️ За снижение вероятности попасть на long-tail запрос приходится платить многократным увеличением нагрузки. Поэтому к дизайну подобного решения нужно подходить особенно тщательно.

➡️ В Go есть готовый пакет singleflight, который позволяет избежать дублирования запросов. Остальным придётся мучиться самостоятельно :)

➡️ Альтернативное решение — изначально посылаем только один запрос. Если он вышел за предел P95, то сразу же посылаем ещё один запрос к другой ноде. Так мы получаем более сбалансированное решение: latency будет похуже, но и нагрузка будет гораздо ниже.

Приятного чтения!

#highload@tech_fit

// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥5👍42
Техника оптимизации Zero Copy в Kafka

Под высокой нагрузкой даже небольшие оптимизации могут дать заметный прирост производительности и удешевление инфраструктуры. Я помню, как коллеги по цеху за пару недель исследований снизили потребление CPU на 20% на сервисе с 10k RPS — представляете, сколько это в деньгах стоит?

Так вот, Kafka (изначально созданная для высоких нагрузок) под капотом использует много интересных оптимизаций. Одной из таких техник является Zero Copy — техника, направленная на уменьшение количества операций копирования (нет, там не всегда 0 копий).

⭐️ Интересные идеи

➡️ В случае Kafka Zero Copy выглядит так: ОС копирует данные из кэша страницы памяти напрямую в TCP socket buffer, полностью минуя программу на Java. Это позволяет убрать несколько лишних операций копирования и переключения контекста.

➡️ Kafka копирует данные с диска и посылает их по сети. При этом происходит несколько переключений контекста между приложением и ОС, а также множество операций копирования (от четырёх до бесконечности, в зависимости от объёма данных).

➡️ Поскольку Kafka хранит данные в том же формате, в котором и пересылает их, эти данные нет смысла копировать с диска в приложение, а из приложения — в TCP-буфер. Можно сделать загрузку файловых дескрипторов напрямую с диска в буфер сетевой карты (не TCP!), минуя приложение. Сетевая карта вычитывает данные по дескрипторам и отправляет их по сети.

➡️ Печальная правда: CPU редко является бутылочным горлышком Kafka, поэтому такая оптимизация не слишком влияет на общую производительность (перегруз сети случается гораздо чаще).

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍63🔥1
PostgreSQL Full-Text Search: быстрый, если делать правильно

Интересная статья о том, как разогнать full-text search в PostgreSQL. FTS в Постгресе традиционно считается не слишком быстрым на больших объёмах данных, из-за чего в инфраструктуру приходится тащить более сложные решения, заточенные под эту задачу.

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

⭐️ Интересные идеи

➡️ Первый фикс — сразу же преобразовать сообщение в тип tsvector и сохранить его в отдельной проиндексированной колонке. Затем по этой колонке можно легко осуществлять поиск. Это убирает лишние дорогие касты текста в tsvector и делает GIN-индекс более эффективным.

➡️ У GIN есть настройка fastupdate, которая по умолчанию включена. Она влияет на скорость обновления данных в индексе. Включённая настройка ускоряет обновление, но замедляет поиск. Если нагрузка идёт в основном на чтение, можно отключить fastupdate и получить прирост в скорости поиска.

➡️ Эти два изменения дали х50 прирост производительности FTS.

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍62🔥2
Почему Redis такой быстрый, несмотря на однопоточность?

Redis — очень быстрое in-memory KV-хранилище, которое может выдерживать довольно большие нагрузки. Но удивительнее всего тот факт, что он однопоточный.

Возникает вопрос: а как же однопоточное приложение так быстро работает и справляется с большой нагрузкой? На этот вопрос и отвечает сегодняшняя статья.

⭐️ Интересные идеи

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

➡️ Главная причина высокой скорости работы — простота. Redis работает с данными в оперативной памяти, у которой очень высокая скорость доступа. Также базовая структура данных Redis — хэш-таблица, которая даёт временную сложность доступа к информации O(1).

➡️ Для более сложных кейсов у Redis есть набор структур данных, специально оптимизированных под его внутренние операции и use cases пользователей.

➡️ Redis активно использует мультиплексирование как на своей стороне (I/O), так и на стороне клиента (мультиплексирование подключения). Это позволяет обслуживать множество клиентских потоков без необходимости создавать подключение для каждого из них. Но у этого подхода есть и минусы: у Redis есть блокирующие операции (BLPOP, BRPOP), а пересылка больших чанков данных может замедлить всю работу.

➡️ Redis разработан так, чтобы как можно меньше нагружать CPU. Он выполняет минимум вычислений, поэтому узким местом чаще всего становятся память или пропускная способность сети.

➡️ В Redis реализованы специальные многопоточные оптимизации. Например, очистку памяти выполняет отдельный фоновый процесс.

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
24🔥4👍2
Антипаттерн Retry Storm

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

⭐️ Интересные идеи

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

➡️ Делать бесконечные Retry нет смысла, потому что любой запрос валиден только в течение определённого времени. Поэтому всегда нужно ограничивать количество повторных попыток.

➡️ Делайте паузу между повторными попытками — не нужно бомбить страдающий сервис сразу же по тайм-ауту.

➡️ Для защиты от Retry Storm можно использовать gateway, который будет ограничивать нагрузку, отключать соединения при инциденте и даже может посылать в ответ заголовок Retry-After для упрощения коммуникации со стороны клиентов.

➡️ Клиенты должны грамотно обрабатывать полученные ошибки. Например, нет смысла повторно вызывать запрос, в ответ на который уже пришла ошибка 400 — это просто не имеет смысла.

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍31🔥1
Управление рисками. Практический подход

Не одной архитектурой живут сеньёры, техлиды и архитекторы. Одна из задач проектирования — управление рисками (а точнее, тем, чтобы они не сделали нам очень больно). При этом на работу с рисками традиционно все забивают. В лучшем случае — «мы записали этот риск, поехали».

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

⭐️ Интересные идеи

➡️ Первый шаг (на котором чаще всего всё и заканчивается) — собрать вообще все риски, которые видит команда. Для этого можно использовать брейншторм с последующим разгребанием всего нагенерированного.

➡️ Каждый найденный риск нужно оценить по вероятности возникновения и степени влияния на проект. Также важно понимать, на что конкретно и в какой степени повлияет реализация риска (это может быть скоуп проекта, качество продукта или ещё что-то).

➡️ Когда риски готовы и описаны — можно приступать к оценке. Для этого можно взять любую удобную шкалу (главное, чтобы она была одна для всех). На этом этапе каждый риск получает сводную оценку по всем параметрам. Теперь риски можно отсортировать.

➡️ В финале для каждого риска нужно определить стратегию работы и план действий (при необходимости).

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍4🔥211
Перестаньте называть базы CP или AP

Довольно разгромная статья в адрес применения CAP-теоремы к базам данных от Мартина Клеппманна (того самого, который написал книжку с кабанчиком). Стриггерился он на другую статью, которая призывает использовать CAP для критичных систем.

Посыл статьи в целом ясен из заголовка: базы данных не могут быть CA (consistent & available без partition tolerance). Детали — в статье. Рекомендую прочитать хотя бы первый раздел, где Клеппманн разматывает CAP-теорему — чистое удовольствие.

⭐️ Интересные идеи

➡️ Под консистентностью в CAP-теореме обычно подразумевается линеаризуемость, которую практически невозможно гарантировать (даже CPU не гарантирует линеаризуемый доступ к RAM — что уж говорить о больших системах).

➡️ CAP-теорема ничего не говорит о latency, которая для многих даже важнее, чем availability. И в целом её термины весьма относительны и мало что полезного сообщают.

➡️ Доступность в CAP-теореме и доступность в реальной жизни — это два очень разных понятия. В реальности мы обычно смотрим на доступность в рамках некоторого SLA, но с точки зрения CAP любой отказ делает систему недоступной.

➡️ В итоге получается, что многие системы с точки зрения CAP не являются ни C, ни A — они просто P. И это хорошие, надёжные системы. Просто нужно перестать прикладывать к ним неуместную классификацию.

➡️ Даже автор CAP-теоремы Эрик Брюер признаёт, что теорема вводит в заблуждение и чрезмерно упрощена.

➡️ Финальный совет Клеппманна: учитесь думать самостоятельно, вне рамок излишне узких теорем и аббревиатур.

Приятного чтения!

Ссылка на статью: https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
28👍3🔥31
Что делает программистов лучшими?

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

Автор пытается ответить на вопрос: что делает лучших программистов, которых он встречал, лучшими? В результате у него получился список принципов, применимых не только к программистам.

⭐️ Интересные идеи

➡️ Вместо гугления или «насилования» LLM, эти ребята идут в официальную документацию инструментария и читают её. Мало кто так делает сейчас :)

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

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

➡️ Они всегда учатся. Ни для кого не секрет, что в нашем мире приходится бежать очень быстро только ради того, чтобы оставаться на месте. Эти инженеры бегут.

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

➡️ Они не боятся говорить: «я не знаю». Умные люди осознают ограниченность своих знаний и понимают, что не знать чего-то вовсе не стыдно – наоборот, это возможность узнать что-то новое и обогатить себя.

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥73👍3
Заметки о распределённых системах для молодёжи

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

⭐️ Интересные идеи

➡️ В распределённых системах гораздо больше ошибок и сбоев. Сборка мусора может заставить master “исчезнуть”, медленное чтение с диска может подвесить всю систему, а заблокированный распределённый мьютекс может вызвать продолжительный сбой. Поэтому при проектировании нужно сразу закладывать отказы.

➡️ Координация – это очень сложно, её по возможности стоит избегать. Необходимость достижения консенсуса сильно усложняет систему. Почитайте про задачу двух генералов или про византийские сбои (или лучше сразу “Распределённые системы” Танненбаума).

➡️ “Тормоза” будут самой сложной проблемой, которую вам доведётся дебажить. Сам процесс обнаружения узкого места уже может стать нетривиальной задачей, потому что проблема может проявляться только в определённых условиях (которые ещё нужно нащупать).

➡️ Без метрик как без рук. Метрики – единственный способ посмотреть, как реально себя чувствует ваша система.

➡️ Перцентили более показательны, чем средние. Средние показатели обычно хороши, если у вас есть нормальное распределение (график-колокол), а в распределённых системах такой роскоши обычно нет.

📎Ссылка на статью

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍7🔥322
Секреты стройности монолита: подходы по снятию нагрузки с БД

Одна из причин, почему команды начинают переходить на микросервисы — основная БД захлёбывается под нагрузкой. Масштабировать stateless-сервисы просто, с базой же это делать гораздо сложнее.

В очередной интересной статье инженеры Яндекса разбирают, как можно снизить нагрузку на БД, которая и так уже работает на ~100K RPS, и как её аккуратно распилить на части.

⭐️ Интересные идеи

➡️ Первое, с чего стоит начать — тщательный анализ долгих запросов. Инженеры Яндекса написали для этого свой парсер логов. Это позволило выявить плохо написанные запросы и быстро их поправить, получив буст к производительности.

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

➡️ Интересен также процесс выбора таких таблиц: они должны быть достаточно нагруженными, не слишком сильно связаны с другими таблицами и к ним не должно быть слишком специфичных запросов (попутно ещё и с MySQL на PostgreSQL переезжали).

➡️ Эксперимент пришлось несколько раз откатывать из-за особенностей инфраструктуры. В первом релизе не хватило воркеров, потому что их количество в Яндекс Облаке фиксировано для выбранного флейвора, и двойная запись быстро их исчерпала. Во втором случае master переехал в другой ДЦ, и система несколько минут пыталась писать в slave — с печальными последствиями.

➡️ Была проделана большая работа по очистке базы (потому что исходный вес был 4 ТБ): анализ и удаление исторических данных, анализ неиспользуемых таблиц, даже лишние индексы почистили. В итоге удалось значительно сократить объём занимаемого на диске пространства.

➡️ Финальный аккорд — после выяснения требований оказалось, что не нужно хранить в основной БД данные о заказах старше одного месяца, потому что они используются в основном для аналитики и выборочных проверок. Это позволило уменьшить размер БД до целевого значения в 750 ГБ.

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍52🔥2
Как Slack переделал архитектуру настроек рабочих пространств на EAV-модель

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

Одной из таких проблем оказались настройки. Их было 165 штук, и хранились они в виде JSON blob’а, достигая размера в 55 КБ. Боль была в том, что доступ к этим данным осуществлялся очень часто. Кэширование помогало, но из-за размеров blob’ов кэш тоже страдал.

⭐️ Интересные идеи

➡️ Была выбрана модель EAV (Entity/Attribute/Value), потому что нужно было поддержать неограниченный рост числа настроек. В обычную таблицу пришлось бы постоянно добавлять новые колонки.

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

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

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

Приятного чтения!


// Понравился пост? Ставь 💛
// И обязательно подпишись на канал, чтобы не пропустить новые статьи
Please open Telegram to view this post
VIEW IN TELEGRAM
2🔥7👍42