1. Tổng quan và Nguyên lý Hoạt động
etcd là một hệ thống lưu trữ dữ liệu dạng key-value phân tán, được phát triển ban đầu bởi CoreOS và hiện là thành phần cốt lõi trong các nền tảng container như Kubernetes. Dự án này được xây dựng bằng ngôn ngữ Go và sử dụng giao thức Raft để đảm bảo tính nhất quán mạnh mẽ giữa các node trong cụm.
1.1 Đặc điểm nổi bật
- Dễ sử dụng: Cung cấp giao diện HTTP RESTful chuẩn, quy trình cài đặt và cấu hình đơn giản.
- Bảo mật cao: Hỗ trợ xác thực qua chứng chỉ SSL/TLS cho cả kết nối client và peer.
- Hiệu năng tốt: Benchmark chính thức cho thấy khả năng xử lý hàng nghìn yêu cầu đọc mỗi giây trên một instance đơn.
- Độ tin cậy: Dựa trên thuật toán Raft, etcd đảm bảo dữ liệu luôn đồng bộ và sẵn sàng ngay cả khi có node bị lỗi.
1.2 Các thuật ngữ cốt lõi
- Raft: Thuật toán đồng thuận phân tán đảm bảo tính nhất quán.
- Member/Node: Một tiến trình etcd chạy trên máy chủ, tham gia vào quá trình đồng thuận.
- Cluster: Tập hợp nhiều member hoạt động phối hợp với nhau.
- Leader/Follower/Candidate: Các trạng thái của node trong chu kỳ Raft. Leader xử lý ghi, Follower nhận replication, Candidate tham gia bầu chọn khi mất kết nối với Leader.
- WAL (Write-Ahead Log): Định dạng nhật ký ghi trước nhằm đảm bảo dữ liệu không bị mất khi xảy ra sự cố phần cứng.
- Snapshot: Bản chụp trạng thái hệ thống định kỳ để giảm tải cho WAL.
1.3 Luồng dữ liệu và Bầu chọn Leader
Mô hình ghi dữ liệu trong etcd là đơn hướng: mọi lệnh ghi đều phải đi qua Leader. Sau khi ghi thành công, Leader sẽ replicating các entry này tới các Follower. Dữ liệu chỉ được coi là cam kết (committed) khi đa số các node xác nhận nhận được. Cụ thể, với N node, ngưỡng cam kết là Quorum = N/2 + 1. Do đó, cụm sản xuất khuyến nghị tối thiểu 3 node để chịu được 1 node hỏng mà không mất khả năng hoạt động.
Quá trình bầu chọn Leader dựa trên cơ chế vote ngẫu nhiên (election timeout). Khi một node không nhận được heartbeat từ Leader trong khoảng thời gian định trước, nó sẽ chuyển sang trạng thái Candidate và yêu cầu bầu chọn. Node nhận được đa số phiếu sẽ trở thành Leader mới và bắt đầu gửi heartbeat để duy trì quyền kiểm soát.
2. Kiến trúc nội bộ
etcd được thiết kế theo kiến trúc phân lớp, bao gồm bốn thành phần chính tương tác chặt chẽ:
- HTTP Server: Tiếp nhận yêu cầu từ client (API requests) và giao tiếp giữa các peer (heartbeat, replication).
- Store: Lớp xử lý nghiệp vụ, quản lý cây key-value, theo dõi chỉ mục (index), xử lý sự kiện và TTL.
- Raft Core: Não bộ của hệ thống, thực hiện đồng thuận, quản lý vòng đời các term và điều phối việc bầu chọn.
- WAL & Snapshot: Cơ chế lưu trữ bền vững. Mọi thay đổi trạng thái đều được ghi vào WAL trước khi cập nhật vào bộ nhớ và Snapshot. Cơ chế này giúp hệ thống có thể khôi phục nhanh chóng sau khi khởi động lại.
Khi một client gửi yêu cầu ghi, HTTP Server sẽ chuyển tới Store. Store đóng gói yêu cầu thành một proposal và gửi tới Raft module. Raft thực hiện đồng thuận, sau đó dữ liệu được ghi vào WAL, cập nhật vào bộ nhớ trong, và cuối cùng phản hồi lại client. Các node khác trong cụm sẽ nhận entry này qua stream replication và ghi vào WAL của chúng.
3. Các kịch bản ứng dụng phổ biến
- Đăng ký và Phát hiện dịch vụ: Các microservice đăng ký địa chỉ IP và port lên etcd. Load balancer hoặc service mesh lắng nghe thay đổi để định tuyến lưu lượng động.
- Xuất bản và Đăng ký tin nhắn (Pub/Sub): Producer ghi tin nhắn vào key chỉ định, Consumer sử dụng cơ chế watch để nhận thông báo khi dữ liệu thay đổi.
- Cân bằng tải động: Tự động phát hiện node mới tham gia hoặc node lỗi để điều chỉnh pool xử lý mà không cần restart.
- Khóa phân tán (Distributed Lock): Sử dụng cơ chế
CreatehoặcCompare-and-Swapđể đảm bảo chỉ một tiến trình duy nhất nắm giữ tài nguyên tới cùng một thời điểm. - Hàng đợi phân tán & Điều phối công việc: Tạo các key có thứ tự để mô phỏng hàng đợi, kết hợp với watch để phân phối task cho các worker node.
4. Cài đặt và Cấu hình Cụm 3 Node
Để đảm bảo độ tin cậy, triển khai cụm lẻ node (3, 5, 7...) là tiêu chuẩn khuyến nghị. Dưới đây là quy trình cài đặt cụm 3 node trên CentOS/RHEL.
4.1 Chuẩn bị môi trường
| Hostname | IP Address | Vai trò |
|---|---|---|
| etcd-node-1 | 10.20.30.101 | etcd member |
| etcd-node-2 | 10.20.30.102 | etcd member |
| etcd-node-3 | 10.20.30.103 | etcd member |
Trên tất cả các máy, cập nhật danh sách hosts:
echo "10.20.30.101 etcd-node-1
10.20.30.102 etcd-node-2
10.20.30.103 etcd-node-3" | tee -a /etc/hosts
4.2 Cài đặt package
sudo yum install -y epel-release
sudo yum install -y etcd
sudo systemctl enable etcd
4.3 Cấu hình từng node
Chỉnh sửa file /etc/etcd/etcd.conf. Cấu hình cho etcd-node-1:
ETCD_DATA_DIR="/var/lib/etcd/data"
ETCD_LISTEN_PEER_URLS="http://10.20.30.101:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://10.20.30.101:2379"
ETCD_NAME="etcd-node-1"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.20.30.101:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://10.20.30.101:2379"
ETCD_INITIAL_CLUSTER="etcd-node-1=http://10.20.30.101:2380,etcd-node-2=http://10.20.30.102:2380,etcd-node-3=http://10.20.30.103:2380"
ETCD_INITIAL_CLUSTER_TOKEN="my-cluster-token"
ETCD_INITIAL_CLUSTER_STATE="new"
Thực hiện tương tự cho node-2 và node-3, chỉ cần thay đổi IP và tên node. Sau đó khởi động dịch vụ trên cả 3 máy:
sudo systemctl start etcd
4.4 Kiểm tra trạng thái cụm
etcdctl --endpoints="http://10.20.30.101:2379" member list -w table
etcdctl --endpoints="http://10.20.30.101:2379" endpoint health -w table
Nếu cả 3 node trả về healthy và có đúng 1 Leader, cụm đã hoạt động bình thường.
5. Thao tác với Dữ liệu qua etcdctl
Từ phiên bản etcd 3.0, công cụ dòng lệnh được nâng cấp lên API v3. Các thao tác cơ bản bao gồm:
5.1 Ghi và Đọc dữ liệu
# Ghi một cặp key-value mới
etcdctl put /app/config/database_host "192.168.1.50"
# Lấy giá trị của key
etcdctl get /app/config/database_host
# Ghi đè giá trị với điều kiện CAS (Compare-And-Swap)
etcdctl put /app/lock/session_id "worker-01" --prev-field=key --prev-value="empty"
5.2 Quản lý Prefix và Directory ảo
# Tạo key với prefix
etcdctl put /queue/tasks/task001 "pending"
# Liệt kê tất cả key trong prefix /queue/tasks
etcdctl get /queue/tasks --prefix --keys-only
# Xóa toàn bộ prefix
etcdctl del /queue/tasks --prefix
5.3 Giám sát thay đổi (Watch)
# Theo dõi thay đổi của một key cụ thể
etcdctl watch /app/status/heartbeat
# Theo dõi toàn bộ namespace và in ra thay đổi liên tục
etcdctl watch / --prefix --forever
# Thực thi lệnh shell khi key thay đổi
etcdctl watch /deploy/trigger --prefix --exec="curl -X POST http://localhost:8080/reload"
5.4 Sao lưu và Khôi phục
# Tạo snapshot backup
etcdctl --endpoints="http://10.20.30.101:2379" snapshot save /backup/etcd-snap.db
# Kiểm tra thông tin snapshot
etcdctl snapshot status /backup/etcd-snap.db -w json
# Khôi phục từ snapshot (dừng dịch vụ etcd trước)
etcdctl snapshot restore /backup/etcd-snap.db --data-dir=/var/lib/etcd/new-data
5.5 Quản lý Member
# Thêm node mới vào cụm đang chạy
etcdctl member add etcd-node-4 --peer-urls="http://10.20.30.104:2380"
# Xóa node cũ ra khỏi cụm
etcdctl member remove <member-id>
6. Hạn chế và Lưu ý khi Sử dụng
etcd được tối ưu hóa cho các workload đọc nhiều, ghi ít. Hệ thống mặc định chỉ lưu giữ một số lượng hạn chế lịch sử sự kiện (revision history) để tối ưu không gian lưu trữ và hiệu năng truy vấn. Do đó, nó không phù hợp làm message queue chịu tải cao hay cơ sở dữ liệu lưu trữ hàng loạt dữ liệu giao dịch.
Trong thực tế, etcd thường đóng vai trò bộ não điều phối cho các hệ sinh thái container. Để xây dựng cơ chế service discovery hoàn chỉnh, cần kết hợp với các công cụ như consul, confd hoặc các controller của Kubernetes. Ngoài ra, hiện tại etcd chưa tích hợp sẵn giao diện quản trị đồ họa, việc vận hành chủ yếu dựa trên dòng lệnh và các webhook tích hợp bên thứ ba.