Tạp chí Thợ Code

Nắm tay chỉ cài đặt MongoDB trên hạ tầng của AWS, đảm bảo đầy đủ tính high availability

Thật sự mà nói thì bài này lẽ ra phải lên sóng lâu lắm rồi vì năm xưa đã từng hứa với một đại Idol giấu tên sẽ biên mấy dòng về chủ đề này, “sẽ duyệt bài nhanh cho” anh Hưng giấu tên ân cần nhắn. Sau đó vì nhiều lý do khách quan cũng như chủ quan, cộng với việc tác giả đã xin được hơn mười nghìn Mỹ kim tiền credits cho cả MongoDB Atlas, nên bạn biết đấy, sống đời kham khổ đêm thức khuya ngáp muốn trẹo bản họng ngồi canh traffic lên xuống như canh nước ròng nước lớn để tắt instance rồi sáng dậy sớm bật lên cho tiết kiệm đồng nào hay đồng nấy(*) bỗng dưng được một cục credits tổ chảng rớt cái đùng xuống thì đâu còn động lực để ngồi lọ mọ cài cài cắm cắm config config chi cho cực khổ nữa đâu, cứ xài service cho sướng đời thôi!

Ah, nhưng mà thực tế thì sắp hết credits xài MongoDB Atlas rồi… 😪

Lần đầu viết bài này thì chỉ mới Mongo 6.0, lần này ráng viết tiếp phần kết thì đã có phiên bản 7.0, ôi thời gian nhanh còn hơn chó chạy ngoài đồng.

Poe Assistant viết lại: Trong chặng đường đầu tiên của viết bài này, tôi chỉ mới khởi đầu với phiên bản Mongo 6.0. Nhưng ngay khi tôi cố gắng hoàn thiện phần kết, phiên bản 7.0 đã xuất hiện. Trái tim tôi tràn đầy tiếc nuối khi nhận ra rằng thời gian đã trôi đi nhanh chóng, vượt xa cả sự vụt bước của chó trên đồng cỏ. Tôi hối tiếc vì chưa thể biến những kỳ vọng của mình thành hiện thực.

🌃
Kính chào quý đọc giả, lẽ ra tuần này chúng tôi sẽ tiếp tục với series NhatKyMayMua cùng Chiên Da nhưng vì bận rộn sinh kế trong những tháng cuối năm nên Chiên Da phải chạy KPIs cũng như là làm OKRs nên đã lỡ hẹn cùng quý bạn đọc. Thay vào đó chúng tôi xin đổi gió cùng bạn đọc series Bán Nguyệt San của Thợ Code. *LTS: Nhiều khả năng đoạn này tác giả chém gió quá đà hoặc viết án văn trên trong lúc đã “zô vài ve”! Qua kiểm chứng thực tế của chúng tôi thì rõ ràng tác giả biết dùng AWS CLI aws ec2 stop-instances cùng với Task Scheduler.

MongoDB on AWS: Cài đặt Standalone trên EC2 Instance

Mặc dù AWS đã hỗ trợ NoSQL với 2 dịch vụ là DynamoDB và DocumentDB, trong đó DynamoDB là cơ sở dữ liệu dạng key-value, còn DocumentDB thì cùng một nền tảng với MongoDB. Tuy nhiên, nếu như bạn chỉ muốn đơn giản sử dụng MongoDB trên hạ tầng của AWS để tận dụng sức mạnh mà không cần phải tốn nhiều công sức migration source-code hiện tại thì giải pháp tự cài đặt được trình bày ở bên dưới sẽ rất phù hợp với nhu cầu của bạn.

1. Tạo EC2 Instance

