четверг, 13 января 2022 г.

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

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

Подсистемы хранения и извлечение данных

БД rocks db (основа для spark streaming, kafka) - Используют lsm дерево для быстрой вставки

Варианты реализации вторичных btree индексов:
Напрямую на файл (Oracle):
+ нет лишних обращений к первичному ключу при чтений
- оба индекса должны меняться при изменении данных таблице
На первичный индекс (MsSql):
+ не надо перестраивать вторичный индекс, при изменений данных в таблице
- лишние чтения при select

Кодирование данных

бинарные форматы кодирования данных с сохранением типов:

Thrift BinaryProtocol

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

Thrift CompactProtocol и Protocol Buffers

+ в схему (тег поля) включается тип данных
+ числа кодируются переменной длиной:
* 64 - кодируется 1 байтом
* 1025 - уже 2 байтамами
старший бит каждого байта указывает есть ли еще продолжение числа
+ required/optional провереяется по схеме и не хранится в самих данных
- размер (длина) хранятся в самом сообщений

-> Такое кодирование обеспечивает прямую совместимость: добавление новых полей (старый код просто будет их игнорировать)
Так же есть и обратная совместимость: новый код сможет читать неполное старое сообщение (но новые поля не могут быть обязательными без значения по умолчанию)
Можно удалять колонки, но номер тега должен остаться старый (не смещаться для совместимости)
Изменение типа данных: только в сторону уменьшения

Avro

состоит из json схемы и закодированных данных
+ нет тегов: только длинна записи
+ числа также кодируются переменной длиной
- для чтения avro файла нужна схема с которой он записывался

Эволюция схемы:
* изменение порядка: приложение ищет одинаковые названия полей в совместимых схемах
* обратная совместимость обеспечивается через значения поумолчанию и union нескольких типов: int + null

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

Отличие Avro от Thrift CompactProtocol и Protocol Buffers

+ нет тегов: прямое соостветствие схемы файла avro схеме бд по имени столбца.
в случае pb/tc нужно держать дополнительный вручную созданный маппинг: поле бд - тег файла

ORC

Сохранение метаданных осуществляется в бинарном формате сериализации Protocol Buffers

Репликация


проблемы асинхронной синхронизации в OLTP приложении
* запись идет с мастера
* чтение с реплики: пользователь может не увидеть свои изменения
по этому: чтение своих изменений (домашняя страница к примеру), всегда идет с матера, а чтение других данных с реплик с задержкой
так же можно хранить таймер последнего изменения и читать с мастера, пока не пройдет лаг до реплики
* разные реплики опаздывают по разному: пользователь должен привязыватья к конкретной реплике
* в случае нескольких мастеров: запись конкретного объекта должна идти всегда через один мастер, чтобы не получить конфликт изменений с разных нод
либо держать общий ID для всех мастеров, и запись с болшим ID будет перетирать с меньшим

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

ребалансировка шардов нод:
* плохой подход: секция = ключ % число нод
т.к. при изменение числа нод, почти все ключи переедут на новое место
* хорошее решение: число секций в разы больше числа нод (В 1 ноде много секций), тогда добавление новой ноды выведет по 1 секции из каждой старой ноды в новую
и число секций не меняется одмоментно при добавлении ноды. Существующие секции переезжают постепенно 1 за 1

Большинство БД для маршрутизации секция - нода используется zookeper (в нем же регистрируются изменения)
* zookeper так же хранит монотонный счетчик блокировок и выдает их при изменении ключа
Cassandra же обменивается топологией между всеми нодами, по этому коннектится можно к любой, любая из них перенаправит на нужную

Проблемы распределенных систем

максимальное время ожидания данных через сеть: 2d + r
d - среднее время обработки
r - максимальное время по SLA

Протоколы:
UDP - протокол без подтверждения и повтороной отправки: подходит для потоковых данных (потоковое аудио к примеру)
NTP - необходимо очень точно синхронзировать время в распределенных системах (каждые 30 секунд, не более 2мс расхождение)
со временем много нюансов:
* оно может ходить резко перемещаться во время синхронизации
* могут пропадать конечные секунды в минуте

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

так же нужно быть готовым к падению узла или долгой его ответу изза gc пауз (к примеру)

Согласованность и консенсус

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

CAP

- либо последовательность (консистентность), либо доступность при нарушении связности сети
(считается что нарушение связи всегда настанет, по этому этот пункт всегда выбран и остается выбрать 1)
p - схемы: кольцо (разделение если 2 узла из строя), звезда (если вышел из строя центр), все со всеми (дорого по сети)
c - консистентность при разделении сети доступна только, если данные в рамках 1 сервера
a - доступность (двухфазный коммит, репликация), при разделении сети не будет консистентности

Двухфазный коммит

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

Потоковые данные

очереди сообщений схожи с бд, но хранят набор данных временно и не могут их обновлять
push модель шины данных:
+ очередь извещает потребителей о новых данных (потребители сами не запрашивают данные), по этому снижается число обращений, нагрузка на источник, улучшается скорость доставки
- в случае ошибки отправки одному из потребителей сообщение отправляется повторно, это может задублить данные у хорошего потребителя
+ подтверждение о доставке (возможен даже 2PC)
pull модель:
+ kafka - очередь может читать неограниченное число потребителей
+ данные не удаляются после их прочтения

Комментариев нет:

Отправить комментарий