في هذا المثال، ستتعلم كيفية إعداد عنقود ClickHouse بسيط قابل للتوسّع. هناك خمسة خوادم مُعدّة. يُستخدم اثنان منها لتجزئة البيانات. وتُستخدم الخوادم الثلاثة الأخرى للتنسيق.
تظهر أدناه معمارية العنقود الذي ستقوم بإعداده:

المتطلبات الأساسية
- سبق أن قمتَ بإعداد خادم ClickHouse محلي
- أنت على دراية بمفاهيم الإعداد الأساسية في ClickHouse، مثل ملفات الإعداد
- Docker مُثبَّت على جهازك
إعداد بنية الدليل وبيئة الاختبار
في هذا الدليل العملي، ستستخدم Docker compose لإعداد مجموعة ClickHouse. يمكن تعديل هذا الإعداد ليعمل على أجهزة محلية منفصلة، أو أجهزة افتراضية، أو نسخ سحابية كذلك.
شغّل الأوامر التالية لإعداد بنية الدليل لهذا المثال:
mkdir cluster_2S_1R
cd cluster_2S_1R
# Create clickhouse-keeper directories
for i in {01..03}; do
mkdir -p fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper
done
# Create clickhouse-server directories
for i in {01..02}; do
mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server
doneأضف ملف docker-compose.yml التالي إلى دليل cluster_2S_1R:
version: '3.8'
services:
clickhouse-01:
image: "clickhouse/clickhouse-server:latest"
user: "101:101"
container_name: clickhouse-01
hostname: clickhouse-01
networks:
cluster_2S_1R:
ipv4_address: 192.168.7.1
volumes:
- ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
- ${PWD}/fs/volumes/clickhouse-01/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
ports:
- "127.0.0.1:8123:8123"
- "127.0.0.1:9000:9000"
depends_on:
- clickhouse-keeper-01
- clickhouse-keeper-02
- clickhouse-keeper-03
clickhouse-02:
image: "clickhouse/clickhouse-server:latest"
user: "101:101"
container_name: clickhouse-02
hostname: clickhouse-02
networks:
cluster_2S_1R:
ipv4_address: 192.168.7.2
volumes:
- ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/config.d/config.xml:/etc/clickhouse-server/config.d/config.xml
- ${PWD}/fs/volumes/clickhouse-02/etc/clickhouse-server/users.d/users.xml:/etc/clickhouse-server/users.d/users.xml
ports:
- "127.0.0.1:8124:8123"
- "127.0.0.1:9001:9000"
depends_on:
- clickhouse-keeper-01
- clickhouse-keeper-02
- clickhouse-keeper-03
clickhouse-keeper-01:
image: "clickhouse/clickhouse-keeper:latest-alpine"
user: "101:101"
container_name: clickhouse-keeper-01
hostname: clickhouse-keeper-01
networks:
cluster_2S_1R:
ipv4_address: 192.168.7.5
volumes:
- ${PWD}/fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
ports:
- "127.0.0.1:9181:9181"
clickhouse-keeper-02:
image: "clickhouse/clickhouse-keeper:latest-alpine"
user: "101:101"
container_name: clickhouse-keeper-02
hostname: clickhouse-keeper-02
networks:
cluster_2S_1R:
ipv4_address: 192.168.7.6
volumes:
- ${PWD}/fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
ports:
- "127.0.0.1:9182:9181"
clickhouse-keeper-03:
image: "clickhouse/clickhouse-keeper:latest-alpine"
user: "101:101"
container_name: clickhouse-keeper-03
hostname: clickhouse-keeper-03
networks:
cluster_2S_1R:
ipv4_address: 192.168.7.7
volumes:
- ${PWD}/fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper/keeper_config.xml:/etc/clickhouse-keeper/keeper_config.xml
ports:
- "127.0.0.1:9183:9181"
networks:
cluster_2S_1R:
driver: bridge
ipam:
config:
- subnet: 192.168.7.0/24
gateway: 192.168.7.254أنشئ المجلدات الفرعية والملفات التالية:
for i in {01..02}; do
mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d
mkdir -p fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d
touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/config.d/config.xml
touch fs/volumes/clickhouse-${i}/etc/clickhouse-server/users.d/users.xml
done- يحتوي الدليل
config.dعلى ملف إعدادات خادم ClickHouse config.xml، حيث تُحدَّد الإعدادات المخصصة لكل عقدة ClickHouse. وتُدمَج هذه الإعدادات مع ملف إعدادات ClickHouse الافتراضيconfig.xmlالذي يأتي مع كل عملية تثبيت لـ ClickHouse. - يحتوي الدليل
users.dعلى ملف إعدادات المستخدمusers.xml، حيث تُحدَّد الإعدادات المخصصة للمستخدمين. وتُدمَج هذه الإعدادات مع ملف إعدادات ClickHouse الافتراضيusers.xmlالذي يأتي مع كل عملية تثبيت لـ ClickHouse.
تهيئة عقد ClickHouse
إعداد الخادم
قم الآن بتعديل كل ملف تهيئة فارغ config.xml الموجود في
fs/volumes/clickhouse-{}/etc/clickhouse-server/config.d. يجب تغيير الأسطر
المُمَيَّزة أدناه بحيث تكون مخصصة لكل عقدة:
<clickhouse replace="true">
<logger>
<level>debug</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>
<display_name>cluster_2S_1R node 1</display_name>
<listen_host>0.0.0.0</listen_host>
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<user_directories>
<users_xml>
<path>users.xml</path>
</users_xml>
<local_directory>
<path>/var/lib/clickhouse/access/</path>
</local_directory>
</user_directories>
<distributed_ddl>
<path>/clickhouse/task_queue/ddl</path>
</distributed_ddl>
<remote_servers>
<cluster_2S_1R>
<shard>
<replica>
<host>clickhouse-01</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse-02</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_1R>
</remote_servers>
<zookeeper>
<node>
<host>clickhouse-keeper-01</host>
<port>9181</port>
</node>
<node>
<host>clickhouse-keeper-02</host>
<port>9181</port>
</node>
<node>
<host>clickhouse-keeper-03</host>
<port>9181</port>
</node>
</zookeeper>
<macros>
<shard>01</shard>
<replica>01</replica>
</macros>
</clickhouse>| الدليل | File |
|---|---|
fs/volumes/clickhouse-01/etc/clickhouse-server/config.d |
config.xml |
fs/volumes/clickhouse-02/etc/clickhouse-server/config.d |
config.xml |
يُشرح كل قسم من أقسام ملف الإعداد أعلاه بمزيد من التفاصيل في ما يلي.
الشبكة والتسجيل
يُفعَّل الاتصال الخارجي عبر واجهة الشبكة من خلال تفعيل إعداد listen host. ويضمن ذلك أن يكون خادم ClickHouse قابلاً للوصول من قِبل المضيفات الأخرى:
<listen_host>0.0.0.0</listen_host>تم ضبط منفذ واجهة برمجة تطبيقات HTTP على 8123:
<http_port>8123</http_port>يُضبط منفذ TCP المستخدم للتواصل عبر البروتوكول الأصلي لـ ClickHouse بين clickhouse-client
وأدوات ClickHouse الأصلية الأخرى، وبين clickhouse-server وخوادم clickhouse-server الأخرى
على 9000:
<tcp_port>9000</tcp_port>يُعرَّف التسجيل في كتلة <logger>. يوفر لك مثال الإعداد هذا سجل تصحيح يُدوَّر عند 1000M ثلاث مرات:
<logger>
<level>debug</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>لمزيد من المعلومات حول تهيئة التسجيل، راجع التعليقات المضمّنة في ملف التهيئة الافتراضي لـ ClickHouse.
تهيئة الكلستر
يتم ضبط إعداد الكتلة في القسم <remote_servers>.
هنا يُحدَّد اسم الكتلة cluster_2S_1R.
يُعرِّف الكتلة <cluster_2S_1R></cluster_2S_1R> تخطيط الكلستر باستخدام إعدادَي <shard></shard> و<replica></replica>، ويعمل كقالب لاستعلامات DDL الموزَّعة، وهي الاستعلامات التي تُنفَّذ عبر الكلستر باستخدام جملة ON CLUSTER. تكون استعلامات DDL الموزَّعة مسموحاً بها افتراضياً، غير أنه يمكن تعطيلها عبر الإعداد allow_distributed_ddl_queries.
يُترك internal_replication مضبوطاً على false بشكل افتراضي نظراً لوجود نسخة واحدة فقط لكل جزء.
<remote_servers>
<cluster_2S_1R>
<shard>
<replica>
<host>clickhouse-01</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse-02</host>
<port>9000</port>
</replica>
</shard>
</cluster_2S_1R>
</remote_servers>لكل خادم، تُحدَّد المعلمات التالية:
| Parameter | Description | Default Value |
|---|---|---|
host |
عنوان الخادم البعيد. يمكنك استخدام اسم النطاق أو عنوان IPv4 أو IPv6. إذا حددت اسم النطاق، فسيُجري الخادم طلب DNS عند بدء التشغيل، وتُحفَظ النتيجة طوال مدة تشغيل الخادم. إذا فشل طلب DNS، فلن يبدأ الخادم. وإذا غيّرت سجل DNS، فستحتاج إلى إعادة تشغيل الخادم. | - |
port |
منفذ TCP لنشاط المراسلة (tcp_port في الإعدادات، ويُضبط عادةً على 9000). لا تخلطه مع http_port. |
- |
تهيئة Keeper
يُحدِّد القسم <ZooKeeper> لـ ClickHouse موقع تشغيل ClickHouse Keeper (أو ZooKeeper).
نظرًا لاستخدامنا Keeper cluster، يجب تحديد كل <node> من عقد الـ cluster،
مع اسم الـ hostname ورقم المنفذ الخاص به باستخدام الوسمَين <host> و<port> على التوالي.
سيُشرح إعداد ClickHouse Keeper في الخطوة التالية من الدليل العملي.
<zookeeper>
<node>
<host>clickhouse-keeper-01</host>
<port>9181</port>
</node>
<node>
<host>clickhouse-keeper-02</host>
<port>9181</port>
</node>
<node>
<host>clickhouse-keeper-03</host>
<port>9181</port>
</node>
</zookeeper>تهيئة الماكرو
بالإضافة إلى ذلك، يُستخدم قسم <macros> لتعريف استبدالات المعاملات للجداول المُتماثلة. وتُدرج هذه الاستبدالات في system.macros، مما يتيح استخدام استبدالات مثل {shard} و{replica} في الاستعلامات.
<macros>
<shard>01</shard>
<replica>01</replica>
</macros>تهيئة المستخدم
عدِّل الآن كل ملف تهيئة فارغ users.xml الموجود في
fs/volumes/clickhouse-{}/etc/clickhouse-server/users.d بالمحتوى التالي:
<?xml version="1.0"?>
<clickhouse replace="true">
<profiles>
<default>
<max_memory_usage>10000000000</max_memory_usage>
<use_uncompressed_cache>0</use_uncompressed_cache>
<load_balancing>in_order</load_balancing>
<log_queries>1</log_queries>
</default>
</profiles>
<users>
<default>
<access_management>1</access_management>
<profile>default</profile>
<networks>
<ip>::/0</ip>
</networks>
<quota>default</quota>
<access_management>1</access_management>
<named_collection_control>1</named_collection_control>
<show_named_collections>1</show_named_collections>
<show_named_collections_secrets>1</show_named_collections_secrets>
</default>
</users>
<quotas>
<default>
<interval>
<duration>3600</duration>
<queries>0</queries>
<errors>0</errors>
<result_rows>0</result_rows>
<read_rows>0</read_rows>
<execution_time>0</execution_time>
</interval>
</default>
</quotas>
</clickhouse>| الدليل | File |
|---|---|
fs/volumes/clickhouse-01/etc/clickhouse-server/users.d |
users.xml |
fs/volumes/clickhouse-02/etc/clickhouse-server/users.d |
users.xml |
في هذا المثال، تم تكوين المستخدم default بدون كلمة مرور لتبسيط الإعداد. في التطبيق الفعلي، لا يُنصح بهذا الأسلوب.
تكوين ClickHouse Keeper
إعداد ClickHouse Keeper
لكي يعمل النسخ المتماثل، يجب إعداد عنقود ClickHouse Keeper وتهيئته. يوفّر ClickHouse Keeper نظام التنسيق لنسخ البيانات المتماثل، إذ يعمل كبديل مباشر لـ ZooKeeper، الذي يمكن استخدامه أيضًا. ومع ذلك، يُوصى باستخدام ClickHouse Keeper لأنه يوفّر ضمانات أفضل وموثوقية أعلى ويستخدم موارد أقل من ZooKeeper. ولتحقيق التوافر العالي والحفاظ على quorum، يُوصى بتشغيل ثلاث عقد ClickHouse Keeper على الأقل.
أنشئ ملفات keeper_config.xml لكل عقدة ClickHouse Keeper
باستخدام الأمر التالي من جذر مجلد المثال:
for i in {01..03}; do
touch fs/volumes/clickhouse-keeper-${i}/etc/clickhouse-keeper/keeper_config.xml
doneعدِّل ملفات التكوين الفارغة التي أُنشئت في
دليل كل عقدة fs/volumes/clickhouse-keeper-{}/etc/clickhouse-keeper. يجب
تعديل الأسطر المظللة أدناه بحيث تكون خاصة بكل عقدة:
<clickhouse replace="true">
<logger>
<level>information</level>
<log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
<errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
<size>1000M</size>
<count>3</count>
</logger>
<listen_host>0.0.0.0</listen_host>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>1</server_id>
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>information</raft_logs_level>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>clickhouse-keeper-01</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>clickhouse-keeper-02</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>clickhouse-keeper-03</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
</clickhouse>| الدليل | الملف |
|---|---|
fs/volumes/clickhouse-keeper-01/etc/clickhouse-keeper |
keeper_config.xml |
fs/volumes/clickhouse-keeper-02/etc/clickhouse-keeper |
keeper_config.xml |
fs/volumes/clickhouse-keeper-03/etc/clickhouse-keeper |
keeper_config.xml |
سيحتوي كل ملف تهيئة على التكوين الفريد التالي (كما هو موضح أدناه).
يجب أن يكون server_id المستخدم فريدًا لتلك العقدة المحددة من ClickHouse Keeper
ضمن العنقود، وأن يطابق <id> الخاص بالخادم المعرّف في قسم <raft_configuration>.
يمثل tcp_port المنفذ الذي يستخدمه عملاء ClickHouse Keeper.
<tcp_port>9181</tcp_port>
<server_id>{id}</server_id>يُستخدم القسم التالي لتكوين الخوادم المشاركة في النصاب ضمن خوارزمية إجماع Raft:
<raft_configuration>
<server>
<id>1</id>
<hostname>clickhouse-keeper-01</hostname>
<!-- TCP port used for communication between ClickHouse Keeper nodes -->
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>clickhouse-keeper-02</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>clickhouse-keeper-03</hostname>
<port>9234</port>
</server>
</raft_configuration>اختبر الإعداد
تأكد من أن Docker قيد التشغيل على جهازك.
ابدأ تشغيل الـcluster باستخدام الأمر docker-compose up من جذر الدليل cluster_2S_1R:
docker-compose up -dمن المفترض أن ترى docker يبدأ بسحب صور ClickHouse وKeeper، ثم تشغيل الحاويات:
[+] Running 6/6
✔ Network cluster_2s_1r_default Created
✔ Container clickhouse-keeper-03 Started
✔ Container clickhouse-keeper-02 Started
✔ Container clickhouse-keeper-01 Started
✔ Container clickhouse-01 Started
✔ Container clickhouse-02 Startedللتأكد من أن الـcluster يعمل، اتصل بأحد clickhouse-01 أو clickhouse-02 ونفّذ
الاستعلام التالي. يرد أدناه أمر الاتصال بالعقدة الأولى:
# Connect to any node
docker exec -it clickhouse-01 clickhouse-clientإذا نجح الأمر، فسترى موجّه أوامر ClickHouse client:
cluster_2S_1R node 1 :)نفّذ الاستعلام التالي للتحقّق من بُنى العناقيد المعرّفة ولأيّ مضيفين تم تعريفها:
SELECT
cluster,
shard_num,
replica_num,
host_name,
port
FROM system.clusters; ┌─cluster───────┬─shard_num─┬─replica_num─┬─host_name─────┬─port─┐
1. │ cluster_2S_1R │ 1 │ 1 │ clickhouse-01 │ 9000 │
2. │ cluster_2S_1R │ 2 │ 1 │ clickhouse-02 │ 9000 │
3. │ default │ 1 │ 1 │ localhost │ 9000 │
└───────────────┴───────────┴─────────────┴───────────────┴──────┘نفّذ الاستعلام التالي للتحقق من حالة مجموعة ClickHouse Keeper:
SELECT *
FROM system.zookeeper
WHERE path IN ('/', '/clickhouse') ┌─name───────┬─value─┬─path────────┐
1. │ task_queue │ │ /clickhouse │
2. │ sessions │ │ /clickhouse │
3. │ clickhouse │ │ / │
4. │ keeper │ │ / │
└────────────┴───────┴─────────────┘يُستخدم الأمر mntr أيضًا على نطاق واسع للتحقق من أن ClickHouse Keeper
قيد التشغيل، وللحصول على معلومات عن حالة العلاقة بين عقد Keeper الثلاث.
في الإعداد المستخدم في هذا المثال، هناك ثلاث عقد تعمل معًا.
ستنتخب هذه العقد قائدًا، وستكون العقد المتبقية عقدًا تابعة.
يوفّر الأمر mntr معلومات متعلقة بالأداء، ويُبيّن أيضًا ما إذا كانت
عقدة معيّنة تابعة أم قائدًا.
شغّل الأمر أدناه من سطر الأوامر على clickhouse-keeper-01 وclickhouse-keeper-02 و
clickhouse-keeper-03 للتحقق من حالة كل عقدة Keeper. الأمر
الخاص بـ clickhouse-keeper-01 موضح أدناه:
docker exec -it clickhouse-keeper-01 /bin/sh -c 'echo mntr | nc 127.0.0.1 9181'تعرض الاستجابة أدناه مثالًا على استجابة من عقدة follower:
zk_version v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 0
zk_packets_sent 0
zk_num_alive_connections 0
zk_outstanding_requests 0
zk_server_state follower
zk_znode_count 6
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 1271
zk_key_arena_size 4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count 46
zk_max_file_descriptor_count 18446744073709551615يوضح الرد أدناه مثالًا لرد صادر من العقدة القائدة:
zk_version v23.3.1.2823-testing-46e85357ce2da2a99f56ee83a079e892d7ec3726
zk_avg_latency 0
zk_max_latency 0
zk_min_latency 0
zk_packets_received 0
zk_packets_sent 0
zk_num_alive_connections 0
zk_outstanding_requests 0
zk_server_state leader
zk_znode_count 6
zk_watch_count 0
zk_ephemerals_count 0
zk_approximate_data_size 1271
zk_key_arena_size 4096
zk_latest_snapshot_size 0
zk_open_file_descriptor_count 48
zk_max_file_descriptor_count 18446744073709551615
zk_followers 2
zk_synced_followers 2وبهذا، تكون قد أعددت بنجاح عنقود ClickHouse يضم شريحتين ونسخة متماثلة واحدة لكل شريحة. في الخطوة التالية، ستُنشئ جدولًا في العنقود.
أنشئ قاعدة بيانات
الآن بعد أن تحققت من أن العنقود مُعَدّ بشكل صحيح ويعمل، ستعيد إنشاء الجدول نفسه المستخدم في الدليل العملي الخاص بمجموعة البيانات النموذجية UK property prices. ويتكوّن من نحو 30 مليون صف لأسعار العقارات المدفوعة في إنجلترا وويلز منذ عام 1995.
اتصل بعميل كل مضيف بتشغيل كلٍّ من الأوامر التالية من علامات تبويب أو نوافذ طرفية منفصلة:
docker exec -it clickhouse-01 clickhouse-client
docker exec -it clickhouse-02 clickhouse-clientيمكنك تشغيل الاستعلام أدناه باستخدام clickhouse-client على كل مضيف للتأكد من
عدم إنشاء أي قواعد بيانات بعد، باستثناء القواعد الافتراضية:
SHOW DATABASES; ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default │
3. │ information_schema │
4. │ system │
└────────────────────┘من عميل clickhouse-01، شغّل استعلام DDL موزّعًا التالي باستخدام عبارة
ON CLUSTER لإنشاء قاعدة بيانات جديدة باسم uk:
CREATE DATABASE IF NOT EXISTS uk
ON CLUSTER cluster_2S_1R;يمكنك تشغيل الاستعلام نفسه مرة أخرى كما سبق من العميل على كل مضيف
للتأكد من أن قاعدة البيانات قد أُنشئت على مستوى العنقود رغم تشغيل
الاستعلام على clickhouse-01 فقط:
SHOW DATABASES; ┌─name───────────────┐
1. │ INFORMATION_SCHEMA │
2. │ default │
3. │ information_schema │
4. │ system │
5. │ uk │
└────────────────────┘إنشاء جدول على العنقود
الآن بعد أن أُنشئت قاعدة البيانات، ستُنشئ جدولًا. شغّل الاستعلام التالي من أي عميل من عملاء المضيف:
CREATE TABLE IF NOT EXISTS uk.uk_price_paid_local
ON CLUSTER cluster_2S_1R
(
price UInt32,
date Date,
postcode1 LowCardinality(String),
postcode2 LowCardinality(String),
type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
is_new UInt8,
duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
addr1 String,
addr2 String,
street LowCardinality(String),
locality LowCardinality(String),
town LowCardinality(String),
district LowCardinality(String),
county LowCardinality(String)
)
ENGINE = MergeTree
ORDER BY (postcode1, postcode2, addr1, addr2);لاحظ أنه مطابق للاستعلام المستخدم في جملة CREATE الأصلية الخاصة بـ
دليل مجموعة البيانات المثال UK property prices،
باستثناء عبارة ON CLUSTER.
صُمِّمت عبارة ON CLUSTER للتنفيذ الموزّع لاستعلامات DDL (لغة تعريف البيانات)
مثل CREATE وDROP وALTER وRENAME، بما يضمن تطبيق
هذه التغييرات على المخطط عبر جميع العقد في العنقود.
يمكنك تشغيل الاستعلام أدناه من عميل كل مضيف للتأكد من أن الجدول قد أُنشئ على مستوى العنقود:
SHOW TABLES IN uk; ┌─name────────────────┐
1. │ uk_price_paid_local │
└─────────────────────┘قبل أن نُدرج بيانات الأسعار المدفوعة في المملكة المتحدة، دعونا نجري تجربة سريعة لمعرفة ما الذي يحدث عند إدراج البيانات في جدول عادي من أيٍّ من الخادمين.
أنشئ قاعدة بيانات وجدولًا اختباريًا باستخدام الاستعلام التالي من أيٍّ من الخادمين:
CREATE DATABASE IF NOT EXISTS test ON CLUSTER cluster_2S_1R;
CREATE TABLE test.test_table ON CLUSTER cluster_2S_1R
(
`id` UInt64,
`name` String
)
ENGINE = MergeTree()
ORDER BY id;الآن، من clickhouse-01، نفّذ استعلام INSERT التالي:
INSERT INTO test.test_table (id, name) VALUES (1, 'Clicky McClickface');انتقل إلى clickhouse-02 ونفّذ استعلام INSERT التالي:
INSERT INTO test.test_table (id, name) VALUES (1, 'Alexey Milovidov');الآن، شغّل الاستعلام التالي من clickhouse-01 أو clickhouse-02:
-- from clickhouse-01
SELECT * FROM test.test_table;
-- ┌─id─┬─name───────────────┐
-- 1.│ 1 │ Clicky McClickface │
-- └────┴────────────────────┘
--from clickhouse-02
SELECT * FROM test.test_table;
-- ┌─id─┬─name───────────────┐
-- 1.│ 1 │ Alexey Milovidov │
-- └────┴────────────────────┘ستلاحظ أنه، بخلاف جدول ReplicatedMergeTree، لا يُعاد إلا الصف الذي أُدرج في الجدول على ذلك
المضيف تحديدًا، وليس كلا الصفين.
لقراءة البيانات عبر الشاردين، نحتاج إلى واجهة يمكنها التعامل مع الاستعلامات عبر جميع الشاردات، مع دمج البيانات من كلا الشاردين عندما ننفّذ استعلامات select عليها، أو إدراج البيانات في كلا الشاردين عندما ننفّذ استعلامات insert.
في ClickHouse تُسمّى هذه الواجهة جدولًا موزعًا، وننشئها باستخدام
محرك الجدول Distributed. لنلقِ نظرة على كيفية عمله.
إنشاء جدول موزّع
أنشئ جدولًا موزّعًا باستخدام الاستعلام التالي:
CREATE TABLE test.test_table_dist ON CLUSTER cluster_2S_1R AS test.test_table
ENGINE = Distributed('cluster_2S_1R', 'test', 'test_table', rand())في هذا المثال، اختيرت الدالة rand() كمفتاح للتجزئة بحيث
تتوزع عمليات الإدراج عشوائيًا على الأجزاء.
الآن نفّذ استعلامًا على الجدول الموزّع من أيٍّ من المضيفين، وستحصل على كلا الصفين اللذين أُدرجا على المضيفين كليهما، بخلاف مثالنا السابق:
SELECT * FROM test.test_table_dist; ┌─id─┬─name───────────────┐
1. │ 1 │ Alexey Milovidov │
2. │ 1 │ Clicky McClickface │
└────┴────────────────────┘لنفعل الأمر نفسه مع بيانات أسعار العقارات في المملكة المتحدة. من أيٍّ من الأجهزة المضيفة التي تشغّل العميل،
شغّل الاستعلام التالي لإنشاء جدول موزّع باستخدام الجدول الحالي
الذي أنشأناه سابقًا باستخدام ON CLUSTER:
CREATE TABLE IF NOT EXISTS uk.uk_price_paid_distributed
ON CLUSTER cluster_2S_1R
ENGINE = Distributed('cluster_2S_1R', 'uk', 'uk_price_paid_local', rand());إدراج البيانات في جدول موزّع
الآن اتصل بأيٍّ من المضيفَين وأدرج البيانات:
INSERT INTO uk.uk_price_paid_distributed
SELECT
toUInt32(price_string) AS price,
parseDateTimeBestEffortUS(time) AS date,
splitByChar(' ', postcode)[1] AS postcode1,
splitByChar(' ', postcode)[2] AS postcode2,
transform(a, ['T', 'S', 'D', 'F', 'O'], ['terraced', 'semi-detached', 'detached', 'flat', 'other']) AS type,
b = 'Y' AS is_new,
transform(c, ['F', 'L', 'U'], ['freehold', 'leasehold', 'unknown']) AS duration,
addr1,
addr2,
street,
locality,
town,
district,
county
FROM url(
'http://prod1.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-complete.csv',
'CSV',
'uuid_string String,
price_string String,
time String,
postcode String,
a String,
b String,
c String,
addr1 String,
addr2 String,
street String,
locality String,
town String,
district String,
county String,
d String,
e String'
) SETTINGS max_http_get_redirects=10;بمجرد إدراج البيانات، يمكنك التحقق من عدد الصفوف باستخدام الجدول الموزع:
SELECT count(*)
FROM uk.uk_price_paid_distributed ┌──count()─┐
1. │ 30212555 │ -- 30.21 million
└──────────┘إذا نفّذت الاستعلام التالي على أيٍّ من المضيفَين، ستلاحظ أن البيانات توزّعت بشكل متساوٍ إلى حدٍّ ما عبر الأجزاء (علمًا بأن اختيار الجزء الذي تُدرج فيه البيانات كان عشوائيًا باستخدام rand()، لذا قد تختلف النتائج لديك):
-- from clickhouse-01
SELECT count(*)
FROM uk.uk_price_paid_local
-- ┌──count()─┐
-- 1. │ 15107353 │ -- 15.11 million
-- └──────────┘
--from clickhouse-02
SELECT count(*)
FROM uk.uk_price_paid_local
-- ┌──count()─┐
-- 1. │ 15105202 │ -- 15.11 million
-- └──────────┘ماذا سيحدث إذا تعطّل أحد المضيفين؟ لنحاكِ هذا السيناريو بإيقاف
clickhouse-01:
docker stop clickhouse-01تحقق من أن المضيف متوقف عن طريق تشغيل:
docker-compose psNAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
clickhouse-02 clickhouse/clickhouse-server:latest "/entrypoint.sh" clickhouse-02 X minutes ago Up X minutes 127.0.0.1:8124->8123/tcp, 127.0.0.1:9001->9000/tcp
clickhouse-keeper-01 clickhouse/clickhouse-keeper:latest-alpine "/entrypoint.sh" clickhouse-keeper-01 X minutes ago Up X minutes 127.0.0.1:9181->9181/tcp
clickhouse-keeper-02 clickhouse/clickhouse-keeper:latest-alpine "/entrypoint.sh" clickhouse-keeper-02 X minutes ago Up X minutes 127.0.0.1:9182->9181/tcp
clickhouse-keeper-03 clickhouse/clickhouse-keeper:latest-alpine "/entrypoint.sh" clickhouse-keeper-03 X minutes ago Up X minutes 127.0.0.1:9183->9181/tcpالآن من clickhouse-02 نفِّذ نفس استعلام select الذي أجريناه سابقًا على الجدول الموزَّع:
SELECT count(*)
FROM uk.uk_price_paid_distributedReceived exception from server (version 25.5.2):
Code: 279. DB::Exception: Received from localhost:9000. DB::Exception: All connection tries failed. Log:
Code: 32. DB::Exception: Attempt to read after eof. (ATTEMPT_TO_READ_AFTER_EOF) (version 25.5.2.47 (official build))
Code: 209. DB::NetException: Timeout: connect timed out: 192.168.7.1:9000 (clickhouse-01:9000, 192.168.7.1, local address: 192.168.7.2:37484, connection timeout 1000 ms). (SOCKET_TIMEOUT) (version 25.5.2.47 (official build))
Code: 198. DB::NetException: Not found address of host: clickhouse-01: (clickhouse-01:9000, 192.168.7.1, local address: 192.168.7.2:37484). (DNS_ERROR) (version 25.5.2.47 (official build))
: While executing Remote. (ALL_CONNECTION_TRIES_FAILED)للأسف، مجموعتنا ليست متسامحة مع الأعطال. إذا تعطّل أحد المضيفين، تُعدّ المجموعة غير سليمة ويفشل الاستعلام، خلافًا للجدول المُكرَّر الذي رأيناه في المثال السابق، والذي كنّا قادرين فيه على إدراج البيانات حتى عند تعطّل أحد المضيفين.
الخاتمة
تتمثل ميزة طوبولوجيا هذا العنقود في أن البيانات تُوزَّع عبر مضيفين منفصلين، مع استخدام نصف سعة التخزين لكل عقدة. والأهم من ذلك أن الاستعلامات تُعالَج عبر كلا الشاردين، مما يحسّن كفاءة استخدام الذاكرة ويقلّل عمليات الإدخال/الإخراج على كل مضيف.
أما العيب الرئيسي لطوبولوجيا هذا العنقود فهو، بطبيعة الحال، أن فقدان أحد المضيفين يجعلنا غير قادرين على معالجة الاستعلامات.
في المثال التالي، سنلقي نظرة على كيفية إعداد عنقود يضم شاردين ونسختين متماثلتين، بما يوفّر قابلية التوسع وتحمّل الأعطال.