Từ màn hình AWS Console > EC2 > Instances, chọn Launch instances với các tùy chọn sau.

  • Name: Tên instance.
  • Application and OS Images (Amazon Machine Image): Amazon Linux 2 AMI (Free tier). Hiện tại đã có phiên bản Amazon Linux 2023, tuy nhiên qua test thử thì việc cài đặt các package liên quan đến MongoDB vẫn còn khá phức tạp cũng như là phía MongoDB.com họ thông báo chưa hỗ trợ. Cập nhật tại thời điểm tháng 10/2023: MongoDB đã hỗ trợ Amazon Linux 2023 https://www.mongodb.com/docs/manual/installation/#supported-platforms.
  • Instance type: t2.micro (Free tier). Hãy chú ý nếu như không muốn tốn tiền oan! 😂
  • Key pair (login): Chọn key pair sẵn có của bạn hoặc tạo mới tùy.
  • Network settings: Nhớ chú ý việc Allow SSH traffic from Anywhere để có thể SSH vào instance.
2. Cài đặt MongoDB

Sau khi đã khởi tạo xong instance ở trạng thái Running, dùng SSH client nào đó hoặc EC2 Instance Connect để kết nối vào instance vừa được tạo.

Gõ lệnh sau để tạo file mongodb-org-7.0.repo và thêm vào đoạn cấu hình bên dưới để ta có thể cài đặt MongoDB bằng yum. Có thể dùng vi hay nano để tạo/ edit file này đều được.

sudo nano /etc/yum.repos.d/mongodb-org-7.0.repo

