Сжатие журналов

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

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

Рассмотрим конкретный пример. Имеется топик, содержащий адреса электронной почты пользователей. Каждый раз, когда пользователь обновляет адрес своей электронной почты, в топик отправляется сообщение с использованием идентификатора пользователя в качестве первичного ключа. Теперь допустим, что за определенный период времени отправляются следующие сообщения для пользователя с id 123, каждое сообщение соответствует изменению адреса электронной почты (сообщения для других идентификаторов опущены):

1  123 => bill@microsoft.com
2          .
3          .
4          .
5  123 => bill@gatesfoundation.org
6          .
7          .
8          .
9  123 => bill@gmail.com

Сжатие журнала дает более гранулированный механизм хранения, поэтому ADS гарантирует сохранение по крайней мере последнего обновления для каждого первичного ключа (например, bill@gmail.com). Так же гарантируется, что журнал содержит полный снапшот конечного значения для каждого ключа, а не только недавно измененные. Это означает, что нижестоящие потребители могут восстановить свое собственное состояние с этого топика без необходимости ведения полного журнала всех изменений.

Далее приведены несколько вариантов использования:

  1. Подписка на изменение базы данных. Часто необходимо иметь набор данных в нескольких системах, и при этом одна из этих систем представляет собой некоторую базу данных (либо РСУБД, либо, возможно, новомодное хранилище ключ-значение). Например, может быть база данных, кэш, кластер поиска и кластер Hadoop. Каждое изменение БД должно отражаться в кэше, кластере поиска и, в конечном итоге, в Hadoop. В случае если идет обработка обновлений только в реальном времени, то нужен последний актуальный журнал. Но в случае необходимости перезагрузки кэша или восстановления отказавшего узла поиска, может понадобиться полный набор данных.
  2. Поиск событий. Это стиль разработки приложений, который совмещает обработку запросов с дизайном приложения и использует журнал изменений в качестве основного хранилища для приложения.
  3. Ведение журнала для обеспечения высокой работоспособности. Процесс, выполняющий локальные вычисления, можно сделать отказоустойчивым, фиксируя вносимые в локальном состоянии изменения, с целью, чтобы другой процесс мог перезагрузить эти изменения и продолжить работу в случае сбоя первого. Конкретным примером является обработка счетчиков, агрегатов и других операций типа “group by” в потоковой системе запросов. Samza, платформа потоковой обработки данных в реальном времени, использует эту функцию именно для данной цели.

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

Общая идея довольно проста. Имея бесконечную сохраняемость журнала, каждое изменение в вышеуказанных случаях регестрировалось бы в него, и тогда состояние системы фиксировалось бы каждый раз с момента ее первого запуска. Используя этот полный журнал, была бы возможность восстановить систему в любой момент времени, воспроизведя первые N записей журнала. Но этот гипотетический полный журнал не очень практичен для систем, многократно обновляющих одну запись, поскольку журнал имел бы безграничный рост даже для стабильного набора данных. Простой же механизм ведения журнала, отбрасывающий устаревшие обновления, ограничен в пространстве, но и не является способом восстановления текущего состояния – восстановление системы с момента запуска не осуществляется посредством журнала, поскольку старые обновления могут быть не зафиксированы.

Сжатие журнала – это механизм, обеспечивающий гранулированное хранение каждой записи, а не крупнозернистое хранение во времени. Идея заключается в выборочном удалении записей, имеющих более новое обновление с тем же самым первичным ключом. Таким образом, журнал гарантированно имеет по крайней мере последнее состояние для каждого ключа.

Такая политика хранения может быть настроена для каждого топика, поэтому один кластер может иметь несколько топиков, где сохранение осуществляется по заданному объему данных или по времени ожидания, и другие топики, где сохранение обеспечивает сжатие.

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

Основы сжатия журналов

Далее приведен рисунок, отображающий логическую структуру ведения журнала ADS со смещением для каждого сообщения (Рис.151.).

../_images/ADS_Architect_Log-structure.png

Рис. 151. Логическая структура журнала ADS

Журнал ADS идентичен традиционному журналу. В нем плотно фиксируются последовательные смещения и сохраняются все данные. Сжатие журнала добавляет опцию для обработки его хвоста (на Рис.151. показан журнал с уплотненным хвостом). Важно обратить внимание, что данные в хвосте журнала сохраняют исходное смещение, назначенное при первой записи, которое никогда не изменяется. Также важно, что все смещения остаются действующими позициями в журнале, даже если сообщение с этим смещением сжато; в таком случае позиция неотличима от следующего наибольшего смещения, которое появляется в журнале. Например, на Рис.151. смещения 36, 37 и 38 являются эквивалентными позициями, и начало чтения в любом из этих смещений выдает набор данных, начинающийся с 38.

Сжатие также может удалять данные. Сообщение с ключом и нулевой полезной нагрузкой рассматривается на удаление из журнала и маркируется. Это приводит к удалению любых предыдущих сообщений с таким ключом (как и любые новые данные с таким же ключом), при этом маркированные на удаление данные являются особенными, поскольку они сами будут удалены из журнала через некоторое время. Момент времени, в который такие данные больше не сохраняются, на приведенном выше рисунке помечен как “Delete Retention Point”.

Сжатие выполняется в фоновом режиме с периодическим копированием сегментов журнала. Очистка не блокирует операции чтения и может регулироваться на настроенный объем пропускной способности ввода-вывода данных во избежание влияния на поставщиков и потребителей. Процесс сжатия сегмента журнала выглядит примерно как показано на Рис.152.

../_images/ADS_Architect_Log-compaction.png

Рис. 152. Процесс сжатия сегмента журнала

Обеспечиваемые гарантии

Сжатие журнала обеспечивает следующие гарантии:

  1. Любой потребитель, находящийся в голове журнала, видит каждое записанное сообщение; эти сообщения имеют последовательные смещения. Параметр топика min.compaction.lag.ms используется для гарантии минимального промежутка времени, затрачиваемого после записи сообщения прежде, чем оно будет сжато. То есть обеспечивается нижняя граница того, как долго каждое сообщение остается в неуплотненной голове журнала.
  2. Всегда поддерживается упорядоченность данных. Сжатие никогда не нарушает порядок сообщений, а просто удаляет их.
  3. Смещение для сообщения никогда не изменяется. Это постоянный идентификатор позиции в журнале.
  4. Любому идущему от начала журнала потребителю видны, по крайней мере, окончательные состояния всех данных в порядке их записи. Кроме того, видны все маркированные под удаление данные при условии, что потребитель достигает головы журнала в течение меньшего периода времени, чем установлено в топике в параметре delete.retention.ms (по умолчанию 24 часа). Другими словами, поскольку удаление маркированных данных происходит одновременно с операцией чтения, потребитель может пропустить эти данные при отставании более, чем на установленное в параметре delete.retention.ms время.

Детали сжатия журнала

Сжатие журнала выполняется посредством очистки log cleaner – объединением фоновых потоков, которые перезаписывают файлы сегментов журнала, и удалением данных, ключ которых отображается в голове журнала. Средство очистки работает следующим образом:

  1. Выбирает журнал с самым высоким отношением между головой и хвостом.
  2. Создает краткую сводку последнего смещения для каждого ключа в голове журнала.
  3. Перезаписывает журнал от начала до конца, удаляя ключи, которые имеют более позднее появление в журнале. Новые, чистые сегменты немедленно подставляются в журнал, поэтому дополнительное пространство на диске требуется всего лишь для одного дополнительного сегмента журнала (а не для полной копии журнала).
  4. Суммарно, голова журнала – это просто компактная хэш-таблица, использующая 24 байта на запись. В результате с 8 ГБ пространства под очистку одна итерация log cleaner может освободить около 366 ГБ головы журнала (принимая данные равными 1 Кб).