๐ ์ด ๊ธ์์ ๋ค๋ฃฐ ๋ด์ฉ
1๏ธโฃ Kafka์ ์ฐ๊ฒฐ๋ ClickHouse ํ
์ด๋ธ ์์ฑ (ํ๊ฒฝ์ค์ ํฌํจ)
2๏ธโฃ ์ค์ต์ฉ ๋ฐ์ดํฐ์
kafka produce
3๏ธโฃ Kafka ํ
์ด๋ธ์์ ๋ฐ์ดํฐ ์
ํ์ธ ๋ฐฉ๋ฒ
1. Kafka์ ์ฐ๊ฒฐ๋ ClickHouse ํ ์ด๋ธ ์์ฑ
๐น Kafka ๋ฐ์ดํฐ๋ฅผ ClickHouse์์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์
ClickHouse๋ Kafka์ ์ง์ ์ฐ๊ฒฐํ์ฌ ์ค์๊ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ Kafka ์์ง์ ์ ๊ณตํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก Kafka → Buffer ํ
์ด๋ธ → MergeTree ํ
์ด๋ธ์ ๊ตฌ์กฐ๋ก ์ด์๋ฉ๋๋ค.
๐น ClickHouse ์ค์ ๋ณ๊ฒฝ (Kafka ์ฌ์ฉ์ ์ํ ์ค์ )
๋จผ์ , clickhouse-server์ ํ๊ฒฝ์ค์ ์ ์์ ํด์ผ ํฉ๋๋ค.
ClickHouse ์ค์ ํ์ผ (config.xml)์์ Kafka๋ฅผ ์ฌ์ฉํ๋๋ก ์ค์ ํฉ๋๋ค. ์ด์ ์ ๊ฒ์ํ๋ ํฌ์คํธ(https://jongwho.tistory.com/21 )์์ ์์ฑํ values.yaml์ ์์ ํฉ๋๋ค.
[๋ฐ์ดํฐ ๋ถ์ ํ๊ฒฝ ๊ตฌ์ถ - 02. Clickhouse ์ค์น ๋ฐ ํด๋ฌ์คํฐ ๊ตฌ์ฑ
์ด๋ฒ ๊ธ์์๋ Kubernetes ํ๊ฒฝ์์ ClickHouse๋ฅผ ๋ฐฐํฌ ๋ฐ ์คํํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.Docker Desktop์ ๋ด์ฅ Kubernetes๋ฅผ ํ์ฉํ๊ณ , Helm ๋ฐ Bitnami Helm ์ฐจํธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐํธํ๊ฒ ClickHouse๋ฅผ ๋ฐฐํฌํฉ๋๋ค.1. ์ฌ
jongwho.tistory.com](https://jongwho.tistory.com/21)
๐ 1) values.yaml ์์
- line 273: defaultConfigurationOverrides ๋ด xml ํ์์ ์ฝ๋ ์ถ๊ฐ
<!-- config.xml -->
<clickhouse>
<!-- Kafka -->
<kafka>
<debug>all</debug>
<security_protocol>SASL_SSL</security_protocol>
<sasl_mechanism>SCRAM-SHA-512</sasl_mechanism>
<sasl_username>(์ ์ ์ด๋ฆ ์
๋ ฅ)</sasl_username>
<sasl_password>(password ์
๋ ฅ)</sasl_password>
<kafka_topic>
<name>(kafka ํ ํฝ ์
๋ ฅ)</name>
<statistics_interval_ms>4000</statistics_interval_ms>
</kafka_topic>
<!-- Settings for consumer -->
<consumer>
<auto_offset_reset>smallest</auto_offset_reset>
<kafka_topic>
<name>(kafka ํ ํฝ ์
๋ ฅ)</name>
<fetch_min_bytes>100000</fetch_min_bytes>
</kafka_topic>
</consumer>
</kafka>
...(์ดํ ์๋ต)
</clickhouse>
๐ 2) ClickHouse ์ฌ ๋ฐฐํฌ
helm upgrade clickhouse oci://registry-1.docker.io/bitnamicharts/clickhouse -f ./clickhouse/values.yaml -n clickhouse
# or
helm upgrade clickhouse bitnami/clickhouse -f ./clickhouse/values.yaml -n clickhouse
์ดํ k8s ๋ด clickhouse ์๋น์ค๋ฅผ port-forwardํ์ฌ ์ ์ํ ์ ์๋๋ก ํฉ๋๋ค.
- ์๋ ๋ช
๋ น์ด๋ก
localhost:8123
์ผ๋ก clickhouse์ ์ ๊ทผ ๊ฐ๋ฅํฉ๋๋ค.
kubectl port-forward svc/clickhouse 8123:8123 -n clickhouse
2. ClickHouse์์ Kafka ํ ์ด๋ธ ์์ฑํ๊ธฐ
Kafka์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ClickHouse์ ์ ์ฅํ๋ ํ ์ด๋ธ์ ์์ฑํฉ๋๋ค.
๐น 1) Kafka ์์ง ํ ์ด๋ธ ์์ฑ
๋จผ์ , Kafka ํ ํฝ์ ๊ตฌ๋ ํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฐ ํ ์ด๋ธ์ ์์ฑํฉ๋๋ค.
CREATE DATABASE IF NOT EXISTS streaming_db;
CREATE TABLE streaming_db.kafka_events (
event_time DateTime,
user_id UInt32,
event_type String
) ENGINE = Kafka
-- kafka_broker_list์ ์ฝค๋ง(,)๋ก broker ๋ชฉ๋ก์ ์ถ๊ฐํฉ๋๋ค.
SETTINGS kafka_broker_list = 'kafka-broker-headless.kafka.svc.cluster.local:9092',
kafka_topic_list = 'events',
kafka_group_name = 'clickhouse_consumer',
kafka_format = 'JSONEachRow';
๐ ์ค๋ช
- ENGINE = Kafka: Kafka์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- kafka_broker_list: Kafka ๋ธ๋ก์ปค ์ฃผ์
- kafka_topic_list: ๊ตฌ๋ ํ Kafka ํ ํฝ
- kafka_group_name: Kafka Consumer Group
- kafka_format = 'JSONEachRow': JSON ๋ฐ์ดํฐ๋ฅผ Row ๋จ์๋ก ๋ณํ
๐น 2) Materialized View ๋ฐ ํ ์ด๋ธ ์์ฑ
Buffer ํ ์ด๋ธ์ ์์ฑํ์ฌ clickhouse ์๋ฒ ์ฑ๋ฅ์ ์ ํ ์์ด ์ฌ์ฉํ๋๋ก ์ค์ ํ ์ ์์ต๋๋ค. ํ์ง๋ง ์ค์ต ์ค ๋น ๋ฅธ ๋ฐ์ดํฐ ํ์ธ์ ์ํด Materialized View๋ฅผ ์์ฑํ์ฌ kafka - clickhouse ์ฐ๊ฒฐ์ ํ์ธํฉ๋๋ค.
๐ Materiazlied View ๋ฐ ํ ์ด๋ธ ์์ฑ
-- events ํ
์ด๋ธ ์์ฑ
CREATE TABLE streaming_db.events (
event_time DateTime,
user_id UInt32,
event_type String
) ENGINE = MergeTree()
ORDER BY (event_time, user_id);
-- Materialized View ์์ฑ
CREATE MATERIALIZED VIEW streaming_db.events_mv TO streaming_db.events AS
SELECT *
FROM streaming_db.kafka_events
;
ํด๋น ํ ์ด๋ธ ์์ฑ์ผ๋ก Redpanda Console(Kafka ui)์์ Consumer group์ ํ์ธํ ์ ์์ต๋๋ค.
๐น ๊ธฐํ) Buffer ํ ์ด๋ธ
๐ Buffer ํ ์ด๋ธ์ด ํ์ํ ์ด์ ?
Kafka์์ ClickHouse๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ก ์ ์ฅํ๋ฉด MergeTree์ ๋ํ ๋น๋ฒํ INSERT ์์
์ด ๋ฐ์ํ์ฌ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด Buffer ํ
์ด๋ธ์ ์ฌ์ฉํ์ฌ RAM์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ํ, ์ผ์ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด MergeTree๋ก ๋ฐฐ์น ์ ์ฅํ๋ ๋ฐฉ์์ด ํ์ํฉ๋๋ค.
๐ Buffer ํ ์ด๋ธ ๊ธฐ๋ณธ ๊ฐ๋
- ๋ฐ์ดํฐ๋ฅผ RAM์ ์์ ์ ์ฅ ํ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๋ฉด ์๋ ํ๋ฌ์ (Flush) ์ํ
- INSERT ์๋ ํฅ์ ๋ฐ MergeTree ํ ์ด๋ธ์ ๋์คํฌ ์ฐ๊ธฐ ๋ถํ ๊ฐ์
- num_layers ๊ฐ์ ์ฌ์ฉํ์ฌ ๋ณ๋ ฌ ๋ฒํผ๋ง ๊ฐ๋ฅ
- ํน์ ์๊ฐ(min_time), ํ ์(min_rows), ํฌ๊ธฐ(min_bytes) ์กฐ๊ฑด์ ๋ง์กฑํ๋ฉด ์๋ ์ ์ฅ
๐ Buffer ํ ์ด๋ธ ์์ฑ (RAM ์บ์ฑ ํ์ฉ)
CREATE TABLE streaming_db.buffer_events (
event_time DateTime,
user_id UInt32,
event_type String
) ENGINE = Buffer(streaming_db, events, 1, 10, 100, 10000, 100000, 1000000, 10000000);
โ ์ค๋ช
- Buffer(database, ๋์(flush) ํ
์ด๋ธ, 1, 10, 100, 10000, 100000, 1000000, 10000000)
- 1: ๋จ์ผ ๋ฒํผ ์ฌ์ฉ (num_layers)
- 10: ์ต์ 10์ด ํ ์๋ ์ ์ฅ (min_time)
- 100: ์ต์ 100๊ฐ ํ์ด ์์ด๋ฉด ์ ์ฅ (min_rows)
- 10000: ์ต์ 10KB ๋ฐ์ดํฐ๊ฐ ์์ด๋ฉด ์ ์ฅ (min_bytes)
- 10000000: ์ต๋ 10MB ๋ฐ์ดํฐ๊น์ง ์ ์ฅ ๊ฐ๋ฅ (max_bytes)
โ ๋ฐ์ดํฐ ํ๋ฆ
Kafka → Buffer ํ ์ด๋ธ (RAM) → MergeTree ํ ์ด๋ธ (๋์คํฌ ์ ์ฅ)
๐ ๊ฒฐ๊ณผ:
- Kafka์์ ๋๋ ๋ฐ์ดํฐ๋ฅผ ์์งํ ๋ ๋น ๋ฅธ INSERT ์๋ ๋ณด์ฅ
- MergeTree ํ ์ด๋ธ๋ก ์ ์ฅํ ๋ ์ผ๊ด ์ฒ๋ฆฌ(Batch Insert)๋ก ์ฑ๋ฅ ์ต์ ํ
3. ์ค์ต์ฉ ๋ฐ์ดํฐ์ ์์ฑ(Kafka)
kafka ๋ฐ์ดํฐ ์์ฑ(in redpanda console)
๐ ์ ์ฒด ์กฐํ SQL
select event_time, user_id, event_type
from cluster('default', streaming_db.events_mv)
limit 10;
- ๋ฐ์ดํฐ ์์
{"event_time": "2025-03-20 10:00:00", "user_id": 101, "event_type": "page_view"}
{"event_time": "2025-03-20 10:01:00", "user_id": 102, "event_type": "click"}
{"event_time": "2025-03-20 10:02:00", "user_id": 103, "event_type": "purchase"}
{"event_time": "2025-03-20 10:03:00", "user_id": 104, "event_type": "page_view"}
{"event_time": "2025-03-20 10:04:00", "user_id": 105, "event_type": "click"}
{"event_time": "2025-03-20 10:05:00", "user_id": 106, "event_type": "purchase"}
{"event_time": "2025-03-20 10:06:00", "user_id": 107, "event_type": "page_view"}
{"event_time": "2025-03-20 10:07:00", "user_id": 108, "event_type": "click"}
{"event_time": "2025-03-20 10:08:00", "user_id": 109, "event_type": "purchase"}
{"event_time": "2025-03-20 10:09:00", "user_id": 110, "event_type": "page_view"}
{"event_time": "2025-03-20 10:10:00", "user_id": 111, "event_type": "click"}
{"event_time": "2025-03-20 10:11:00", "user_id": 112, "event_type": "purchase"}
{"event_time": "2025-03-20 10:12:00", "user_id": 113, "event_type": "page_view"}
{"event_time": "2025-03-20 10:13:00", "user_id": 114, "event_type": "click"}
{"event_time": "2025-03-20 10:14:00", "user_id": 115, "event_type": "purchase"}
{"event_time": "2025-03-20 10:15:00", "user_id": 116, "event_type": "page_view"}
{"event_time": "2025-03-20 10:16:00", "user_id": 117, "event_type": "click"}
{"event_time": "2025-03-20 10:17:00", "user_id": 118, "event_type": "purchase"}
{"event_time": "2025-03-20 10:18:00", "user_id": 119, "event_type": "page_view"}
{"event_time": "2025-03-20 10:19:00", "user_id": 120, "event_type": "click"}
- ์กฐํ ์์