[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2023/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-7.0.asc

画像が読み込まれない場合はページを更新してみてください。

Chạy lệnh sau để cài đặt MongoDB sudo yum install -y mongodb-org

Sau khi thấy terminal hiện ra Complete! thì chạy tiếp lệnh mongod --version để kiểm tra xem phiên bản MongoDB được cài đặt thành công.

Tiếp đến, chạy lệnh sudo systemctl start mongod để khởi động các dịch vụ của MongoDB. Xong thì chạy tiếp sudo systemctl status mongod để kiểm tra trạng thái dịch vụ.

画像が読み込まれない場合はページを更新してみてください。
3. Cấu hình & thử nghiệm

Vẫn trên terminal, chạy lệnh mongosh để tiến hành tạo DB, user, insert dữ liệu vào collection customer, đọc dữ liệu vừa instert.

use myDB

db.createUser({user: "admin", pwd: "admin", roles:[{role:"dbAdmin", db: "myDB"}]})

db.customer.insert({name: "Viet-AWS"})

db.customer.find()

画像が読み込まれない場合はページを更新してみてください。

exit() để thoát khỏi mongosh.

Thật không may, ở phiên bản 7.0 này thì ngay khi chạy lên mongosh là gặp lỗi liền

mongosh: OpenSSL configuration error: 00698192257F0000:error:030000A9:digital envelope routines:alg_module_init:unknown option:../deps/openssl/openssl/crypto/evp/evp_cnf.c:61:name=rh-allow-sha1-signatures, value=yes

Để xử lý, chúng ta sẽ chạy 3 lệnh thần thánh bên dưới:

sudo yum remove mongodb-mongosh

sudo yum install mongodb-mongosh-shared-openssl3

sudo yum install mongodb-mongosh

Mặc định, nếu cài từ package như trên thì chúng ta sẽ có 2 thư mục.

  • Dữ liệu /var/lib/mongo
  • Logs /var/log/mongodb

4. Mở đường ra Internet

Trường hợp bạn cần sử dụng các client tool như kiểu MongoDB Compass hay NoSQLBooster hoặc application kết nối MongoDB của bạn đang nằm ở một nơi khác AWS thì đây là những thứ cần phải làm:

  • Vì MongoDB listen port 27017, nên ta cần phải allow port này để có thể kết nối từ bên ngoài.
  • Mở Security Groups của instance vừa tạo và Edit inbound rules, rồi add như minh họa hoặc chỉ với địa chỉ IP mà ta muốn cho phép để đảm bảo an toàn.
画像が読み込まれない場合はページを更新してみてください。
  • Cập nhật lại cấu hình MongoDB: sudo nano /etc/mongod.conf, tìm đến đoạn #network interface và cập nhật bindIp thành 0.0.0.0. Sau đó lưu file và chạy lệnh sudo systemctl restart mongod để khởi động lại MongoDB với cấu hình mới.
画像が読み込まれない場合はページを更新してみてください。

Vậy là xong, bạn có thể thay đổi connection string trong ứng dụng của mình để chuyển sang dùng MongoDB trên hạ tầng AWS.

画像が読み込まれない場合はページを更新してみてください。

MongoDB on AWS: Thiết lập Replica

Để triển khai hệ thống MongoDB trên môi trường production thì gần như bắt buộc phải có cơ chế replica set để đảm bảo:

  1. Dự phòng và độ tin cậy cao: Replica set cho phép sao lưu dữ liệu và duy trì sự nhất quán giữa các bản sao dữ liệu trên các thành viên của replica set. Khi một thành viên gặp sự cố hoặc bị ngắt kết nối, hệ thống vẫn tiếp tục hoạt động bình thường và người dùng vẫn có thể truy cập vào dữ liệu từ các thành viên khác trong replica set.
  2. Tăng cường hiệu suất đọc: Replica set cho phép phân tán yêu cầu đọc dữ liệu qua các thành viên của replica set. Điều này giúp tăng cường khả năng chịu tải và cung cấp khả năng đáp ứng tốt hơn cho các hoạt động đọc dữ liệu.
  3. Khả năng mở rộng: Replica set cung cấp khả năng mở rộng dễ dàng bằng cách thêm các thành viên mới vào replica set. Khi lưu lượng truy cập tăng, bạn có thể thêm các thành viên mới để phân tán công việc và tăng cường khả năng xử lý.
  4. Khả năng phục hồi dữ liệu: Khi có sự cố xảy ra và một thành viên trong replica set bị mất, replica set có khả năng tự động chuyển đổi sang các thành viên khác để tiếp tục hoạt động. Quá trình này được gọi là quá trình bầu cử (election), và nó đảm bảo rằng hệ thống vẫn có thể truy cập và sử dụng dữ liệu mà không bị gián đoạn.
  5. Sao lưu và khôi phục dữ liệu: Replica set cung cấp khả năng sao lưu dữ liệu dựa trên các bản sao dữ liệu trên các thành viên của replica set. Điều này giúp đảm bảo an toàn dữ liệu và khả năng khôi phục dữ liệu khi cần thiết.

Tính năng này có trên các phiên bản MongoDB Atlas/ Enterprise/ Community.

Chiến lược

Một replica set tiêu chuẩn cơ bản sẽ gồm có 3 node (có thể hiểu là thành viên), trong đó có 1 node làm nhiệm vụ voting (trọng tài điều phối khi có sự cố xảy ra), 1 node là node chính, các node còn lại sẽ là node phụ. Tối đa 7 voting, số còn lại sẽ là non-voting node và lên đến 50 node.

Một replica set tiêu chuẩn cơ bản

画像が読み込まれない場合はページを更新してみてください。

Các noode phu sẽ chép dữ liệu oplog của node chính để đồng bộ hóa. Khi có sự cố xảy ra với node chính, một trong các node phụ sẽ “làm trọng tài” để bầu ra một node chính khác thay thế.

画像が読み込まれない場合はページを更新してみてください。

Vẫn có trường hợp voting node chỉ làm trọng tài, không chứa dữ liệu.

画像が読み込まれない場合はページを更新してみてください。

Nói chung, phần này khá hay nhưng hơi lằng nhằng, cần phải request thêm nhiều task research trước khi nhào vô. Bạn đọc quan tâm có thể coi kỹ hình minh họa và giải thích rất chi tiết về Repication tại https://www.mongodb.com/docs/manual/replication/

Khả năng chịu lỗi

Số lượng nodeSố node cần để bầu node chínhKhả năng chịu lỗi
321
431
532
642

Các patterns hãng khuyên dùng:

Cấu hình

Theo chiến lược ở trên, chúng ta sẽ cần có 3 instance, ở phần đầu Cài đặt Standalone trên EC2 Instance chúng ta đã có 1 instance, bạn có thể tiếp tục lặp lại các bước trên để cài 2 instance. Hoặc để nhanh hơn thì bạn cứ tạo AMI Image từ instance hiện tại rồi sau đó Launch Instance from AMI vừa tạo là được.

画像が読み込まれない場合はページを更新してみてください。

Sau khi đã chuẩn bị xong 3 instance, tạm gọi là mongo1, mongo2, mongo3.

Ở instance mongo1, bạn chạy sudo nano /etc/mongod.conf rồi tìm đến dòng # network interfaces, tiến hành thay đổi như sau:

# network interfaces
net:
  port: 27021
  bindIp: 127.0.0.1,ip-x-x-x-x.ap-regionname.compute.internal
replication:
  replSetName: "dbrs"

Trong đó

  • port: 27021 chỉ định port mặc định MongoDB
  • bindIp: 127.0.0.1,ip-x-x-x-x.ap-regionname.compute.internal đoạn ở sau dấu phẩy là Private IP DNS name (IPv4 only).
  • replSetName: "dbrs" chỉ định tên của replicate set

Sau khi đã cấu hình xong thì chạy sudo systemctl restart mongod để khởi động lại MongoDB với cấu hình mới.

Thực hiện tương tự cho các instance mongo2, mongo3, bạn có thể thay đổi giá trị port thành 27022, 27023 để dễ nhận dạng. Chú ý replSetName thì phải cùng một tên.

Sau khi thực hiện xong toàn bộ 3 instance, để test xem đã thông port chưa thì ta có thể dùng Netcat. Mặc định trên Amazon Linux không có package này, cần phải cài thêm bằng lệnh sudo yum install -y nc, nếu có package nào mặc định cũng ngon thì nhờ bà con chỉ giùm tui nghen.

nc -zv ip-x-x-x-x.ap-regionname.compute.internal 27021
nc -zv ip-x-x-x-x.ap-regionname.compute.internal 27022
nc -zv ip-x-x-x-x.ap-regionname.compute.internal 27023

Khởi động replicate set

Quay lại mongo1, chạy mongo shell, lúc này port mặc định đã thay đổi thành 27021 nên cần phải thêm agrument —port chứ không sẽ bị báo lỗi như hình.

mongosh --port 27021

画像が読み込まれない場合はページを更新してみてください。

Gõ đoạn này vào mongo shell.

rsconf = {
	_id: "dbrs",
	members: [
		{ _id: 0, host: "ip-x-x-x-x.ap-regionname.compute.internal:27021" },
		{ _id: 1, host: "ip-x-x-x-x.ap-regionname.compute.internal:27022" },
		{ _id: 2, host: "ip-x-x-x-x.ap-regionname.compute.internal:27023" }
	]
}

Gõ xong thì gõ tiếp rồi Enter: rs.initiate(rsconf);

画像が読み込まれない場合はページを更新してみてください。

Nếu mọi chuyện xuôi chèo mát mái thì lúc này command line sẽ chuyển thành dbrs [direct: secondary] test>

Bạn có thể kiểm tra tình trạng replicate set bằng lệnh rs.status()

画像が読み込まれない場合はページを更新してみてください。

Để ý, lúc này command line đã chuyển thành dbrs [direct: primary] test>. Điều này có nghĩa là voting node đã chọn node này làm node chính.

Thật tuyệt, bây giờ bạn có thể sang mongo2 hoặc mongo3 hay đứng ngay tại mongo1 và kết nối vào replicate set bằng lệnh

mongosh --host dbrs/mongo1-privateIPDNSname:27021,mongo2-privateIPDNSname:27022,mongo3-privateIPDNSname:27023

Thử nghiệm một chút

use myDB db.customer.insert({name: "ThoCode"}) db.customer.find()

Kết

Còn khá nhiều thứ cần phải tiếp tục thực hiện để hệ thống an toàn hơn thí dụ cấu hình keyfile authentication hoặc sử dụng x.509 certificates cho việc authentication vì nếu không thì bất kỳ ai có quyền truy cập vào các instance này đều có thể đơn giản truy cập vào mongo shell.

Cảm ơn sự trợ giúp của Poe Assistant đã góp ý một vài chỗ ở bản nháp, cũng như là Adobe Firefly đã vẽ giùm ảnh minh họa cover theo prompt mà tôi chả hiểu gì cả.

color photo of a MongoDB replica set mechanism consisting of 3 nodes
画像が読み込まれない場合はページを更新してみてください。

Anh Dũng, Sài Gòn tháng 10-2023.