Chào mọi người,
Sau một chuỗi bài gây nhức đầu về performance, thì hôm nay, chúng ta tạm nghỉ ngơi, để chuyển sang 1 series mới nhé. Đó là về MongoDB. Ở chuỗi bài viết này, chúng ta sẽ cùng xem và thảo luận về những câu hỏi ở mức độ khá khó của MongoDB. Một số câu hỏi trong này mình cũng đã gặp trong lúc phỏng vấn. Mong rằng series này sẽ tiếp tục mang lại giá trị cho các bạn. Bài này lý thuyết khá nhiều, nên nếu chưa có thời gian đọc, hãy bookmark lại nhé!
1. Trình bày về cấu trúc lưu trữ của MongoDB và giải thích cách MongoDB xử lý cơ chế bộ nhớ ảo và bộ nhớ thật (virtual memory and physical memory)
Cấu trúc lưu trữ của MongoDB dựa trên mô hình documents theo định dạng JSON-like. Mỗi document là một bản ghi độc lập chứa các cặp key-value, trong đó key là một chuỗi và value có thể là một kiểu dữ liệu bất kỳ.
MongoDB xử lý cơ chế bộ nhớ ảo và bộ nhớ thật bằng cách sử dụng hệ điều hành để quản lý việc cung cấp bộ nhớ cho nó:
-
Bộ nhớ ảo (Virtual Memory): Bộ nhớ ảo là một khái niệm mà hệ điều hành cung cấp để cho phép quản lý dữ liệu vượt ra ngoài bộ nhớ thật của hệ thống. Hệ điều hành sẽ tạo ra một không gian địa chỉ ảo lớn hơn khả năng bộ nhớ thật và ánh xạ các phần dữ liệu từ ổ cứng vào không gian địa chỉ này. Việc sử dụng bộ nhớ ảo cho phép ứng dụng nhìn thấy dữ liệu như nó đang được lưu trữ trong bộ nhớ, mặc dù thực tế nó có thể nằm trong ổ cứng.
-
Bộ nhớ thật (Physical Memory): Bộ nhớ thật là bộ nhớ vật lý có sẵn trên hệ thống, bao gồm RAM (Random Access Memory) và bộ nhớ cache. Bộ nhớ thật được sử dụng để lưu trữ các dữ liệu và mã chương trình mà hệ thống đang sử dụng và xử lý. Truy cập vào bộ nhớ thật nhanh hơn so với truy cập vào bộ nhớ ảo, vì không cần truy xuất đĩa để đọc dữ liệu.
Trong MongoDB, khi một truy vấn được thực hiện, MongoDB sẽ cố gắng đưa dữ liệu cần thiết từ ổ cứng vào bộ nhớ ảo. Quá trình này gọi là quá trình "paging in". MongoDB sử dụng một cơ chế bộ nhớ đệm (buffer cache) để lưu trữ dữ liệu được truy cập gần đây trong bộ nhớ thật. Việc sử dụng bộ nhớ đệm giúp tăng tốc độ truy xuất dữ liệu, vì dữ liệu không cần phải được đọc từ ổ cứng mỗi lần truy cập.
2. MongoDB sử dụng Wire Protocol để truyền tải dữ liệu. Hãy trình bày chi tiết về cấu trúc của gói tin Wire Protocol và các loại thông điệp trong giao thức này.
Wire Protocol là giao thức mạng được MongoDB sử dụng để truyền tải dữ liệu giữa client và server. Giao thức này xác định cấu trúc của các gói tin dữ liệu và các loại thông điệp được sử dụng trong quá trình truyền tải.
Cấu trúc của gói tin Wire Protocol: Gói tin Wire Protocol được chia thành hai phần: header và body.
- Header chứa các thông tin quan trọng như độ dài của gói tin, mã báo hiệu (Opcodes) xác định loại thông điệp, các thuộc tính và mã xác thực.
- Body chứa dữ liệu thực tế được truyền tải, ví dụ: các câu lệnh truy vấn, dữ liệu để cập nhật, kết quả truy vấn, ...
Một số Opcodes có thể kể đến như:
- Query (OP_QUERY): Thông điệp này được sử dụng để truy vấn dữ liệu từ MongoDB. Nó chứa câu lệnh truy vấn, các tiêu chí tìm kiếm và các tùy chọn khác.
- Update (OP_UPDATE): Thông điệp này được sử dụng để cập nhật dữ liệu trong MongoDB. Nó chứa câu lệnh cập nhật, các tiêu chí tìm kiếm và các tùy chọn khác.
- Insert (OP_INSERT): Thông điệp này được sử dụng để chèn dữ liệu mới vào MongoDB. Nó chứa dữ liệu mới được chèn vào và các tùy chọn khác.
- Delete (OP_DELETE): Thông điệp này được sử dụng để xóa dữ liệu khỏi MongoDB. Nó chứa các tiêu chí tìm kiếm để xác định các bản ghi cần xóa.
- Get More (OP_GETMORE): Thông điệp này được sử dụng để lấy thêm kết quả truy vấn khi kết quả ban đầu không đủ.
- Kill Cursors (OP_KILL_CURSORS): Thông điệp này được sử dụng để kết thúc các con trỏ (cursor) đang được sử dụng để duyệt kết quả truy vấn.
Chi tiết hơn, các bạn có thể đọc thêm tại: MongoDB Wire Protocol
3. Giải thích khái niệm sharding trong MongoDB. Trình bày các cách thức triển khai sharding và lợi ích của việc sử dụng sharding trong môi trường MongoDB.
Sharding là một khái niệm quan trọng trong MongoDB để mở rộng khả năng lưu trữ và xử lý dữ liệu. Nó cho phép phân tán dữ liệu trên nhiều máy chủ (server) để đạt được hiệu suất và khả năng mở rộng tốt hơn.
Giải thích cách thức triển khai sharding trong MongoDB:
-
Shard: Shard là một tập hợp các máy chủ MongoDB, mỗi máy chủ lưu trữ một phần của dữ liệu. Các shard được cấu hình để làm việc cùng nhau như một hệ thống phân tán.
-
Metadata Server: Metadata Server (config server) duy trì thông tin về cấu trúc và phân phối dữ liệu trên các shard. Nó lưu trữ metadata về các tập con dữ liệu (chunks) và vị trí của chúng trên các shard.
-
Router: Router (mongos) là giao diện truy cập dữ liệu của client. Nó chịu trách nhiệm định tuyến các truy vấn và yêu cầu từ client đến các shard tương ứng.
-
Chunk: Chunk là một phần của dữ liệu được chia nhỏ và phân phối trên các shard. Mỗi chunk có kích thước cố định và chứa một phạm vi giá trị khóa (range). Các chunk được tự động di chuyển và cân bằng giữa các shard để đảm bảo sự phân phối đồng đều và tối ưu hóa hiệu suất.
Các lợi ích của việc sử dụng sharding trong môi trường MongoDB:
-
Mở rộng khả năng lưu trữ: Sharding cho phép lưu trữ dữ liệu trên nhiều shard, giúp mở rộng dung lượng lưu trữ của hệ thống và xử lý được lượng dữ liệu lớn hơn.
-
Tăng hiệu suất truy vấn: Dữ liệu được phân tán trên nhiều shard, giúp chia sẻ khối lượng công việc và tăng khả năng xử lý song song. Điều này giúp tăng tốc độ truy vấn và giảm thời gian phản hồi.
-
Tăng khả năng mở rộng: Khi nhu cầu tăng cường xử lý hoặc lưu trữ, ta có thể dễ dàng thêm shard mới vào hệ thống, giúp mở rộng khả năng mà không làm gián đoạn hoạt động của hệ thống.
-
Dự phòng và khả năng chịu lỗi: Sharding cung cấp khả năng sao lưu và khả năng chịu lỗi thông qua sao lưu dữ liệu trên các shard khác nhau. Nếu một shard gặp sự cố, các shard khác vẫn có thể hoạt động bình thường.
-
Tối ưu hóa tài nguyên: Sharding cho phép phân chia khối lượng công việc trên nhiều máy chủ, giúp tận dụng tối đa tài nguyên và cân bằng tải.
Chi tiết hơn, các bạn có thể đọc thêm tại: MongoDB Sharding
4. Trình bày về cơ chế Replication trong MongoDB. Hãy nêu rõ quá trình hoạt động của Replication, các khái niệm như Primary, Secondary và Arbiter, cũng như cách MongoDB đảm bảo tính nhất quán của dữ liệu.
Cơ chế Replication trong MongoDB là quá trình sao chép và đồng bộ dữ liệu giữa các bản sao của cùng một cơ sở dữ liệu MongoDB trên các máy chủ khác nhau. Replication cung cấp tính sẵn sàng cao, khả năng chịu lỗi và khả năng mở rộng trong môi trường MongoDB.
Quá trình hoạt động của Replication:
Primary và Secondary:
- Trong một Replica Set, một nút được chọn làm Primary và các nút khác là Secondary.
- Primary nhận và xử lý các yêu cầu ghi (write) từ client. Nó cũng là nút duy nhất có quyền thay đổi dữ liệu trong Replica Set. Secondary nhận các bản sao dữ liệu từ Primary và cập nhật dữ liệu của mình để đồng bộ với Primary.
Replication process:
- Khi một yêu cầu ghi được gửi tới Primary, nó sẽ ghi dữ liệu vào bộ nhớ và gửi các write messages cho các Secondary.
- Các Secondary nhận các thông điệp ghi từ Primary và áp dụng dữ liệu mới vào cơ sở dữ liệu của mình.
- Các Secondary cũng gửi lại thông báo xác nhận (acknowledgement) cho Primary để xác nhận rằng dữ liệu đã được nhận và áp dụng thành công.
- Primary sẽ chờ đến khi nhận được xác nhận từ tất cả các Secondary để xác định rằng dữ liệu đã được đồng bộ trên toàn bộ Replica Set.
Arbiter:
Trong một Replica Set, có thể có một Arbiter, đó là một nút đặc biệt không lưu trữ dữ liệu và chỉ tham gia vào quá trình bầu cử (election) để chọn Primary khi Primary hiện tại gặp sự cố. Arbiter đảm bảo tính nhất quán của Replica Set bằng cách tham gia vào quá trình quyết định nút nào sẽ là Primary.
Tính nhất quán của dữ liệu:
MongoDB đảm bảo tính nhất quán của dữ liệu trong Replica Set bằng cách sử dụng một giao thức bầu cử để chọn Primary và đồng bộ dữ liệu trên các Secondary. Khi Primary gặp sự cố, các Secondary tổ chức một quá trình bầu cử để chọn một Secondary mới làm Primary. Quá trình bầu cử này đảm bảo rằng chỉ có một Primary hoạt động tại một thời điểm, giữ cho Replica Set có tính nhất quán.
Chi tiết hơn, các bạn có thể đọc thêm tại: MongoDB Replication
5. MongoDB cung cấp các tính năng khái quát hóa dữ liệu (data modeling). Hãy so sánh và đánh giá sự khác nhau giữa việc sử dụng Embedding và việc sử dụng Referencing trong mô hình khái quát hóa dữ liệu MongoDB.
Trong MongoDB, có hai cách thức phổ biến để khái quát hóa dữ liệu: Embedding (nhúng) và Referencing (tham chiếu). Cả hai cách thức này đều có ưu điểm và hạn chế riêng, và cần được lựa chọn phù hợp với yêu cầu cụ thể của ứng dụng.
Embedding (Nhúng):
- Embedding là cách thức nhúng dữ liệu của một đối tượng vào một đối tượng khác trong MongoDB. Thông tin liên quan được lưu trữ cùng với đối tượng chính.
- Embedding phù hợp khi quan hệ giữa các đối tượng là một quan hệ "có" hoặc "thuộc về" (has-a relationship). Ví dụ, trong một hệ thống quản lý khách hàng, thông tin về các đơn hàng có thể được nhúng trực tiếp vào tài khoản khách hàng. Giả sử chúng ta có hai collections trong MongoDB: "users" (người dùng) và "orders" (đơn hàng). Mỗi người dùng có nhiều đơn hàng. Chúng ta có thể nhúng thông tin về các đơn hàng trong tài liệu người dùng:
{ _id: 1, name: "Duc Phuc", orders: [ { order_id: 101, amount: 50 }, { order_id: 102, amount: 75 } ]
}
- Embedding giúp tăng tốc độ truy vấn và giảm số lần truy vấn cần thiết, vì dữ liệu có thể được truy cập trong một truy vấn duy nhất. Tuy nhiên, embedding có hạn chế khi cần cập nhật dữ liệu. Khi dữ liệu được nhúng vào một đối tượng chính, việc cập nhật dữ liệu này trên nhiều đối tượng có thể gây ra việc cập nhật lặp lại và tốn kém.
Referencing (Tham chiếu):
- Referencing là cách thức tham chiếu đến dữ liệu từ một đối tượng khác trong MongoDB. Thông tin liên quan được lưu trữ trong một bản ghi riêng biệt và được tham chiếu từ đối tượng chính thông qua khóa ngoại.
- Referencing phù hợp khi quan hệ giữa các đối tượng là một quan hệ "tham chiếu đến" (refer-to relationship). Ví dụ, trong một hệ thống diễn đàn blog như Viblo, mỗi bài viết có thể tham chiếu đến tác giả của nó thông qua một khóa ngoại tới bản ghi tác giả.
// author
{ _id: 1, name: "Duc Phuc"
} // blogs
{ _id: 101, user_id: 1, title: "This is title", content: "This is content"
}
- Referencing cho phép quản lý dữ liệu một cách linh hoạt và hiệu quả khi cần cập nhật. Thay vì phải cập nhật dữ liệu trên nhiều đối tượng, chỉ cần cập nhật thông tin trong bản ghi tham chiếu. Tuy nhiên, referencing có thể tạo ra nhiều truy vấn để thu thập dữ liệu liên quan từ các bản ghi khác nhau, dẫn đến hiệu năng chậm hơn so với embedding.
Chi tiết hơn, các bạn có thể đọc thêm tại: MongoDB Data Modeling
Như vậy là phần 1 này chúng ta sẽ dừng ở 5 câu hỏi này nhé. Đây chính là 5 câu hỏi mà mình rất hay gặp khi đi phỏng vấn các dự án. Hẹn gặp lại mọi người ở bài sau. Đừng quên upvote nếu bài này hữu ích nhé.