refactor(smoke): ограничен по времени опрос keeper, уточнены формулировки

- Зачем:
  - горячее ревью: перевезённая проверка keeper потеряла привычку файла
    ограничивать обращения к контейнерам по времени и глушить их ошибки.
- Что:
  - опрос keeper идёт через keeper_exec с timeout 20s и тихим stderr,
    в отчёте об отказе пустой ответ назван словами.
  - комментарий к проверке и абзац README переписаны на проверяемое
    утверждение: настройки объявлены в compose.yaml, смоук спрашивает,
    дошли ли они до процесса.
  - в пробнике ClickHouse ожидаемой строке возвращено имя expected_rows.
- Проверка:
  - make config-test, make smoke, make smoke-cluster; отдельно проверено,
    что на паузе keeper проверка краснеет, а не виснет.
This commit is contained in:
2026-08-06 14:01:45 +03:00
parent 66490d124e
commit a2f5b27d89
3 changed files with 29 additions and 22 deletions
+10 -9
View File
@@ -64,8 +64,8 @@ Superset, создаёт администратора и импортирует
`make smoke` проверяет зависимости машины, здоровье контейнеров, устройство
keeper, Kafka через порт машины, три цели Prometheus, источник Grafana,
компоненты Airflow, ручной запуск пробников `test_clickhouse`
и `test_kafka`, метаданные и подключение Superset. Первый пробник создаёт
компоненты Airflow, ручной запуск пробников `test_clickhouse` и `test_kafka`,
метаданные и подключение Superset. Первый пробник создаёт
таблицы на обеих нодах и читает через `Distributed` на ноде 2 строку из
локальной таблицы ноды 1. Второй пишет в Kafka и читает свой маркер. В конце
проверка спрашивает у Docker, не убивало ли ядро что-нибудь в долгоживущих
@@ -74,13 +74,14 @@ keeper, Kafka через порт машины, три цели Prometheus, ис
Временный топик проверки с машины и запуски DAG удаляются;
постоянный топик пробника сохраняется, а старые записи чистит Kafka.
Про здоровье контейнеров честно будет сказать так: сразу после `make up --wait`
эти одиннадцать проверок повторяют то, чего Compose уже дождался, — у каждой
долгоживущей службы есть своя `healthcheck`. Оставлены они потому, что первый
вопрос к стенду всё равно «всё ли живо», и ответ на него стоит меньше секунды.
Устройство keeper — другое дело: он работает от пользователя `clickhouse`, с
пределом в 262144 открытых файла и своим каталогом координации. Здоровым он
выглядит и без этого, а грабли тут настоящие.
Одиннадцать проверок здоровья сразу после `make up --wait` повторяют то, чего
Compose уже дождался: у каждой долгоживущей службы есть своя `healthcheck`.
Оставлены они потому, что первый вопрос к стенду всё равно «всё ли живо», а
ответ на него стоит меньше секунды. Устройство keeper — другое дело: он должен
работать от пользователя `clickhouse`, с пределом в 262144 открытых файла и со
своим томом под данные. Всё это объявлено в `compose.yaml`, но здоровым keeper
выглядит и без этого, поэтому смоук спрашивает у живого контейнера, дошли ли
объявленные настройки до процесса.
`make smoke-cluster` запускает отдельную глубокую проверку ClickHouse: описание
кластера, макросы, связь с keeper, `ReplicatedMergeTree`, `Distributed`, очередь
+4 -3
View File
@@ -83,8 +83,8 @@ def _drop_tables(client) -> None:
)
# Единственная проверка, вынесенная из задач: её делают обе, до создания таблиц
# и после уборки.
# Отсутствие таблиц проверяют обе задачи — перед созданием и после уборки,
# поэтому у этой проверки своё имя, а остальные живут прямо в теле задач.
def _assert_tables_absent(client) -> None:
for node_name, source in NODES:
remaining = _table_engines(client, source)
@@ -197,7 +197,8 @@ def test_clickhouse():
raise RuntimeError(
"запись и чтение маркера должны выполняться с разных нод"
)
if distributed_rows != [(1, written["hostname"], written["marker"])]:
expected_rows = [(1, written["hostname"], written["marker"])]
if distributed_rows != expected_rows:
raise RuntimeError(
"нода 2 не прочитала маркер первого шарда через Distributed: "
f"{written['marker']}, получено {distributed_rows}"
+15 -10
View File
@@ -74,26 +74,31 @@ check_container_health() {
fi
}
# Keeper — единственная служба, которой мало быть здоровой: она пишет журнал
# координации, и если запустить её от root или с чужим каталогом данных, файлы
# останутся с неверным владельцем и следующий запуск их не откроет. Предел на
# открытые файлы у неё свой: соединений много, и стандартной тысячи не хватает.
keeper_exec() {
timeout 20s "${COMPOSE_CMD[@]}" --project-directory "$ROOT_DIR" \
exec -T clickhouse-keeper "$@" 2>/dev/null
}
# Три настройки keeper объявлены в compose.yaml: свой пользователь, свой предел
# на открытые файлы и свой том под /var/lib/clickhouse. Проверка спрашивает у
# живого контейнера, дошли ли они до процесса — здоровым keeper выглядит и без
# них, а каталог координации, однажды созданный от чужого пользователя,
# следующий запуск уже не откроет.
check_keeper_runtime() {
local keeper_user
local keeper_nofile
local keeper_owner
local keeper_user
keeper_user="$(compose exec -T clickhouse-keeper id -un)"
keeper_nofile="$(compose exec -T clickhouse-keeper \
keeper_user="$(keeper_exec id -un)"
keeper_nofile="$(keeper_exec \
awk '$1 == "Max" && $2 == "open" && $3 == "files" {print $4}' /proc/1/limits)"
keeper_owner="$(compose exec -T clickhouse-keeper \
stat -c '%U:%G' /var/lib/clickhouse/coordination)"
keeper_owner="$(keeper_exec stat -c '%U:%G' /var/lib/clickhouse/coordination)"
if [[ "$keeper_user" == 'clickhouse' ]] && \
[[ "$keeper_nofile" -ge 262144 ]] && \
[[ "$keeper_owner" == 'clickhouse:clickhouse' ]]; then
pass 'keeper работает от clickhouse с nofile 262144 и своим каталогом данных'
else
fail "неверное окружение keeper: пользователь=${keeper_user}, nofile=${keeper_nofile}, владелец каталога=${keeper_owner}"
fail "неверное окружение keeper: пользователь=${keeper_user:-нет ответа}, nofile=${keeper_nofile:-нет ответа}, владелец каталога=${keeper_owner:-нет ответа}"
fi
}