6.6 KiB
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 в случае, если идут метаданные. В остальных случаях отсылаются данные, как и прежде.
Применик перед запросом смотрит, будет ли хранить данные в S3. Проверка сейчас кривая - если в сторадже есть S3, то считаем, что будет S3. Если да S3, то отсылает в запросе send_s3_metadata=1.
Источник при получении такого запроса смотрит, лежит ли парт на S3. Если да, то в Зукипере ставит метку по пути <путь к данным таблицы>/zero_copy_s3/shared/<некий ID парта>/<ID реплики>
,
ставит в ответ куку send_s3_metadata=1 и вместо файлов с данными отсылает только файлы метаданных.
Приемник при получении ответа с send_s3_metadata=1 создает только файлики с идентичными меаданными, которые в итоге будут ссылаться на те же ключи в S3, ставит в зукипере аналогичную метку, только со своим ID реплики, и работает с этим. Для первого фалйа из списка проверяет наличие первого ы3-объекта (просто наличие), если объект с таким именем найден, то все ок, если нет, то откат на старую версию. (Сейчас есть еще код на случай наличия более одного диска S3, тогда перебирает все и если на каком-то файл найден, то использует его, но мы внутри команды MDB смотрим на такую конфигурацию как на странную. Планируем ограничить функционал только случаем одного S3 диска.)
При желании удалить парт нода удаляет в Зукипере ключ <путь к данным таблицы>/zero_copy_s3/shared/<некий ID парта>/<ID реплики>
, потом получает все подключи <путь к данным таблицы>/zero_copy_s3/shared/<некий ID парта>
.
Если список не пустой, то считает, что данные использует другая нода и удаляет только локальные метаданные, если пустой, то удаляет и данные в S3.
При мерже если реузльтат будет на S3, нода ставит эфемерную метку в Zookeeper по пути <путь к данным таблицы>/zero_copy_s3/merged/<имя нового парта>
. Если такая метка уже есть, то считает, что другая нода
уже помержила или мержит сейчас, и надо сделать fetch вместо мержа самой.
Костыли и недоработки, коих много
-
В качестве ID парта берется имя первого S3-ключа от файла checksums.txt.
-
Не нашел удобного способа прокидывать в коде зукипер, прокинул хадркодом.
-
При удалении класс диска ничего не знает про парты, прокинул флаг, что надо оставлять данные в S3 параметром, это очень криво получилось.
-
Возможна гонка, если источник отошлет метаданные про парт и тут же решит его удалить до того, как приемник поставит в зукипер пометку.
-
В протоколе репликации обмен инфой через параметр запрос в одну сторону и куку в другую мне не нравится, хотя так сделан обмен версиями репликации.
-
При ошибке должно пытаться реплицироваться по старому, но не уверен, всегда ли сработает
-
Не будет обратной совместимости, если образуются такие шареные парты, откатиться на старую версию кликхауса не получится, иначе нода может удалить используемые другой данные.
-
Возможны все же дублирования партов. Пример - нода делает мерж, падает. Другая нода незавимо делает мерж, первая нода поднимается. В итоге есть две копии померженого парта.
-
... много их. Честно.
TODO, чего еще вообще не делалось
-
Флаг в конфиге для включения функционала, по умолчанию будет выключен.
-
Для гибридного хранилища сделать проверку и fetch при переезде парта с локального диска в S3.
-
Тесты.