ClickHouse یک پایگاه داده تحلیلی توزیعشده و بسیار سریع است که برای پردازش دادههای بزرگ در محیطهای OLAP طراحی شده است. یکی از قابلیتهای کلیدی آن Replication یا تکرار دادهها است که باعث میشود دادهها در چند نود ذخیره شوند تا هم دسترسی بالا فراهم شود و هم تحمل خطا در نودها ممکن باشد.
در این کارگاه عملی، ما یک کلاستر با ۴ نود، ۲ شارد و ۲ رپلیکا برای هر شارد ایجاد میکنیم و با مکانیزم توزیع و رپلیکیشن دادهها در ClickHouse آشنا میشویم.
در ClickHouse، هر جدول میتواند روی چند نود توزیع شود. برای افزایش دسترسپذیری و تحمل خطا، از ReplicatedMergeTree استفاده میکنیم.
نکته مهم: برای اینکه رپلیکیشن درست کار کند، هر نود باید ماکروها و کانفیگ مخصوص خود را داشته باشد و مسیر ZooKeeper (یا ClickHouse Keeper) برای هر جدول منحصر به شارد و رپلیکا باشد.
در این کارگاه، چهار نود داریم:
| نود | شارد | رپلیکا |
|---|---|---|
| chnode1 | ۱ | replica_1 |
| chnode3 | ۱ | replica_2 |
| chnode2 | ۲ | replica_1 |
| chnode4 | ۲ | replica_2 |
ابتدا در فایل کانفیگ هر نود، بخش remote_servers را مطابق ساختار کلاستر به روز میکنیم:
<clickhouse>
<remote_servers replace="true">
<cluster_2S_2R>
<!-- Shard 1 -->
<shard>
<internal_replication>true</internal_replication>
<replica><host>chnode1</host><port>9000</port></replica>
<replica><host>chnode3</host><port>9000</port></replica>
</shard>
<!-- Shard 2 -->
<shard>
<internal_replication>true</internal_replication>
<replica><host>chnode2</host><port>9000</port></replica>
<replica><host>chnode4</host><port>9000</port></replica>
</shard>
</cluster_2S_2R>
</remote_servers>
</clickhouse>
توجه: هر نود یک پوشه کانفیگ مجزا دارد، و تنظیمات باید بر اساس نقش آن نود در شارد و رپلیکا متفاوت باشد.
در فایل macros.xml هر نود، اطلاعات شارد و رپلیکا خود را تعریف میکنیم:
<macros>
<shard>1</shard>
<replica>replica_1</replica>
</macros>
<macros>
<shard>1</shard>
<replica>replica_2</replica>
</macros>
<macros>
<shard>2</shard>
<replica>replica_1</replica>
</macros>
<macros>
<shard>2</shard>
<replica>replica_2</replica>
</macros>
CREATE TABLE rides.trips_local ON CLUSTER 'cluster_2S_2R'
(
VendorID Int32,
tpep_pickup_datetime DateTime64(6),
tpep_dropoff_datetime DateTime64(6),
passenger_count Nullable(Int64),
trip_distance Nullable(Float64),
RatecodeID Nullable(Int64),
store_and_fwd_flag Nullable(String),
PULocationID Int32,
DOLocationID Int32,
payment_type Nullable(Int64),
fare_amount Nullable(Float64),
extra Nullable(Float64),
mta_tax Nullable(Float64),
tip_amount Nullable(Float64),
tolls_amount Nullable(Float64),
improvement_surcharge Nullable(Float64),
total_amount Nullable(Float64),
congestion_surcharge Nullable(Float64),
Airport_fee Nullable(Float64)
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/rides/trips_local', '{replica}')
PARTITION BY toYYYYMM(tpep_pickup_datetime)
ORDER BY (tpep_pickup_datetime, tpep_dropoff_datetime, PULocationID, DOLocationID)
SETTINGS index_granularity = 8192;
/clickhouse/tables/{shard}/rides/trips_local مخصوص هر شارد است.{replica} با نام رپلیکای نود جایگزین میشود.CREATE TABLE rides.trips_distributed ON CLUSTER 'cluster_2S_2R'
AS rides.trips_local
ENGINE = Distributed('cluster_2S_2R', rides, trips_local, toMonth(tpep_pickup_datetime) % 2);
Distributed Table داده را نگه نمیدارد، فقط کوئریها را به شاردها هدایت میکند.
برای وارد کردن داده به کلاستر، از جدول توزیع شده استفاده میکنیم:
INSERT INTO rides.trips_distributed
FROM INFILE '/var/lib/clickhouse/user_files/nyc_taxi/*.parquet'
FORMAT Parquet;
برای اطمینان از اینکه همه جداول دارای رپلیکا هستند:
SELECT
database,
table,
is_leader,
total_replicas,
active_replicas,
is_readonly
FROM system.replicas
WHERE database NOT IN ('system', 'information_schema', 'INFORMATION_SCHEMA')
ORDER BY database, table;
total_replicas = 2 → هر شارد دو رپلیکا داردactive_replicas = 2 → همه رپلیکاها فعال هستندبا این کارگاه:
نکته حرفهای: اگر بعداً تعداد نودها یا شاردها تغییر کند، باید جدولهای توزیع شده دوباره ساخته شوند تا فرمول توزیع (Shard Key) بر اساس تعداد جدید نودها اعمال شود.