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:
@@ -64,8 +64,8 @@ Superset, создаёт администратора и импортирует
|
|||||||
|
|
||||||
`make smoke` проверяет зависимости машины, здоровье контейнеров, устройство
|
`make smoke` проверяет зависимости машины, здоровье контейнеров, устройство
|
||||||
keeper, Kafka через порт машины, три цели Prometheus, источник Grafana,
|
keeper, Kafka через порт машины, три цели Prometheus, источник Grafana,
|
||||||
компоненты Airflow, ручной запуск пробников `test_clickhouse`
|
компоненты Airflow, ручной запуск пробников `test_clickhouse` и `test_kafka`,
|
||||||
и `test_kafka`, метаданные и подключение Superset. Первый пробник создаёт
|
метаданные и подключение Superset. Первый пробник создаёт
|
||||||
таблицы на обеих нодах и читает через `Distributed` на ноде 2 строку из
|
таблицы на обеих нодах и читает через `Distributed` на ноде 2 строку из
|
||||||
локальной таблицы ноды 1. Второй пишет в Kafka и читает свой маркер. В конце
|
локальной таблицы ноды 1. Второй пишет в Kafka и читает свой маркер. В конце
|
||||||
проверка спрашивает у Docker, не убивало ли ядро что-нибудь в долгоживущих
|
проверка спрашивает у Docker, не убивало ли ядро что-нибудь в долгоживущих
|
||||||
@@ -74,13 +74,14 @@ keeper, Kafka через порт машины, три цели Prometheus, ис
|
|||||||
Временный топик проверки с машины и запуски DAG удаляются;
|
Временный топик проверки с машины и запуски DAG удаляются;
|
||||||
постоянный топик пробника сохраняется, а старые записи чистит Kafka.
|
постоянный топик пробника сохраняется, а старые записи чистит Kafka.
|
||||||
|
|
||||||
Про здоровье контейнеров честно будет сказать так: сразу после `make up --wait`
|
Одиннадцать проверок здоровья сразу после `make up --wait` повторяют то, чего
|
||||||
эти одиннадцать проверок повторяют то, чего Compose уже дождался, — у каждой
|
Compose уже дождался: у каждой долгоживущей службы есть своя `healthcheck`.
|
||||||
долгоживущей службы есть своя `healthcheck`. Оставлены они потому, что первый
|
Оставлены они потому, что первый вопрос к стенду всё равно «всё ли живо», а
|
||||||
вопрос к стенду всё равно «всё ли живо», и ответ на него стоит меньше секунды.
|
ответ на него стоит меньше секунды. Устройство keeper — другое дело: он должен
|
||||||
Устройство keeper — другое дело: он работает от пользователя `clickhouse`, с
|
работать от пользователя `clickhouse`, с пределом в 262144 открытых файла и со
|
||||||
пределом в 262144 открытых файла и своим каталогом координации. Здоровым он
|
своим томом под данные. Всё это объявлено в `compose.yaml`, но здоровым keeper
|
||||||
выглядит и без этого, а грабли тут настоящие.
|
выглядит и без этого, поэтому смоук спрашивает у живого контейнера, дошли ли
|
||||||
|
объявленные настройки до процесса.
|
||||||
|
|
||||||
`make smoke-cluster` запускает отдельную глубокую проверку ClickHouse: описание
|
`make smoke-cluster` запускает отдельную глубокую проверку ClickHouse: описание
|
||||||
кластера, макросы, связь с keeper, `ReplicatedMergeTree`, `Distributed`, очередь
|
кластера, макросы, связь с keeper, `ReplicatedMergeTree`, `Distributed`, очередь
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ def _drop_tables(client) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Единственная проверка, вынесенная из задач: её делают обе, до создания таблиц
|
# Отсутствие таблиц проверяют обе задачи — перед созданием и после уборки,
|
||||||
# и после уборки.
|
# — поэтому у этой проверки своё имя, а остальные живут прямо в теле задач.
|
||||||
def _assert_tables_absent(client) -> None:
|
def _assert_tables_absent(client) -> None:
|
||||||
for node_name, source in NODES:
|
for node_name, source in NODES:
|
||||||
remaining = _table_engines(client, source)
|
remaining = _table_engines(client, source)
|
||||||
@@ -197,7 +197,8 @@ def test_clickhouse():
|
|||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"запись и чтение маркера должны выполняться с разных нод"
|
"запись и чтение маркера должны выполняться с разных нод"
|
||||||
)
|
)
|
||||||
if distributed_rows != [(1, written["hostname"], written["marker"])]:
|
expected_rows = [(1, written["hostname"], written["marker"])]
|
||||||
|
if distributed_rows != expected_rows:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"нода 2 не прочитала маркер первого шарда через Distributed: "
|
"нода 2 не прочитала маркер первого шарда через Distributed: "
|
||||||
f"{written['marker']}, получено {distributed_rows}"
|
f"{written['marker']}, получено {distributed_rows}"
|
||||||
|
|||||||
+15
-10
@@ -74,26 +74,31 @@ check_container_health() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Keeper — единственная служба, которой мало быть здоровой: она пишет журнал
|
keeper_exec() {
|
||||||
# координации, и если запустить её от root или с чужим каталогом данных, файлы
|
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() {
|
check_keeper_runtime() {
|
||||||
local keeper_user
|
|
||||||
local keeper_nofile
|
local keeper_nofile
|
||||||
local keeper_owner
|
local keeper_owner
|
||||||
|
local keeper_user
|
||||||
|
|
||||||
keeper_user="$(compose exec -T clickhouse-keeper id -un)"
|
keeper_user="$(keeper_exec id -un)"
|
||||||
keeper_nofile="$(compose exec -T clickhouse-keeper \
|
keeper_nofile="$(keeper_exec \
|
||||||
awk '$1 == "Max" && $2 == "open" && $3 == "files" {print $4}' /proc/1/limits)"
|
awk '$1 == "Max" && $2 == "open" && $3 == "files" {print $4}' /proc/1/limits)"
|
||||||
keeper_owner="$(compose exec -T clickhouse-keeper \
|
keeper_owner="$(keeper_exec stat -c '%U:%G' /var/lib/clickhouse/coordination)"
|
||||||
stat -c '%U:%G' /var/lib/clickhouse/coordination)"
|
|
||||||
if [[ "$keeper_user" == 'clickhouse' ]] && \
|
if [[ "$keeper_user" == 'clickhouse' ]] && \
|
||||||
[[ "$keeper_nofile" -ge 262144 ]] && \
|
[[ "$keeper_nofile" -ge 262144 ]] && \
|
||||||
[[ "$keeper_owner" == 'clickhouse:clickhouse' ]]; then
|
[[ "$keeper_owner" == 'clickhouse:clickhouse' ]]; then
|
||||||
pass 'keeper работает от clickhouse с nofile 262144 и своим каталогом данных'
|
pass 'keeper работает от clickhouse с nofile 262144 и своим каталогом данных'
|
||||||
else
|
else
|
||||||
fail "неверное окружение keeper: пользователь=${keeper_user}, nofile=${keeper_nofile}, владелец каталога=${keeper_owner}"
|
fail "неверное окружение keeper: пользователь=${keeper_user:-нет ответа}, nofile=${keeper_nofile:-нет ответа}, владелец каталога=${keeper_owner:-нет ответа}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user