Давайте начнем с небольшой предыстории. У нас в компании на обслуживании стоит проект, который до недавнего времени находился в стадии тестирования/разработки. На тот момент в нём использовался ClickHouse с 3 шардами по 2 реплики в каждом. Учитывая то, что инфраструктура этого проекта была тестовой и не требовала никакой дополнительной авторизации (ClickHouse был в закрытом сегменте), никто этим вопросом не задавался.
Со временем проект вырос, ClickHouse стал production базой и нами была произведена миграция данных со старой инфраструктуры в новую с 1 шардом, 3 репликами на 3-х разных серверах (ClickHouse размещён в Kubernetes на базе StatefulSets) и, конечно, с авторизацией.
Вот что было дальше.
Почти сразу после запуска проекта в production мы обнаружили, что в datadir ClickHouse пользовательской базы данных, в не шардированных таблицах (в нашем случае это те, что размещены локально на каждой ноде, без постфикса sharded, имеющие тип Distributed), было большое количество не проигранных bin-логов. Дата логов предшествовала дате установки на ClickHouse авторизации.
Ниже приведён вывод с консоли для одной из реплик ClickHouse таблицы table_1 базы данных test:
ls -l /var/lib/clickhouse/data/test/table_1/test_usr@clickhouse%2D0%2Eclickhouse%2Eclickhouse%2Dprod%2Esvc%2Ecluster%2Elocal\:9000 | tail -n 10
-rw-r----- 1 clickhouse clickhouse 1472 Jul 8 08:26 9983.bin
-rw-r----- 1 clickhouse clickhouse 1453 Jul 8 08:26 9985.bin
-rw-r----- 1 clickhouse clickhouse 1383 Jul 8 08:26 9987.bin
-rw-r----- 1 clickhouse clickhouse 1461 Jul 8 08:27 9989.bin
-rw-r----- 1 clickhouse clickhouse 1458 Jul 8 08:28 9991.bin
-rw-r----- 1 clickhouse clickhouse 1468 Jul 8 08:29 9993.bin
-rw-r----- 1 clickhouse clickhouse 1413 Jul 8 08:29 9995.bin
-rw-r----- 1 clickhouse clickhouse 1509 Jul 8 08:32 9997.bin
-rw-r----- 1 clickhouse clickhouse 1504 Jul 8 08:32 9999.bin
drwxr-x--- 2 clickhouse clickhouse 4096 Sep 16 12:59 tmp
Т.е. сами данные были помещены в локальную Distributed таблицу конкретной реплики, но по неизвестной на тот момент причине не были перемещены в таблицу с постфикcом sharded (типа ReplicatedMergeTree), которая как раз доступна со всех реплик кластера, путем обращения к ней через локальную таблицу (без постфикса sharded).
Как оказалось после проведенного анализа, те данные, которые были записаны в базу ClickHouse ещё на старой инфраструктуре, т.е. до включения авторизации, уже не могли быть распределены между репликами на новой инфраструктуре, т.к. на новых серверах ClickHouse авторизация уже была включена.
Почему так. Когда происходит запись данных в ClickHouse без авторизации, в datadir каталоге ClickHouse в соответствующих каталогах базы данных и таблице формируется ссылка следующего вида (ссылка формируется исходя из запроса, сделанного к базе данных):
test_usr@clickhouse%2D0%2Eclickhouse%2Eclickhouse%2Dprod%2Esvc%2Ecluster%2Elocal\:9000
Давайте посмотрим на неё более детально. В ссылке выше производится обращение под пользователем test_usr, но пароля для авторизации не указано. И что получается, если до включения авторизации в базе данных, в ClickHouse был записан очень большой объем данных, что сформировало bin-логи, а ClickHouse на старых серверах не успел их проиграть, то после включения авторизации на новых серверах ClickHouse и миграции старых не проигранных bin-логов в новые сервера, эти bin-логи уже не могут быть проиграны, т.к. ссылка уже сформирована без авторизации для пользователя test_usr.
Все новые поступающие данные в ClickHouse, также будут формировать bin-логи в соответствующих каталогах базы данных и таблицах, которые потом будут проиграны, но уже с другой ссылкой, где авторизация указана (т.к. обращение к ClickHouse на новой инфраструктуре со стороны приложения уже производится с указанием пароля для пользователя test_usr, иначе в базу запрос просто не дойдет):
test_usr:password@clickhouse%2D0%2Eclickhouse%2Eclickhouse%2Dprod%2Esvc%2Ecluster%2Elocal\:9000
Т.к. данные в базу записываются асинхронно, то есть они сперва помещаются на одну какую-то локальную реплику ClickHouse, к которой было произведено обращение, а только потом отправляются на другие реплики кластера.
Следовательно, старые данные, которые были записаны на одну из локальных реплик ClickHouse, но не были распределены между остальными репликами кластера (т.к. сформированная ссылка не содержала пароль к пользователю, а он уже был задан), то к ним нельзя было обратиться даже на чтение к той реплике, на которой непосредственно находились непримененные bin-логи.
Как мы решили задачу и не потеряли нераспределенные данные?
Всё оказалось довольно просто. Достаточно произвести следующие манипуляции с нераспределенными данными в базе данных:
- Сформированные ссылки для каждой из таблиц проблемной БД привести (переименовать) к требуемому виду:
mv /var/lib/clickhouse/data/test/table_1/test_usr@clickhouse%2D0%2Eclickhouse%2Eclickhouse%2Dprod%2Esvc%2Ecluster%2Elocal\:9000 /var/lib/clickhouse/data/test/table_1/test_usr:password@clickhouse%2D0%2Eclickhouse%2Eclickhouse%2Dprod%2Esvc%2Ecluster%2Elocal\:9000
- Произвести перезапуск реплик ClickHouse, что инициирует процесс проигрывания bin-логов и размещения их в наших sharded таблицах (ReplicatedMergeTree).
P.S: Рекомендую всем проверить работу своих серверов ClickHouse на наличие описанных проблем. Если такие будут найдены, то эта заметка поможет вам сэкономить время на поиск решения и быть внимательнее при установке/смены пароля на ClickHouse в будущем.
Также читайте другие статьи в нашем блоге:
- Blue-Green Deployment приложений на Spring c веб-сервером Nginx
- Как запустить несколько пайплайнов с помощью GitLab CI/CD
- /etc/resolv.conf для Kubernetes pods, опция ndots:5, как это может негативно сказаться на производительности приложения
- Разбираемся с пакетом Context в Golang
- Три простых приема для уменьшения Docker-образов