Kết nối Cluster ScyllaDB bằng CQLsh và Driver
Sử dụng CQLsh (Command Line)
Thực hiện: Mở terminal trên node bất kỳ trong cluster (node1, node2 hoặc node3) và chạy lệnh CQLsh để kết nối trực tiếp đến ScyllaDB.
Lý do: CQLsh là công cụ dòng lệnh mặc định của ScyllaDB, tương tự như psql của PostgreSQL. Nó giúp kiểm tra nhanh trạng thái kết nối và thực thi các câu lệnh CQL (Cassandra Query Language) cơ bản mà không cần cài đặt thư viện bên thứ ba.
Kết quả mong đợi: Dòng lệnh chuyển sang prompt cqlsh>, hiển thị phiên bản ScyllaDB và thời gian kết nối.
cqlsh 192.168.1.10 9042
Kết nối bằng Python Driver (scylla-driver)
Thực hiện: Cài đặt thư viện driver chính thức của ScyllaDB và tạo một script Python đơn giản để thiết lập session.
Lý do: Trong môi trường sản xuất, ứng dụng sẽ giao tiếp với Scylla qua driver (Go, Java, Python) thay vì CQLsh. Driver này tự động xử lý việc phát hiện node, cân bằng tải và retry logic.
Kết quả mong đợi: Script chạy thành công, in ra thông báo "Connected to ScyllaDB" và danh sách các keyspace hiện có.
pip install scylla-driver
Tạo file connect.py với nội dung sau:
from scylla import Cluster, Session
from scylla.cluster import Cluster as ScyllaCluster
cluster = ScyllaCluster(contact_points=['192.168.1.10'], port=9042)
session = cluster.connect()
print("Connected to ScyllaDB")
print("Local Keyspaces:", session.cluster.metadata.keyspaces)
cluster.shutdown()
Chạy script:
python3 connect.py
Tạo Keyspace với NetworkTopologyStrategy
Cấu trúc Keyspace cho Production
Thực hiện: Sử dụng CQL để tạo một keyspace mới với chiến lược sao chép NetworkTopologyStrategy.
Lý do: SimpleStrategy chỉ phù hợp cho môi trường test hoặc single-datacenter. NetworkTopologyStrategy là chuẩn bắt buộc cho môi trường Production vì nó cho phép xác định số lượng replica cụ thể cho từng Datacenter (DC), đảm bảo tính sẵn sàng cao (High Availability) khi một DC bị sự cố.
Kết quả mong đợi: Keyspace được tạo thành công, dữ liệu sẽ được phân tán và nhân bản theo cấu hình DC đã định.
CREATE KEYSPACE production_data
WITH replication = {
'class': 'NetworkTopologyStrategy',
'dc1': 3
};
Verify Keyspace
Thực hiện: Liệt kê toàn bộ keyspace và kiểm tra thuộc tính replication của keyspace vừa tạo.
DESCRIBE KEYSPACES;
DESCRIBE KEYSPACE production_data;
Thiết kế Schema Table tối ưu Primary Key
Nguyên tắc thiết kế Primary Key (Partition Key + Clustering Key)
Thực hiện: Tạo bảng user_sessions để lưu lịch sử đăng nhập, sử dụng user_id làm Partition Key và login_time làm Clustering Key.
Lý do: Trong ScyllaDB, Partition Key quyết định dữ liệu được lưu trên node nào (hashing). Clustering Key quyết định thứ tự sắp xếp dữ liệu trong cùng một partition. Thiết kế này tối ưu cho query dạng "Lấy 10 lần đăng nhập gần nhất của một user".
Kết quả mong đợi: Bảng được tạo, dữ liệu tự động phân vùng theo user_id và sắp xếp giảm dần theo thời gian.
USE production_data;
CREATE TABLE user_sessions (
user_id uuid,
login_time timestamp,
ip_address inet,
session_token text,
PRIMARY KEY (user_id, login_time)
) WITH CLUSTERING ORDER BY (login_time DESC)
AND gc_grace_seconds = 864000;
Tạo bảng Logs với Counter Column
Thực hiện: Tạo bảng app_metrics sử dụng loại dữ liệu counter để đếm số lần truy cập API theo ngày.
Lý do: ScyllaDB hỗ trợ atomic counter. Việc nhóm dữ liệu theo ngày (date) làm Partition Key giúp giảm số lượng partition và tối ưu hóa việc ghi (write) cho các ứng dụng logging hoặc metrics.
CREATE TABLE app_metrics (
metric_date date,
api_endpoint text,
request_count counter,
PRIMARY KEY (metric_date, api_endpoint)
) WITH CLUSTERING ORDER BY (api_endpoint ASC);
Import Dữ liệu Mẫu (Bulk Insert)
Chạy Script Python để tạo dữ liệu giả (Mock Data)
Thực hiện: Viết script Python sử dụng scylla-driver để thực hiện hàng nghìn lệnh INSERT đồng thời (async) vào bảng user_sessions.
Lý do: Để kiểm tra hiệu năng ghi (write throughput) và xác nhận cơ chế phân tán dữ liệu (sharding) của cluster. Sử dụng async giúp tận dụng tối đa băng thông mạng và CPU của ScyllaDB.
from scylla.cluster import Cluster
from scylla.query import Statement
from uuid import uuid4
from datetime import datetime, timedelta
import random
cluster = Cluster(contact_points=['192.168.1.10'], port=9042)
session = cluster.connect('production_data')
# Chuẩn bị query chuẩn
insert_query = """
INSERT INTO user_sessions (user_id, login_time, ip_address, session_token)
VALUES (%s, %s, %s, %s)
"""
# Tạo 1000 user và mỗi user có 50 session
num_users = 1000
sessions_per_user = 50
for i in range(num_users):
user_id = uuid4()
for j in range(sessions_per_user):
# Random time trong 30 ngày qua
time_delta = timedelta(days=random.randint(0, 30), hours=random.randint(0, 23))
login_time = datetime.now() - time_delta
# Random IP
ip = f"192.168.{random.randint(1, 255)}.{random.randint(1, 255)}"
token = f"token_{user_id}_{j}"
session.execute(insert_query, (user_id, login_time, ip, token))
print(f"Successfully inserted {num_users * sessions_per_user} records.")
cluster.shutdown()
Verify Dữ liệu đã nhập
Thực hiện: Kiểm tra tổng số lượng bản ghi trong bảng và đếm số lượng partition (unique user_id).
SELECT count(*) FROM user_sessions;
SELECT count(DISTINCT user_id) FROM user_sessions;
Thực hiện Query và Thao tác Dữ liệu
Query theo Partition Key và Clustering Key
Thực hiện: Chọn một user_id cụ thể (đã có trong dữ liệu mẫu) và lấy 10 bản ghi gần nhất.
Lý do: Đây là mẫu truy vấn tối ưu nhất (Point Query + Range Query). ScyllaDB có thể tìm đúng partition ngay lập tức mà không cần quét toàn bộ cluster (full scan).
SELECT * FROM user_sessions
WHERE user_id = '3e7a2b1c-9d8f-4e5a-b6c7-d8e9f0a1b2c3'
LIMIT 10;
Ghi chú: Thay thế UUID trên bằng một UUID thực tế bạn lấy được từ bước verify trước đó.
Update và Delete dữ liệu
Thực hiện: Cập nhật một trường ip_address của một session cụ thể và xóa một session cũ.
Lý do: ScyllaDB yêu cầu Primary Key (bao gồm cả Partition Key và Clustering Key) phải được chỉ định đầy đủ trong mệnh đề WHERE khi thực hiện UPDATE hoặc DELETE. Đây là quy tắc bắt buộc để đảm bảo tính nhất quán dữ liệu (consistency) trong hệ thống phân tán.
-- Update chỉ một bản ghi cụ thể
UPDATE user_sessions
SET ip_address = '10.0.0.1'
WHERE user_id = '3e7a2b1c-9d8f-4e5a-b6c7-d8e9f0a1b2c3'
AND login_time = '2023-10-27 14:30:00+0000';
-- Xóa một bản ghi cụ thể
DELETE FROM user_sessions
WHERE user_id = '3e7a2b1c-9d8f-4e5a-b6c7-d8e9f0a1b2c3'
AND login_time = '2023-10-27 14:30:00+0000';
Verify kết quả Update/Delete
Thực hiện: Query lại bản ghi vừa sửa hoặc xóa để xác nhận trạng thái.
SELECT * FROM user_sessions
WHERE user_id = '3e7a2b1c-9d8f-4e5a-b6c7-d8e9f0a1b2c3'
AND login_time = '2023-10-27 14:30:00+0000';
Kết quả mong đợi: Nếu UPDATE thành công, IP sẽ là 10.0.0.1. Nếu DELETE thành công, kết quả trả về là rỗng (empty).
Điều hướng series:
Mục lục: Series: Triển khai Database phân tán với ScyllaDB trên Ubuntu 24.04
« Phần 3: Triển khai Cluster 3-node và kiểm tra trạng thái hoạt động
Phần 5: Tối ưu hóa hiệu năng: Cấu hình Tuning và Disk I/O »