ClickHouse/S3ZeroCopyReplication.md
2021-02-05 18:52:40 +03:00

7.4 KiB
Raw Blame History

ClickHouse S3 Zero Copy Replication

Код просто для теста, не production-ready ни разу.

Ветка

Как сделано

При fetch-е парта при репликации в случае, если источник хранит, а приемник собирается хранить парт в S3, вместо данных пересылаются только метаданные S3, приемник кладет их локально себе и испольузет общие с источником данные на S3. Для того, чтобы не удалить такие пошареные данные, делается пометка в ZooKeeper.

Введена новая версия протокола REPLICATION_PROTOCOL_VERSION_WITH_PARTS_S3_COPY. В запросе новый параметр send_s3_metadata, если 1, то приемних просит у источника метаданные вместо данных, если это возможно. Приемник в ответ отсылает куку send_s3_metadata=1 в случае, если идут метаданные. В остальных случаях отсылаются данные, как и прежде.

В новой версии протокола перед полем с количеством файлов добавлена еще одна строка. Абстрактно это некий ID, по которому ноды могу понять, с одним S3 они работают или с разными. Практически сейчас это один имя первого объекта файла checksums.txt. Эта же строка используется в качестве ID парта в зукипере.

Применик перед запросом смотрит, будет ли хранить данные в S3. Проверка сейчас кривая - если в сторадже есть S3, то считаем, что будет S3. Если да S3, то отсылает в запросе send_s3_metadata=1.

Источник при получении такого запроса смотрит, лежит ли парт на S3. Если да, то в Зукипере ставит метку по пути <путь к данным таблицы>/zero_copy_s3/shared/<имя парта>/<ID парта>/<Путь парта>/<ID реплики>, ставит в ответ куку send_s3_metadata=1 и вместо файлов с данными отсылает только файлы метаданных.

Путь получился сложным, потому что требуется

  • по имени парта получить, на каких репликах он уже есть на S3 (нужно для гибридного хранилища)
  • по уникальному пути понимать, используелся ли эта копия парта другими репликами
  • для павильного времени жизни лока различать лок основного варианта (all_0_0_0) от временного (tmp_fetch_all_0_0_0)

Приемник при получении ответа с send_s3_metadata=1 проверяет доступность по переданному ключу (первый объект checksums.txt) создает только файлики с идентичными меаданными, которые в итоге будут ссылаться на те же ключи в S3, ставит в зукипере аналогичную метку, только со своим ID реплики, и работает с этим.

При желании удалить парт нода удаляет в Зукипере ключ <путь к данным таблицы>/zero_copy_s3/shared/<ID парта>/<ID реплики>, потом получает все подключи <путь к данным таблицы>/zero_copy_s3/shared/<ID парта>. Если список не пустой, то считает, что данные использует другая нода и удаляет только локальные метаданные, если пустой, то удаляет и данные в S3.

При мерже если реузльтат будет на S3, нода ставит эфемерную метку в Zookeeper по пути <путь к данным таблицы>/zero_copy_s3/merged/<имя нового парта> (!! НЕ <ID парта> !!). Если такая метка уже есть, то считает, что другая нода уже помержила или мержит сейчас, и надо сделать fetch вместо мержа самой.

В гибридном хранилище если парт переносится на S3, нода через ZK проверяет, нет был ли парт перенесен другой нодой, если был, то делает fetch (модифицированный по сравнению с обычным fetch'ем).

В конфиг добавлен флаг, по которому включается функционал нового протокола репликации - merge_tree->allow_s3_zero_copy_replication. Сейчас стоит в false.

Костыли и недоработки, коих много

  • В качестве ID парта берется имя первого S3-ключа от файла checksums.txt.

  • При удалении класс диска ничего не знает про парты, прокинул флаг, что надо оставлять данные в S3 параметром, это очень криво получилось.

  • Возможна гонка, если источник отошлет метаданные про парт и тут же решит его удалить до того, как приемник поставит в зукипер пометку.

  • В протоколе репликации обмен инфой через параметр запрос в одну сторону и куку в другую мне не нравится, хотя так сделан обмен версиями репликации.

  • При ошибке должно пытаться реплицироваться по старому, но не уверен, всегда ли сработает

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

  • Возможны все же дублирования партов. Пример - нода делает мерж, падает. Другая нода незавимо делает мерж, первая нода поднимается. В итоге есть две копии померженого парта.

  • Тесты пока только самые базовые.

  • Для гибридного хранилища если две ноды решают одновременно перенести парт на S3, обе проверяют, что его там еще нет и обе переносят.