I. LỜI NÓI ĐẦU
Dành cho các bạn đọc mới biết đến mình thì mình cũng xin giới thiệu lại, các bài viết của mình sẽ xoay quanh chủ đề liên quan đến các lĩnh vực Backend, Blockchain cũng như DevOps. Ngoài ra, mình cũng viết chia sẻ về suy nghĩ, tâm sự và quan điểm sống trên một vài lĩnh vực về tâm lý học, tài chính và phát triển bản thân.
Quay lại chủ đề lần trước, mình đã chia sẻ đến mọi người tiếp tục bài viết về nguyên lý lý thuyết sharding mongoDB trong chuỗi bài MongoDB mình viết từ 2022. Mọi người có thể tìm đọc lại các bài viết cũ thuộc cùng chuỗi series MongoDB bao gồm:
- Phần 1: cấu hình standalone MongoDB
- Phần 2: cấu hình replica set MongoDB
- Phần 3: nguyên lý triển khai và cấu hình Sharding MongoDB
Vì nội dung khá dài nên mình tách phần sharding MongoDB ra làm 2 bài, và hôm nay chúng ta sẽ tiếp tục đến với phần tiếp theo - Thực chiến triển khai và cấu hình Sharding MongoDB [MongoDB - phần 4].
II. THỰC HÀNH
Trước khi vào phần thực hành, các bạn có thể tìm đọc lại bài viết số 2 trong chuỗi MongoDB để biết cách thiết lập một cụm replica set MongoDB trước nhé.
1. Hướng dẫn các bước thiết lập sharding MongoDB
Step 1 — Thiết lập Config Server MongoDB
- Config Server quản lý metadata và định tuyến dữ liệu trong sharding.
- Khởi tạo một Replica Set Config Server (thường gồm 3 nút để đảm bảo tính sẵn sàng).
Step 2 — Cấu hình Shard Server Replica Sets
- Thiết lập các Replica Sets đại diện cho từng shard.
- Mỗi Replica Set chứa dữ liệu cụ thể trong cluster.
- Triển khai ít nhất 2 Replica Sets cho hiệu quả cân bằng tải.
Step 3 — Chạy
mongos
và thêm Shard vào Cluster- Sử dụng
mongos
làm router để điều phối truy vấn đến shard phù hợp.
- Kết nối
mongos
với Config Server.
- Thêm các shard (Replica Sets) vào cluster thông qua
mongos
.
Step 4 — Phân vùng dữ liệu trong Collection
- Bật chế độ sharding cho database.
- Phân vùng (
shard key
) trên các collection cần sharding, đảm bảo shard key được chọn đúng để tối ưu hóa hiệu suất.
Step 5 — Phân tích mức sử dụng Shard
- Kiểm tra và phân tích shard usage để đảm bảo dữ liệu được phân phối đồng đều.
- Sử dụng lệnh MongoDB như
sh.status()
để giám sát trạng thái sharding.
2. Dockerize sharding MongoDB
Cấu trúc triển khai:
- VPS 1:
- Chứa Config Server và
mongos
. - 1 Shard Replica Set (shard1).
- VPS 2:
- Chứa 1 Shard Replica Set (shard2).
Cài đặt Docker và Docker Compose trên cả hai VPS
- Cài Docker
bash sudo apt update sudo apt install docker.io -y sudo systemctl start docker sudo systemctl enable docker
- Cài Docker Compose
bash sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
Tệp docker-compose.yml
mẫu cho cả 2 VPS
VPS 1: Config Server, mongos, shard1
yaml version: '3.8' services: configsvr: image: mongo:6.0 container_name: configsvr command: --configsvr --replSet configReplSet --bind_ip_all ports: - "27019:27019" volumes: - config_data:/data/db mongos: image: mongo:6.0 container_name: mongos command: > mongos --configdb configReplSet/configsvr:27019 ports: - "27017:27017" depends_on: - configsvr shard1-a: image: mongo:6.0 container_name: shard1-a command: --shardsvr --replSet shard1 --bind_ip_all ports: - "27021:27021" volumes: - shard1_data:/data/db volumes: config_data: shard1_data:
VPS 2: shard2
yaml version: '3.8' services: shard2-a: image: mongo:6.0 container_name: shard2-a command: --shardsvr --replSet shard2 --bind_ip_all ports: - "27022:27022" volumes: - shard2_data:/data/db volumes: shard2_data:
Triển khai
- Chạy Docker Compose trên cả hai VPS
bash docker-compose up -d
- Cấu hình Replica Sets
- Kết nối vào từng container:
- Khởi tạo Replica Set:Tương tự cho shard1 và shard2.
bash docker exec -it <container_name> mongo
javascript rs.initiate({ _id: "configReplSet", members: [{ _id: 0, host: "configsvr:27019" }] })
- Thêm Shard vào Cluster
- Kết nối đến
mongos
: - Thêm Shard:
bash docker exec -it mongos mongo
javascript sh.addShard("shard1/shard1-a:27021") sh.addShard("shard2/shard2-a:27022")
- Bật Sharding cho Database
javascript sh.enableSharding("myDatabase") sh.shardCollection("myDatabase.myCollection", { shardKeyField: 1 })
- Kiểm tra trạng thái Sharding
javascript sh.status()
III. Kinh nghiệm thực chiến
1. Có cần cấu hình Arbiter node cho Sharding?
Trong hệ thống sharding MongoDB, mỗi shard được triển khai dưới dạng một replica set để đảm bảo tính sẵn sàng và khả năng chịu lỗi. Khi triển khai sharding với replica set, câu hỏi đặt ra là liệu có cần thêm arbiter node để tối ưu hóa quá trình bầu chọn và giảm thiểu chi phí?
Khi nào cần Arbiter node trong sharding?
Bạn cần thêm arbiter node trong các trường hợp sau:
- Replica set của shard có số lượng server chẵn:
- Arbiter giúp tạo tổng số phiếu bầu lẻ, đảm bảo hệ thống luôn có thể bầu chọn được primary trong trường hợp mất một số node.
- Ví dụ: Nếu shard có 2 node (A và B), việc mất một node sẽ khiến không đạt được đa số phiếu (1/2 không đủ). Thêm arbiter (C) sẽ giúp tạo 3 phiếu bầu, và chỉ cần 2/3 phiếu để bầu chọn primary.
- Tài nguyên hạn chế:
- Arbiter là một tiến trình nhẹ, không lưu dữ liệu. Điều này giảm chi phí triển khai, đặc biệt trong môi trường cần tối ưu hóa tài nguyên (như EC2 micro instances).
- Hạ tầng phân tán:
- Trong môi trường đa trung tâm dữ liệu hoặc vùng khả dụng (availability zones), arbiter đóng vai trò phân giải tranh chấp khi có hiện tượng chia cắt mạng (network split).
- Ví dụ: Với 4 node (2 ở DC1 và 2 ở DC2), arbiter có thể được triển khai tại DC1 hoặc DC2 để tránh tình trạng dual primary gây xung đột dữ liệu.
Khi nào không cần Arbiter node?
- Replica set có số node lẻ:
- Trong trường hợp này, arbiter là không cần thiết vì hệ thống đã có đủ phiếu bầu lẻ để đảm bảo quá trình bầu chọn primary.
- Yêu cầu về hiệu năng cao:
- Arbiter không lưu dữ liệu, nên nếu một trong các node lưu trữ dữ liệu bị mất, hệ thống sẽ không thể đọc hoặc ghi dữ liệu cho đến khi primary được bầu lại. Điều này có thể làm giảm hiệu năng trong các ứng dụng yêu cầu độ trễ thấp hoặc khối lượng truy vấn lớn.
Lưu ý khi triển khai Arbiter trong sharding
- Không đặt arbiter trên cùng server với các node khác trong replica set:
- Nếu server này bị mất, bạn có thể mất cả primary và arbiter, dẫn đến mất đa số phiếu bầu.
- Không triển khai nhiều hơn 1 arbiter trong mỗi replica set:
- Arbiter chỉ có nhiệm vụ đảm bảo tổng số phiếu lẻ. Việc thêm nhiều hơn 1 arbiter không có ý nghĩa và có thể gây ra lỗi cấu hình.
- Cân nhắc vị trí arbiter khi phân vùng mạng:
- Arbiter nên được đặt tại vị trí trung lập, giữa các khu vực hoặc trung tâm dữ liệu, để đảm bảo khả năng kết nối với các node còn lại.
Nhận xét
- Arbiter là giải pháp hiệu quả để đảm bảo tính sẵn sàng của hệ thống trong các replica set có số lượng server chẵn hoặc tài nguyên hạn chế.
- Trong hệ thống sharding, arbiter node là cần thiết nếu một shard không thể đảm bảo đa số phiếu khi một hoặc nhiều node bị mất.
- Tuy nhiên, arbiter không nên được lạm dụng, và cần được triển khai cẩn thận để tránh rủi ro mất đa số phiếu bầu hoặc lỗi cấu hình.
2. Chiến lược lựa chọn shard key
1. Low-Cardinality Shard Key
Low-cardinality là chiến lược lựa chọn shard key dựa trên một số lượng giới hạn các giá trị duy nhất, ví dụ như các châu lục.
- Ưu điểm: Dễ hình dung và triển khai ban đầu. Ví dụ, bạn có thể chia các shard theo vùng địa lý như:
- (-∞, "Antarctica")
- ["Antarctica", "Asia")
- ["Asia", "Australia")
- ...
- Nhược điểm: Nếu một shard chứa dữ liệu lớn hơn các shard khác (như châu Á có dữ liệu nhiều hơn), hệ thống sẽ gặp khó khăn trong việc tái phân bổ dữ liệu, dẫn đến mất cân bằng tải. Việc sử dụng thêm một trường nữa (ví dụ, kết hợp "châu lục" và "quốc gia") có thể cải thiện tình hình, nhưng cách này thường không tối ưu về lâu dài.
2. Ascending Shard Key
Chiến lược này sử dụng một shard key tăng dần, thường là timestamp hoặc ObjectId, để tối ưu hóa việc truy cập dữ liệu gần đây hơn.
- Ưu điểm:
- Hỗ trợ tốt cho các ứng dụng thường xuyên làm việc với dữ liệu gần đây (như logs hoặc lịch sử giao dịch).
- Khi hệ thống đọc dữ liệu, shard cuối cùng sẽ chứa thông tin mới nhất, dễ dàng truy cập.
- Nhược điểm:
- Dữ liệu mới luôn được ghi vào shard cuối cùng, dẫn đến việc shard đó liên tục phải chia nhỏ.
- Tạo ra tình trạng mất cân bằng tải nghiêm trọng, đặc biệt trong các hệ thống ghi dữ liệu lớn.
3. Random Shard Key
Random shard key sử dụng các giá trị ngẫu nhiên như hash MD5 hoặc các giá trị duy nhất để phân phối dữ liệu.
- Ưu điểm:
- Phân phối dữ liệu đồng đều giữa các shard ngay từ đầu.
- Hạn chế tình trạng tập trung dữ liệu vào một số shard cụ thể.
- Nhược điểm:
- Dữ liệu được phân bố ngẫu nhiên khiến việc truy vấn không thể tối ưu qua index.
- Khi cân bằng lại (rebalancing), MongoDB phải di chuyển chunk ngẫu nhiên, làm tăng thời gian và tài nguyên tiêu thụ.
4. Good Shard Key
Một shard key tốt phải cân bằng giữa khả năng phân mảnh và hiệu suất truy vấn. Đây là sự kết hợp giữa các yếu tố:
- Ascending key: Sử dụng các giá trị thời gian như
date/time
để phân chia dữ liệu theo các khoảng thời gian hợp lý.
- Search key: Kết hợp thêm một trường khác như user hoặc category để tăng khả năng phân phối dữ liệu.
Ví dụ minh họa:
Giả sử một phần mềm cần phân tích dữ liệu của tháng gần nhất:
- Khởi đầu, shard key là
{month, user}
với hai chunk: - (-∞, ∞)
- Khi dữ liệu tăng, chunk được chia thành:
- ((-∞, -∞), ("2011-04", "susan"))
- [("2011-04", "susan"), (∞, ∞)]
- Khi qua tháng mới, dữ liệu tháng trước có thể được lưu trữ ở shard ít sử dụng, giảm tải cho các shard chính.
Ưu điểm:
- Phân phối dữ liệu đều theo thời gian và đối tượng.
- Dữ liệu cũ không cần tái phân phối, giảm thiểu di chuyển chunk không cần thiết.
Nhận xét
- Low-cardinality shard key: Phù hợp với các hệ thống nhỏ, ít thay đổi.
- Ascending shard key: Tốt cho dữ liệu gần đây nhưng cần cải tiến để giảm tải cho shard cuối.
- Random shard key: Đồng đều về phân phối nhưng chậm khi cân bằng lại.
- Good shard key: Sự kết hợp của ascending và search key, đảm bảo cân bằng và hiệu suất lâu dài.
III. LỜI KẾT
Vậy là sau hơn 2 năm kể từ bài viết đầu tiên thuộc chuỗi bài chia sẻ kiến thức về MongoDB, mình cũng hoàn thiện nốt và chính thức khép lại với bài viết chia sẻ về Sharding MongoDB.
Mong là qua bài viết mọi người có thể nắm được các bước cơ bản để tự thiết lập một cụm Sharding MongoDB cũng như là biết được một vài thủ thuật và kinh nghiệm cá nhân của mình trong quá trình thực chiến.
Như đã đề cập trong bài blog hôm trước, sắp tới mình sẽ cố gắng viết đều đặn hơn và tập trung vào các bài viết bằng tiếng anh trên blog cá nhân. Cũng như vẫn sẽ tiếp tục duy trì các chủ đề khác về tài chính, tâm lý học, tư duy cũng như những bài viết tâm sự về góc nhìn cuộc sống.
Nếu thấy thú vị và bổ ích, mọi người có thể để lại cho mình 1 like/upvote hoặc comment để đóng góp ý kiến tiếp thêm động lực cho mình viết thêm nhiều nội dung truyền tải kiến thức chất lượng và thú vị hơn trong tương lai.
IV. TÀI LIỆU THAM KHẢO
- ‣
- ‣