-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sharding): add command to sync tables onto new nodes (#8912)
* feat(sharding): add command to sync tables onto new nodes clickhouse-operator only syncs some tables onto new nodes. This new command ensures that when adding new shards, they are automatically synced up on redeploying Note that there might be timing concerns here as resharding on altinity cloud does not redeploy automatically. In practice however what this means is that new nodes just won't ingest any data until another deploy * Add test to the new command * Improve non-replicated test
- Loading branch information
Showing
7 changed files
with
169 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# This file contains all CREATE TABLE queries, used to sync and test schema | ||
import re | ||
|
||
from ee.clickhouse.sql.cohort import * | ||
from ee.clickhouse.sql.dead_letter_queue import * | ||
from ee.clickhouse.sql.events import * | ||
from ee.clickhouse.sql.groups import * | ||
from ee.clickhouse.sql.person import * | ||
from ee.clickhouse.sql.plugin_log_entries import * | ||
from ee.clickhouse.sql.session_recording_events import * | ||
|
||
CREATE_TABLE_QUERIES = [ | ||
CREATE_COHORTPEOPLE_TABLE_SQL, | ||
PERSON_STATIC_COHORT_TABLE_SQL, | ||
DEAD_LETTER_QUEUE_TABLE_SQL, | ||
KAFKA_DEAD_LETTER_QUEUE_TABLE_SQL, | ||
DEAD_LETTER_QUEUE_TABLE_MV_SQL, | ||
EVENTS_TABLE_SQL, | ||
KAFKA_EVENTS_TABLE_SQL, | ||
EVENTS_TABLE_MV_SQL, | ||
GROUPS_TABLE_SQL, | ||
KAFKA_GROUPS_TABLE_SQL, | ||
GROUPS_TABLE_MV_SQL, | ||
PERSONS_TABLE_SQL, | ||
KAFKA_PERSONS_TABLE_SQL, | ||
PERSONS_TABLE_MV_SQL, | ||
PERSONS_DISTINCT_ID_TABLE_SQL, | ||
KAFKA_PERSONS_DISTINCT_ID_TABLE_SQL, | ||
PERSONS_DISTINCT_ID_TABLE_MV_SQL, | ||
PERSON_DISTINCT_ID2_TABLE_SQL, | ||
KAFKA_PERSON_DISTINCT_ID2_TABLE_SQL, | ||
PERSON_DISTINCT_ID2_MV_SQL, | ||
KAFKA_PLUGIN_LOG_ENTRIES_TABLE_SQL, | ||
PLUGIN_LOG_ENTRIES_TABLE_SQL, | ||
PLUGIN_LOG_ENTRIES_TABLE_MV_SQL, | ||
SESSION_RECORDING_EVENTS_TABLE_SQL, | ||
KAFKA_SESSION_RECORDING_EVENTS_TABLE_SQL, | ||
SESSION_RECORDING_EVENTS_TABLE_MV_SQL, | ||
WRITABLE_EVENTS_TABLE_SQL, | ||
DISTRIBUTED_EVENTS_TABLE_SQL, | ||
WRITABLE_SESSION_RECORDING_EVENTS_TABLE_SQL, | ||
DISTRIBUTED_SESSION_RECORDING_EVENTS_TABLE_SQL, | ||
] | ||
|
||
build_query = lambda query: query if isinstance(query, str) else query() | ||
get_table_name = lambda query: re.findall(r" ([a-z0-9_]+) ON CLUSTER", build_query(query))[0] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from typing import Dict, Set | ||
|
||
import structlog | ||
from django.conf import settings | ||
from django.core.management.base import BaseCommand | ||
|
||
from ee.clickhouse.client import sync_execute | ||
from ee.clickhouse.sql.schema import CREATE_TABLE_QUERIES, build_query, get_table_name | ||
|
||
logger = structlog.get_logger(__name__) | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Synchronize schema across clickhouse cluster, creating missing tables on new nodes" | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"--dry-run", action="store_true", help="Exits with a non-zero status if schema changes would be required." | ||
) | ||
|
||
def handle(self, *args, **options): | ||
if not settings.CLICKHOUSE_REPLICATION or settings.MULTI_TENANCY: | ||
logger.info("✅ Skipping non-replicated or cloud setup") | ||
return | ||
|
||
out_of_sync_hosts = self.get_out_of_sync_hosts() | ||
|
||
if len(out_of_sync_hosts) > 0: | ||
logger.info("Schema out of sync on some clickhouse nodes!", out_of_sync_hosts=out_of_sync_hosts) | ||
|
||
if options.get("dry_run"): | ||
exit(1) | ||
|
||
logger.info("Creating missing tables") | ||
for query in CREATE_TABLE_QUERIES: | ||
sync_execute(build_query(query)) | ||
|
||
logger.info("✅ All ClickHouse nodes schema in sync") | ||
|
||
def get_out_of_sync_hosts(self): | ||
table_names = list(map(get_table_name, CREATE_TABLE_QUERIES)) | ||
rows = sync_execute( | ||
""" | ||
SELECT hostName() as host, groupArray(name) | ||
FROM clusterAllReplicas(%(cluster)s, system, tables) | ||
WHERE database = %(database)s | ||
AND name IN %(table_names)s | ||
GROUP BY host | ||
""", | ||
{ | ||
"cluster": settings.CLICKHOUSE_CLUSTER, | ||
"database": settings.CLICKHOUSE_DATABASE, | ||
"table_names": table_names, | ||
}, | ||
) | ||
|
||
out_of_sync: Dict[str, Set[str]] = {} | ||
for host, host_tables in rows: | ||
missing_tables = set(table_names) - set(host_tables) | ||
if len(missing_tables) > 0: | ||
out_of_sync[host] = missing_tables | ||
|
||
return out_of_sync |
Empty file.
47 changes: 47 additions & 0 deletions
47
ee/management/commands/test/test_sync_replicated_schema.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import pytest | ||
from django.conf import settings | ||
|
||
from ee.clickhouse.client import sync_execute | ||
from ee.clickhouse.sql.events import KAFKA_EVENTS_TABLE_SQL | ||
from ee.clickhouse.sql.schema import CREATE_TABLE_QUERIES | ||
from ee.clickhouse.util import ClickhouseTestMixin | ||
from ee.management.commands.sync_replicated_schema import Command | ||
from posthog.conftest import create_clickhouse_tables | ||
from posthog.test.base import BaseTest | ||
|
||
|
||
@pytest.mark.ee | ||
class TestSyncReplicatedSchema(BaseTest, ClickhouseTestMixin): | ||
def setUp(self): | ||
settings.CLICKHOUSE_REPLICATION = True | ||
self.recreate_database() | ||
sync_execute(KAFKA_EVENTS_TABLE_SQL()) | ||
|
||
def tearDown(self): | ||
self.recreate_database() | ||
settings.CLICKHOUSE_REPLICATION = False | ||
create_clickhouse_tables(0) | ||
|
||
def recreate_database(self): | ||
sync_execute(f"DROP DATABASE {settings.CLICKHOUSE_DATABASE} SYNC") | ||
sync_execute(f"CREATE DATABASE {settings.CLICKHOUSE_DATABASE}") | ||
|
||
def test_get_out_of_sync_hosts(self): | ||
# :KLUDGE: We simulate an out-of-sync database by wiping everything but one table | ||
out_of_sync_hosts = Command().get_out_of_sync_hosts() | ||
|
||
self.assertEqual(len(out_of_sync_hosts), 1) | ||
|
||
[values] = list(out_of_sync_hosts.values()) | ||
self.assertEqual(len(values), len(CREATE_TABLE_QUERIES) - 1) | ||
|
||
def test_handle_sync(self): | ||
Command().handle() | ||
|
||
self.assertEqual(len(Command().get_out_of_sync_hosts()), 0) | ||
|
||
def test_handle_not_replicated_does_nothing(self): | ||
settings.CLICKHOUSE_REPLICATION = False | ||
|
||
Command().handle() | ||
self.assertEqual(len(Command().get_out_of_sync_hosts()), 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters