مقدمه
ClickHouse یک سیستم مدیریت پایگاه داده ستونی متنباز است که در انجام پرسوجوهای OLAP با کارایی بالا و تحلیلهای بلادرنگ برتری دارد. با این حال، مقیاسپذیری ذخیرهسازی دادهها برای ClickHouse میتواند چالشبرانگیز باشد، بهویژه وقتی که حجم دادهها رشد میکند. یکی از راهحلهای کارآمد، استفاده از ذخیرهسازی لایهای است، که به شما این امکان را میدهد که دادههای کمدسترس را به سیستم ذخیرهسازی مقرونبهصرفهتر منتقل کنید و در عین حال دادههای پرکاربرد را روی ذخیرهسازی سریعتر و گرانتر نگه دارید. ClickHouse از انواع مختلفی از پشتیبانهای ذخیرهسازی برای دادهها پشتیبانی میکند، از جمله دیسکهای محلی و گزینههای از راه دور مانند DigitalOcean Spaces. هنگام مدیریت حجم زیاد دادهها، معمولاً از چندین دستگاه ذخیرهسازی استفاده میشود.
DigitalOcean Spaces یک سرویس ذخیرهسازی شیء است که میتواند به عنوان یک لایه در معماری ذخیرهسازی لایهای ClickHouse یکپارچه شود. این راهنما شما را از طریق مراحل پیکربندی DigitalOcean Spaces به عنوان یک گزینه ذخیرهسازی لایهای برای کلاستر ClickHouse راهنمایی میکند.
در این راهنما، یک اپلیکیشن ساده Go را راهاندازی خواهیم کرد که لاگهای دستهای را به ClickHouse ارسال میکند. ابتدا، لاگها در ذخیرهسازی داغ (دیسک پیشفرض، که به آن محلی نیز گفته میشود) ذخیره خواهند شد و سپس پس از یک فاصله زمانی مشخص (۲ دقیقه) به ذخیرهسازی سرد (برای مثال، ذخیرهسازی مبتنی بر S3 مانند DO Spaces) منتقل خواهند شد.
پیش نیازها
قبل از شروع، اطمینان حاصل کنید که موارد زیر را دارید:
- یک حساب Cloud در DigitalOcean.
- یک سطل DigitalOcean Spaces.
- کلیدهای دسترسی به DigitalOcean Spaces.
- آشنایی ابتدایی با پیکربندیهای ClickHouse و ذخیرهسازی شیء.
مرحله 1 — ایجاد و پیکربندی یک DigitalOcean Space
وارد حساب Cloud خود در DigitalOcean شوید و یک فضای جدید (سطل) ایجاد کنید. این سطل به عنوان ذخیرهسازی لایهای برای دادههای کمدسترس استفاده خواهد شد.
- به بخش Spaces از داشبورد بروید.
- بر روی “ایجاد فضای جدید” کلیک کنید، نامی را وارد کرده، منطقه را انتخاب کرده و مجوزها را تنظیم کنید.
- آدرس URL نقطه انتهایی (Endpoint URL) را یادداشت کنید.
- کلید دسترسی و کلید مخفی را یادداشت کنید چرا که به آنها در مراحل بعدی نیاز خواهید داشت.
در این مرحله، سطل شما ایجاد شده و آماده یکپارچهسازی با ClickHouse است.
مرحله 2 — راهاندازی سرور ClickHouse در کانتینر Docker
برای شروع، یک پوشه ایجاد کنید و نام آن را “clickhouse” بگذارید.
mkdir clickhouse
یک فایل Dockerfile در این پوشه ایجاد کنید و مقادیر {YOUR_AWS_ACCESS_KEY_ID} و {YOUR_AWS_SECRET_ACCESS_KEY} را با کلید دسترسی و کلید مخفی خود جایگزین کنید.
FROM clickhouse/clickhouse-server:latest
# Copy the config file to the container
COPY storage.xml /etc/clickhouse-server/config.d/storage.xml
# Copy the S3 table creation script
COPY create.sql /docker-entrypoint-initdb.d/
# Set environment variables for S3 credentials
ENV AWS_ACCESS_KEY_ID={YOUR_AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY={YOUR_AWS_SECRET_ACCESS_KEY}
# Expose ClickHouse HTTP and native ports
EXPOSE 8123 9000
USER clickhouse
# --config-file ./programs/server/config.xml
CMD ["clickhouse-server", "--config-file", "/etc/clickhouse-server/config.xml"]
توضیحات:
- access_key_id و secret_access_key: اینها اعتبارنامههای شما برای DigitalOcean Spaces هستند.
هشدار: ما برای سادگی در این راهنما، اعتبارنامهها را در فایل Dockerfile قرار دادهایم، اما این رویکرد در محیطهای تولید توصیه نمیشود.
مرحله 3 — پیکربندی ClickHouse برای ذخیرهسازی سازگار با S3
در این مرحله، ClickHouse را برای استفاده از DigitalOcean Spaces به عنوان یک لایه در سیستم ذخیرهسازی خود پیکربندی خواهید کرد. این کار شامل اضافه کردن پیکربندی ذخیرهسازی به فایل config.xml در نصب ClickHouse است.
برای استفاده از سطل Spaces به عنوان دیسک ذخیرهسازی، ابتدا باید آن را در فایل پیکربندی ClickHouse اعلام کنید. میتوانید فایل config.xml موجود را اصلاح کنید یا ترجیحاً یک فایل جدید در پوشه conf.d اضافه کنید که بعداً به config.xml پیوسته خواهد شد.
<clickhouse> <storage_configuration> <disks> <s3> <type>s3</type> <endpoint>{YOUR_S3_SPACES_BUCKET_URL}</endpoint> <use_environment_credentials>true</use_environment_credentials> </s3> </disks> </storage_configuration> </clickhouse>
این بخش یک دیسک از راه دور (DigitalOcean Space) را پیکربندی میکند که ClickHouse میتواند از آن برای ذخیرهسازی دادههای کمدسترس استفاده کند.
توجه: مقادیر {YOUR_S3_SPACES_BUCKET_URL} را با URL نقطه انتهایی خود جایگزین کنید.
مرحله 4 — ایجاد یک جدول با ذخیرهسازی لایهای
حال، یک جدول در ClickHouse ایجاد کنید که از ذخیرهسازی لایهای استفاده کند. شما میتوانید چندین سیاست ذخیرهسازی را مشخص کنید تا تعیین کنید کدام دادهها در دیسکهای محلی ذخیره شوند و کدامها در دیسکهای از راه دور (Spaces) ذخیره شوند.
یک سیاست ذخیرهسازی تعریف کنید که دادههای قدیمیتر را پس از مدت زمان مشخص به DigitalOcean Spaces منتقل کند:
CREATE TABLE IF NOT EXISTS tiered_logs (
event_time DateTime,
level String,
message String
) ENGINE = MergeTree
ORDER BY (event_time)
TTL toDateTime(event_time) + INTERVAL 2 MINUTE TO VOLUME 'cold'
SETTINGS storage_policy = 's3_tiered';
توضیحات:
- default: این ذخیرهسازی دیسک محلی است که دادههای اخیر یا پرکاربرد در آن ذخیره میشوند.
- s3: ذخیرهسازی از راه دور (DigitalOcean Spaces) است که دادههای قدیمیتر به آن منتقل میشوند.
این پیکربندی تضمین میکند که دادههای جدید به دیسک محلی نوشته شده و دادههای قدیمیتر به طور خودکار به DigitalOcean Spaces منتقل میشوند.
مرحله 5 — اجرای سرور ClickHouse
برای شروع سرور ClickHouse، دستور زیر را اجرا کنید:
docker build -t clickhouse-demo .
docker run -d --name clickhouse-demo -p 8123:8123 -p 9000:9000 clickhouse-demo
پورت های شبکه
- 8123: این پورت HTTP است که برای برقراری ارتباط با ClickHouse از طریق رابط HTTP استفاده می شود. (http://localhost:8123/play). می توانید از این پورت برای اجرای پرس و جوهای SQL از طریق مرورگر یا از طریق ابزارهای خط فرمان مانند curl یا Postman استفاده کنید. اغلب برای برنامه های کاربردی وب یا کلاینت هایی که با ClickHouse از طریق HTTP تعامل دارند استفاده می شود.
- 9000: این پورت TCP، پورت اصلی برای کلاینت ها و سرورهای ClickHouse است تا با استفاده از پروتکل اصلی ClickHouse با یکدیگر ارتباط برقرار کنند.
- مرجع: https://clickhouse.com/docs/en/guides/sre/network-ports
تأیید با استفاده از:
docker ps
مرحله 6 — اجرای یک برنامه ساده Go که لاگها را ارسال میکند
در یک پوشه جدید، یک فایل به نام main.go
ایجاد کنید که لاگها را به ClickHouse ارسال کند.
package main
import (
"database/sql"
"fmt"
"log"
"os"
"time"
"github.com/ClickHouse/clickhouse-go"
"github.com/sirupsen/logrus"
)
type ClickHouseHook struct {
db *sql.DB
entries []logrus.Entry
batchSize int
}
// NewClickHouseHook establishes a connection to ClickHouse using the provided DSN.
func NewClickHouseHook(dsn string, batchSize int) (*ClickHouseHook, error) {
db, err := sql.Open("clickhouse", dsn)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
if exception, ok := err.(*clickhouse.Exception); ok {
log.Fatalf("[%d] %s \n%s\n", exception.Code, exception.Message, exception.StackTrace)
} else {
log.Fatal(err)
}
}
return &ClickHouseHook{db: db, batchSize: batchSize}, nil
}
// Fire is triggered by Logrus to log entries to ClickHouse.
func (hook *ClickHouseHook) Fire(entry *logrus.Entry) error {
hook.entries = append(hook.entries, *entry)
if len(hook.entries) >= hook.batchSize {
if err := hook.flush(); err != nil {
return err
}
}
return nil
}
// flush sends the collected log entries to ClickHouse in a batch.
func (hook *ClickHouseHook) flush() error {
tx, err := hook.db.Begin()
if err != nil {
return err
}
stmt, err := tx.Prepare("INSERT INTO tiered_logs (event_time, level, message) VALUES (?, ?, ?)")
if err != nil {
return err
}
defer stmt.Close()
for _, entry := range hook.entries {
if _, err := stmt.Exec(entry.Time, entry.Level.String(), entry.Message); err != nil {
return err
}
}
if err := tx.Commit(); err != nil {
return err
}
// Clear the entries after flushing
hook.entries = nil
return nil
}
// Levels returns the logging levels for which the hook is triggered.
func (hook *ClickHouseHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func main() {
// ClickHouse DSN (replace with your credentials and host)
dsn := "tcp://localhost:9000?database=default&username=default&password=&debug=true"
// Create ClickHouse hook with a batch size of 5
hook, err := NewClickHouseHook(dsn, 5)
if err != nil {
log.Fatalf("failed to connect to ClickHouse: %v", err)
}
defer hook.db.Close()
// Set up logrus
logger := logrus.New()
logger.Out = os.Stdout
logger.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
})
logger.AddHook(hook)
// Log some entries
for i := 0; i < 10; i++ {
logger.WithFields(logrus.Fields{
"iteration": i,
}).Info("This is an info log entry")
time.Sleep(time.Second)
}
// Flush any remaining log entries before exiting
if err := hook.flush(); err != nil {
log.Fatalf("failed to flush logs to ClickHouse: %v", err)
}
fmt.Println("Logs sent to ClickHouse.")
}
برای نصب وابستگیهای پکیج:
go mod init example.com/clickhouse-logging
go get github.com/ClickHouse/clickhouse-go
go get github.com/sirupsen/logrus
برای اجرای اپلیکیشن:
go run main.go
مرحله 7 — تایید نتایج
برای شروع کلاینت ClickHouse، دستور زیر را اجرا کنید:
docker exec -it clickhouse-demo clickhouse-client
برای تایید لاگها در کلاستر ClickHouse:
SELECT * FROM tiered_logs
هنگام بررسی دیسک ذخیره سازی برای این ورودی گزارش، می بینیم که روی دیسک پیش فرض (محلی) – که به عنوان ذخیره سازی داغ نیز شناخته می شود – ذخیره می شود.
SELECT name, disk_name FROM system.parts WHERE table = 'tiered_logs';
پس از فاصله دو دقیقه ای مشخص شده در پرس و جو CREATE TABLE، می توانید بررسی کنید که این گزارش ها به دیسک های S3 (سطل راه دور/فضا) منتقل شده اند – که به آن ذخیره سازی سرد نیز می گویند.
همچنین میتوانیم در DigitalOcean Cloud UI ببینیم که سطل ما اکنون حاوی دادههایی است:
نتیجه
با دنبال کردن این راهنما، شما بهطور موفقیتآمیز DigitalOcean Spaces را به عنوان یک گزینه ذخیرهسازی لایهای برای ClickHouse پیکربندی کردهاید. این پیکربندی به شما این امکان را میدهد که هزینههای ذخیرهسازی را بهینه کنید و عملکرد را با انتقال دادههای کمدسترس به ذخیرهسازی شیء مقرونبهصرفه بهبود بخشید، در حالی که ذخیرهسازی با عملکرد بالا برای دادههای فعال حفظ میشود.