Với khả năng mở rộng linh hoạt, hiệu suất cao, NoSQL đã trở thành lựa chọn hàng đầu cho nhiều doanh nghiệp hiện đại và là kỹ năng cần có cho nhiều vị trí nghề nghiệp. Chính vì thế, để chuẩn bị cho buổi phỏng vấn chuyên môn sắp tới, sau đây là 30+ câu hỏi phỏng vấn NoSQL cần biết.

Đọc bài viết sau để hiểu rõ hơn về:

  • Các câu hỏi phỏng vấn NoSQL cơ bản
  • Các câu hỏi phỏng vấn NoSQL về quản lý và lưu trữ dữ liệu
  • Các câu hỏi phỏng vấn NoSQL về hiệu suất và tối ưu hóa
  • Các câu hỏi phỏng vấn NoSQL về bảo mật
  • Các câu hỏi phỏng vấn NoSQL Integration

Tổng quan về NoSQL

NoSQL (Not Only SQL) là một loại cơ sở dữ liệu phi quan hệ thường được sử dụng để xử lý phi cấu trúc hoặc bán cấu trúc. Khác với cơ sở dữ liệu quan hệ truyền thống (SQL), NoSQL không yêu cầu một schema cố định và thường hỗ trợ khả năng mở rộng theo chiều ngang, phù hợp với các ứng dụng hiện đại như mạng xã hội, hệ thống thương mại điện tử hoặc phân tích dữ liệu lớn.

NoSQL được phát triển để giải quyết các hạn chế của hệ thống SQL trong việc xử lý khối lượng dữ liệu ngày càng tăng, đặc biệt là trong môi trường phân tán. Điểm mạnh của NoSQL bao gồm tính linh hoạt, hiệu suất cao và khả năng mở rộng, giúp đáp ứng tốt hơn nhu cầu của các ứng dụng hiện đại.

Ứng dụng của NoSQL

  • Phân tích dữ liệu lớn (Big Data Analytics): NoSQL được thiết kế để xử lý và phân tích khối lượng dữ liệu khổng lồ từ nhiều nguồn khác nhau, chẳng hạn như log máy chủ, dữ liệu mạng xã hội hoặc cảm biến IoT (Internet of Things). Với khả năng mở rộng ngang và xử lý dữ liệu phi cấu trúc, NoSQL là lựa chọn phù hợp với tính linh hoạt và khả năng tùy chỉnh, cho phép các doanh nghiệp trích xuất thông tin giá trị từ dữ liệu lớn một cách hiệu quả.
  • Xử lý dữ liệu thời gian thực (Real-time Data Processing): Nhiều ứng dụng hiện đại như hệ thống gợi ý, bảng tin mạng xã hội, hoặc các ứng dụng thương mại điện tử yêu cầu xử lý dữ liệu ngay lập tức. NoSQL, đặc biệt là các cơ sở dữ liệu tối ưu cho việc truy xuất tốc độ cao, hỗ trợ xây dựng các ứng dụng có khả năng xử lý luồng dữ liệu và cung cấp phản hồi tức thì.
  • Hệ thống quản lý nội dung (Content Management Systems): CMS thường xử lý các loại dữ liệu đa dạng như văn bản, hình ảnh và video. NoSQL cung cấp sự linh hoạt trong việc lưu trữ và truy xuất các loại dữ liệu này, đồng thời đảm bảo khả năng mở rộng khi khối lượng nội dung ngày càng tăng.
  • Các ứng dụng với yêu cầu mở rộng cao: Trong các hệ thống phân tán toàn cầu hoặc xử lý hàng triệu giao dịch mỗi ngày, NoSQL cung cấp khả năng mở rộng theo chiều ngang, cho phép thêm nhiều máy chủ để tăng hiệu năng mà không làm gián đoạn hệ thống.
  • Hệ thống kết hợp SQL và NoSQL (Hybrid Approaches): Nhiều tổ chức hiện nay áp dụng cách tiếp cận kết hợp, sử dụng SQL cho dữ liệu có cấu trúc và NoSQL cho dữ liệu phi cấu trúc hoặc bán cấu trúc. Cho phép tận dụng sức mạnh của cả hai loại cơ sở dữ liệu để đạt được chiến lược quản lý dữ liệu toàn diện và hiệu quả.

Đọc thêm: NoSQL là gì? Vì sao gọi NoSQL là bước tiến mới trong quản lý dữ liệu?

Các vị trí yêu cầu kỹ năng NoSQL

Với sự bùng nổ của dữ liệu lớn và nhu cầu xử lý dữ liệu phi cấu trúc, các vị trí công việc liên quan đến NoSQL ngày càng trở nên phổ biến trong nhiều lĩnh vực.

Dưới đây là một số vai trò tiêu biểu yêu cầu kỹ năng NoSQL:

  • Quản trị viên cơ sở dữ liệu (Database Administrator – DBA): Quản trị viên cơ sở dữ liệu chịu trách nhiệm quản lý, bảo trì và tối ưu hóa các hệ thống cơ sở dữ liệu, bao gồm cả NoSQL. Các nhà tuyển dụng thường tìm kiếm những ứng viên có kinh nghiệm với các nền tảng như MongoDB, Cassandra hay Redis.
  • Kiến trúc sư dữ liệu (Data Architect): Kiến trúc sư dữ liệu chịu trách nhiệm thiết kế các mô hình dữ liệu, xây dựng hệ thống lưu trữ và phân tích dữ liệu. Kinh nghiệm với NoSQL là một lợi thế lớn khi làm việc với các hệ thống dữ liệu lớn và phức tạp.
  • Nhà khoa học dữ liệu (Data Scientist): Nhà khoa học dữ liệu sử dụng NoSQL để thu thập, phân tích và dự đoán dựa trên dữ liệu lớn và phi cấu trúc. Vị trí này thường yêu cầu khả năng làm việc với các cơ sở dữ liệu NoSQL để xử lý các tập dữ liệu khổng lồ từ nhiều nguồn khác nhau.
  • Lập trình viên phần mềm/ứng dụng (Software/Application Developer): Lập trình viên cần sử dụng NoSQL để thiết kế và triển khai các ứng dụng xử lý dữ liệu phi cấu trúc hoặc bán cấu trúc. Đây là một trong những vị trí phổ biến nhất yêu cầu kỹ năng NoSQL.
  • Kỹ sư dữ liệu (Data Engineer): Kỹ sư dữ liệu chịu trách nhiệm xây dựng và duy trì các data pipelines để thu thập, xử lý và lưu trữ dữ liệu. Kỹ năng làm việc với NoSQL giúp bạn xử lý khối lượng dữ liệu lớn và phức tạp một cách hiệu quả.
  • Chuyên viên DevOps (DevOps Engineer): Trong các môi trường DevOps, NoSQL thường được sử dụng để xây dựng và triển khai các hệ thống phân tán. DevOps Engineer cần hiểu biết về NoSQL để tối ưu hóa hệ thống và đảm bảo hiệu suất.

Các câu hỏi phỏng vấn NoSQL cơ bản

Các loại cơ sở dữ liệu NoSQL gồm những loại nào?

Dựa trên cách tổ chức và lưu trữ dữ liệu, NoSQL được chia thành bốn loại chính:

1. Key-Value Store

Là loại cơ sở dữ liệu lưu trữ dữ liệu dưới dạng cặp khóa-giá trị (key-value), giống như một từ điển. Dữ liệu được truy xuất dựa trên khóa (key), mang lại hiệu suất cao trong việc lưu trữ và truy xuất nhanh.

  • Ưu điểm: Tốc độ truy xuất nhanh, dễ dàng mở rộng theo chiều ngang.
  • Nhược điểm: Khó thực hiện truy vấn phức tạp; chỉ phù hợp cho các ứng dụng đơn giản.

Ứng dụng: Lưu trữ phiên người dùng, bộ nhớ cache.

Ví dụ: Redis, DynamoDB, Riak.

2. Document Store

Cơ sở dữ liệu này lưu trữ dữ liệu dưới dạng tài liệu (document), thường ở định dạng JSON, BSON hoặc XML. Dữ liệu có thể có cấu trúc hoặc không có cấu trúc và rất linh hoạt.

  • Ưu điểm: Linh hoạt, dễ dàng mở rộng; phù hợp với dữ liệu bán cấu trúc.
  • Nhược điểm: Truy vấn phức tạp có thể chậm; yêu cầu thiết kế dữ liệu hợp lý để tránh lặp lại.

Ứng dụng: Các ứng dụng web, thương mại điện tử.

Ví dụ: MongoDB, CouchDB, Amazon DocumentDB.

3. Column-Family Store

Ở loại này, dữ liệu được lưu trữ theo các nhóm cột (column families), trong đó mỗi hàng có thể có các cột khác nhau, không cố định như trong SQL. Mỗi cột có thể lưu trữ nhiều thuộc tính liên quan và dễ dàng mở rộng. Kiểu lưu trữ này thích hợp với các tác vụ phân tích và xử lý dữ liệu lớn.

  • Ưu điểm: Tối ưu cho xử lý dữ liệu lớn và truy vấn theo cột; hiệu năng tốt khi mở rộng.
  • Nhược điểm: Khó khăn trong việc cập nhật dữ liệu thường xuyên; không phù hợp cho dữ liệu có mối quan hệ phức tạp.

Ứng dụng: Hệ thống phân tích dữ liệu lớn, dữ liệu thời gian thực.

Ví dụ: Apache Cassandra, HBase.

4. Graph Database

Cơ sở dữ liệu này tập trung vào việc lưu trữ và quản lý các mối quan hệ phức tạp giữa các đối tượng. Nó sử dụng các nút (nodes) để biểu thị thực thể và cạnh (edges) để biểu thị mối quan hệ giữa chúng.

  • Ưu điểm: Tối ưu cho dữ liệu có mối quan hệ phức tạp; truy vấn mối quan hệ nhanh và linh hoạt.
  • Nhược điểm: Khó mở rộng theo chiều ngang; không phù hợp cho dữ liệu dạng bảng hoặc tài liệu.

Ứng dụng: Mạng xã hội, hệ thống khuyến nghị, phân tích mạng lưới.

Ví dụ: Neo4j, OrientDB.

Cách phân biệt cơ sở dữ liệu Column-Family và Key-Value?

Cơ sở dữ liệu Key-Value và Column-Family đều thuộc nhóm NoSQL, nhưng chúng có cấu trúc dữ liệu, cách lưu trữ và ứng dụng khác nhau.

Tiêu chí Key-value Column-Family
Cấu trúc dữ liệu Dữ liệu được lưu trữ dưới dạng cặp key (khóa) và value (giá trị):

  • Key: Là định danh duy nhất, được dùng để truy cập giá trị tương ứng.
  • Value: Có thể là bất kỳ kiểu dữ liệu nào (văn bản, JSON, nhị phân,..).
Dữ liệu được tổ chức thành các hàng (row) và cột (column), với các cột được nhóm lại column families với:

  • Mỗi hàng có một key (khóa hàng) duy nhất.
  • Các giá trị trong cùng một hàng có thể linh hoạt về số lượng và kiểu cột.
Ví dụ “user123”: {“name”: “Alice”, “age”: 25} Row Key: “user123”  

Column Family: Personal_Info → {“name”: “Alice”, “age”: 25} 

Column Family: Address → {“city”: “Hanoi”, “country”: “Vietnam”}

Cách hoạt động Khi cần truy xuất dữ liệu, người dùng chỉ cần cung cấp khóa (key) để lấy giá trị (value) tương ứng. Hệ thống không quan tâm đến nội dung bên trong giá trị, do đó việc truy vấn chỉ thực hiện được theo khóa. Mỗi Column Family là một nhóm cột có liên quan, được lưu trữ và truy vấn cùng nhau. Dữ liệu có thể được truy vấn linh hoạt dựa trên khóa hàng hoặc các cột cụ thể.
Ưu điểm  Đơn giản và nhanh chóng: Truy cập dữ liệu bằng khóa nên rất hiệu quả, phù hợp với các tác vụ yêu cầu tốc độ cao như lưu trữ phiên (session) hoặc dữ liệu tạm (cache).

Dễ mở rộng: Thiết kế tối giản giúp hệ thống dễ dàng mở rộng theo chiều ngang khi khối lượng dữ liệu tăng lên.

Hiệu quả cho dữ liệu lớn: Tối ưu hóa cho việc lưu trữ và truy xuất dữ liệu trong các hệ thống phân tán.

Truy vấn linh hoạt: Hỗ trợ truy vấn theo cột, giúp xử lý các tập dữ liệu phức tạp hiệu quả.

Nhược điểm – Hạn chế trong truy vấn: Chỉ có thể truy xuất dữ liệu theo khóa, không thể tìm kiếm dựa trên nội dung giá trị.

– Không linh hoạt: Thiếu các tính năng phức tạp như lọc dữ liệu, lập chỉ mục (index), hoặc phân tích dựa trên điều kiện.

– Không phù hợp với các hệ thống cần truy vấn phức tạp

– Phức tạp hơn Key-value: Việc thiết kế dữ liệu trong Column-Family yêu cầu hiểu rõ cách tổ chức và sử dụng dữ liệu để đạt hiệu quả tối ưu.

– Quản lý khó khăn hơn: Hệ thống phức tạp đòi hỏi đội ngũ kỹ thuật có chuyên môn cao.

– Việc tinh chỉnh cấu hình và tối ưu hiệu suất đòi hỏi kiến thức chuyên sâu

Ứng dụng – Lưu trữ phiên người dùng trong ứng dụng web.

– Lưu trữ dữ liệu tạm (cache) để tăng hiệu suất.

– Hệ thống cần xử lý dữ liệu đơn giản với hiệu suất cao.

– Hệ thống xử lý dữ liệu lớn, phân tán (Big Data).

– Ứng dụng thời gian thực như theo dõi hành vi người dùng, dữ liệu IoT (Internet of things).

– Phân tích dữ liệu phức tạp hoặc lưu trữ lịch sử.

Công cụ Redis, DynamoDB (chế độ Key-Value), Riak. Cassandra, HBase.

NoSQL khác biệt gì so với SQL?

Tiêu chí SQL (Relational Database) NoSQL (Non-Relational Database)
Cấu trúc dữ liệu Sử dụng bảng (table), cần schema cố định. Lưu trữ linh hoạt: key-value, document, column, graph.
Tính mở rộng Mở rộng theo chiều dọc (vertical scaling) bằng cách nâng cấp phần cứng (tuy nhiên PostgreSQL hay CockroachDB cũng hỗ trợ mở rộng theo chiều ngang trong một số trường hợp). Mở rộng theo chiều ngang (horizontal scaling) bằng cách thêm nhiều máy chủ.
Hỗ trợ giao dịch Đảm bảo ACID (Atomicity, Consistency, Isolation, Durability). Tuân thủ BASE (Basically Available, Soft State, Eventually Consistent).
Khả năng xử lý dữ liệu lớn Hạn chế trong việc xử lý dữ liệu phi cấu trúc và khối lượng lớn. Phù hợp với dữ liệu phi cấu trúc, bán cấu trúc và dữ liệu lớn.
Truy vấn dữ liệu Sử dụng ngôn ngữ SQL tiêu chuẩn. Truy vấn thông qua API hoặc các ngôn ngữ cụ thể.
Ứng dụng Hệ thống kế toán, ngân hàng, CRM. Mạng xã hội, ứng dụng IoT, phân tích dữ liệu lớn.

Ngoài ra bạn có thể tìm hiểu chi tiết hơn về sự khác biệt giữa SQL vs NoSQL.

Những đặc điểm nổi bật của các cơ sở dữ liệu NoSQL là gì?

Khả năng mở rộng theo chiều ngang (Horizontal Scalability): Cơ sở dữ liệu NoSQL cho phép thêm các máy chủ vào hệ thống để tăng khả năng xử lý mà không cần thay đổi cấu trúc hiện có.

Khả năng lưu trữ dữ liệu phi cấu trúc hoặc bán cấu trúc: NoSQL hỗ trợ các loại dữ liệu linh hoạt như JSON, XM, hoặc tài liệu, phù hợp với ứng dụng không yêu cầu mô hình dữ liệu cố định.

Hiệu suất cao (High Performance): Tối ưu hóa cho các ứng dụng yêu cầu xử lý nhanh với khối lượng lớn dữ liệu và truy cập thường xuyên.

Hỗ trợ nhiều loại mô hình dữ liệu: 

  • Dữ liệu dạng cặp khóa-giá trị (Key-Value Store)
  • Dữ liệu dạng tài liệu (Document Store)
  • Dữ liệu dạng đồ thị (Graph Database)
  • Dữ liệu dạng cột (Column-Family Store)

Tính nhất quán linh hoạt (Flexible Consistency): Cho phép tùy chỉnh mức độ đảm bảo dữ liệu chính xác. Người dùng có thể chọn giữa tính nhất quán cao (mọi người đều thấy dữ liệu mới ngay lập tức) hoặc tính nhất quán cuối cùng (dữ liệu sẽ đồng bộ dần theo thời gian), tùy vào yêu cầu của ứng dụng.

Khả năng xử lý khối lượng dữ liệu lớn (Big Data Ready): Thích hợp cho các hệ thống lưu trữ và phân tích dữ liệu lớn như mạng xã hội, thương mại điện tử và IoT (Internet of things).

Không yêu cầu lược đồ cố định (Schema-less): Cho phép thay đổi cấu trúc dữ liệu dễ dàng mà không cần phải chỉnh sửa cơ sở dữ liệu toàn hệ thống.

Khả năng chịu lỗi cao (Fault Tolerance): Hệ thống tự động sao lưu và chia nhỏ dữ liệu ra nhiều phần để bảo vệ, giúp giảm nguy cơ mất mát dữ liệu nếu xảy ra sự cố.

CAP theorem là gì và vai trò của nó trong NoSQL?

CAP Theorem (định lý CAP) được đưa ra bởi Eric Brewer, mô tả ba thuộc tính cơ bản của một hệ thống phân tán:

  • Consistency (Tính nhất quán): Tất cả các nút trong hệ thống đều thấy cùng một dữ liệu tại cùng một thời điểm.
  • Availability (Tính sẵn sàng): Hệ thống luôn sẵn sàng xử lý yêu cầu từ người dùng, bất kể có lỗi xảy ra ở một số nút.
  • Partition Tolerance (Khả năng chịu phân vùng): Hệ thống vẫn hoạt động bình thường ngay cả khi các nút bị chia cắt do lỗi mạng.

Theo định lý CAP, trong một hệ thống phân tán, chỉ có thể đảm bảo tối đa hai hai trong ba thuộc tính cùng một lúc và phải chấp nhận hy sinh thuộc tính còn lại. Dưới đây là những đánh đổi (trade-off) phổ biến:

CA (Consistency & Availability)

Ví dụ: Redis khi chạy ở chế độ Standalone.

  • Lợi ích: Đảm bảo hệ thống luôn nhất quán, các yêu cầu được xử lý liên tục và chính xác. Luôn sẵn sàng trong môi trường không có phân vùng mạng, phù hợp với các hệ thống nội bộ hoặc môi trường nhỏ gọn.
  • Hy sinh (trade-off): Không thể chịu được lỗi phân vùng mạng; khi xảy ra lỗi mạng, hệ thống có thể ngừng hoạt động.

CP (Consistency & Partition Tolerance)

Ví dụ: MongoDB khi chạy ở chế độ phân tán.

  • Lợi ích: Đảm bảo tất cả các nút trong hệ thống luôn có cùng dữ liệu, đặc biệt quan trọng với các ứng dụng yêu cầu tính chính xác cao, như hệ thống tài chính hoặc quản lý giao dịch.
  • Hy sinh (Trade-off): Giảm tính sẵn sàng khi xảy ra lỗi mạng; nếu một số nút không kết nối được, hệ thống có thể từ chối xử lý yêu cầu để bảo vệ tính nhất quán.

AP (Availability & Partition Tolerance)

Hy sinh một phần tính nhất quán để đảm bảo hệ thống luôn sẵn sàng và chịu được lỗi phân vùng. Ví dụ: Cassandra hoặc DynamoDB.

  • Lợi ích: Đảm bảo hệ thống luôn phản hồi các yêu cầu, ngay cả khi một số nút bị phân vùng hoặc không đồng bộ. Phù hợp với các ứng dụng yêu cầu hiệu suất cao và độ trễ thấp, như mạng xã hội hoặc thương mại điện tử.
  • Hy sinh (Trade-off): Tính nhất quán có thể bị ảnh hưởng, nghĩa là các nút khác nhau trong hệ thống có thể hiển thị dữ liệu không giống nhau ngay lập tức(nhất quán cuối cùng – eventual consistency). Ví dụ, nếu bạn cập nhật dữ liệu ở một nút, nút khác có thể chưa thấy thay đổi đó ngay mà cần thêm thời gian để đồng bộ hóa.

Vai trò của CAP theorem trong NoSQL

CAP Theorem đóng vai trò quan trọng trong việc định hướng thiết kế và lựa chọn cơ sở dữ liệu NoSQL cho các hệ thống phân tán. Bằng cách nêu rõ giới hạn của một hệ thống trong việc đạt được cả tính nhất quán (Consistency), tính sẵn sàng (Availability) và khả năng chịu phân vùng (Partition Tolerance) cùng lúc, định lý này giúp lập trình viên hiểu rõ các ưu tiên cần cân nhắc khi xây dựng ứng dụng.

Định hình kiến trúc hệ thống NoSQL: NoSQL thường tập trung vào Partition Tolerance (PT) vì các hệ thống phân tán cần đảm bảo khả năng hoạt động ngay cả khi gặp sự cố mạng. Tùy vào mục tiêu của ứng dụng, NoSQL có thể chọn ưu tiên:

  • AP (Availability + Partition Tolerance): Đáp ứng yêu cầu về hiệu suất và khả năng sẵn sàng cao, như trong các hệ thống thời gian thực (Cassandra, DynamoDB).
  • CP (Consistency + Partition Tolerance): Đảm bảo tính chính xác của dữ liệu, phù hợp cho các hệ thống tài chính hoặc ứng dụng cần tính toàn vẹn dữ liệu (MongoDB, HBase).

Tối ưu hóa theo nhu cầu của ứng dụng: CAP giúp lập trình viên hiểu rõ những đánh đổi cần thiết. Chẳng hạn, các ứng dụng mạng xã hội có thể chấp nhận nhất quán cuối cùng (eventual consistency) để đạt được tốc độ và tính sẵn sàng cao, trong khi các ứng dụng ngân hàng ưu tiên tính nhất quán mạnh.

Giúp lựa chọn cơ sở dữ liệu phù hợp: CAP Theorem giúp phân loại và chọn NoSQL dựa trên các yêu cầu cụ thể của hệ thống, đảm bảo rằng kiến trúc hệ thống có thể mở rộng và đáp ứng tốt các tình huống lỗi.

Trong NoSQL, tại sao BASE thường được áp dụng thay cho ACID?

ACID là một tập hợp các thuộc tính giúp đảm bảo độ tin cậy và tính toàn vẹn của dữ liệu trong các hệ thống cơ sở dữ liệu truyền thống (như RDBMS). Các thuộc tính bao gồm:

  1. Atomicity (Nguyên tử): Một giao dịch được thực hiện hoàn toàn hoặc không thực hiện gì cả. Không có trạng thái trung gian.
    Ví dụ: Nếu một giao dịch ngân hàng chuyển tiền từ tài khoản A sang B thất bại, số tiền sẽ không bị trừ ở tài khoản A.
  2. Consistency (Nhất quán): Dữ liệu phải luôn tuân theo các quy tắc ràng buộc (constraints). Sau mỗi giao dịch, hệ thống chuyển dữ liệu từ trạng thái nhất quán này sang trạng thái nhất quán khác.
  3. Isolation (Cách ly): Các giao dịch đồng thời không được ảnh hưởng lẫn nhau.
    Ví dụ: Hai giao dịch đọc và ghi dữ liệu phải hoạt động như thể chúng được thực hiện tuần tự.
  4. Durability (Bền vững): Sau khi giao dịch hoàn tất, dữ liệu sẽ được lưu trữ vĩnh viễn, bất kể sự cố xảy ra.

BASE là một mô hình khác, thường được áp dụng trong NoSQL, phù hợp hơn với các hệ thống phân tán và yêu cầu khối lượng dữ liệu lớn. BASE bao gồm:

  • Basically Available (Sẵn sàng cơ bản): Hệ thống luôn sẵn sàng phục vụ, ngay cả khi có lỗi xảy ra hoặc một phần của hệ thống bị mất kết nối. Hệ thống ưu tiên về khả năng phản hồi nhanh nhất có thể, tuy nhiên không đảm bảo tất cả yêu cầu đều thành công.
  • Soft State (Trạng thái tạm thời): Dữ liệu có thể thay đổi theo thời gian do quá trình đồng bộ hóa giữa các nút trong hệ thống, ngay cả khi không có yêu cầu chỉnh sửa nào.
  • Eventual Consistency (Nhất quán cuối cùng): Dữ liệu sẽ trở nên nhất quán sau một khoảng thời gian, nhưng không đảm bảo tính nhất quán ngay lập tức.

Tại sao NoSQL chọn BASE thay vì ACID?

Tiêu chí BASE ACID
Hiệu suất và khả năng mở rộng BASE chấp nhận tính nhất quán cuối cùng để đảm bảo hệ thống luôn hoạt động nhanh và xử lý khối lượng dữ liệu lớn trong thời gian thực. BASE hỗ trợ mở rộng theo chiều ngang (horizontal scaling), tức là bổ sung thêm nhiều máy chủ (nodes), giúp hệ thống dễ dàng mở rộng và phân phối khối lượng lớn dữ liệu ACID yêu cầu các giao dịch phải tuân thủ nguyên tắc nghiêm ngặt, điều này làm giảm tốc độ xử lý trong các hệ thống lớn. ACID thường yêu cầu mở rộng theo chiều dọc (vertical scaling), tức là nâng cấp phần cứng như CPU, RAM cho một máy chủ
Tính sẵn sàng cao (High Availability) BASE ưu tiên tính sẵn sàng, cho phép hệ thống xử lý yêu cầu ngay cả khi không thể đảm bảo dữ liệu hoàn toàn nhất quán ACID thường ưu tiên tính nhất quán hơn tính sẵn sàng, có nghĩa là khi xảy ra lỗi mạng hoặc lỗi giao dịch, hệ thống có thể tạm ngừng hoạt động
Thích hợp cho hệ thống phân tán BASE, với nhất quán cuối cùng (eventual consistency), phù hợp hơn cho các hệ thống cần xử lý dữ liệu trên nhiều nút (nodes) và vùng (regions).

Ngoài ra, các ứng dụng như mạng xã hội, thương mại điện tử, IoT thường yêu cầu tốc độ cao và khả năng mở rộng theo chiều ngang. BASE cho phép hệ thống xử lý hàng triệu yêu cầu mà không bị chậm trễ

Trong các hệ thống NoSQL phân tán, việc đảm bảo tính nhất quán mạnh mẽ (strong consistency) theo ACID là rất khó và tốn kém
Khả năng xử lý Big Data BASE được thiết kế để xử lý Big Data một cách hiệu quả bằng cách chấp nhận độ trễ trong tính nhất quán và tập trung vào việc phân phối và lưu trữ dữ liệu theo từng phần, giúp hệ thống đạt hiệu suất cao và khả năng mở rộng linh hoạt ACID gặp hạn chế trong việc xử lý khối lượng lớn dữ liệu do yêu cầu giao dịch phải đảm bảo toàn vẹn và chính xác trong từng bước. Điều này khiến các hệ thống ACID khó mở rộng khi dữ liệu phát triển quá nhanh.

Trong NoSQL, các thuộc tính ACID thường không được đảm bảo đầy đủ do tính chất phân tán và nhu cầu tối ưu hiệu suất. Tuy nhiên, một số cơ sở dữ liệu NoSQL vẫn áp dụng một phần hoặc cung cấp tính năng tương tự ACID, tùy thuộc vào loại và cách triển khai.

Eventual Consistency là gì?

Eventual Consistency (Nhất quán cuối cùng) là một mô hình nhất quán trong hệ thống phân tán, trong đó dữ liệu sẽ đồng bộ trên tất cả các nút sau một khoảng thời gian nhất định nếu không có thêm thay đổi nào xảy ra. Tuy nhiên, trong thời gian đồng bộ, các nút có thể chứa dữ liệu không nhất quán tạm thời, một số yêu cầu vẫn sẽ trả về giá trị cũ thay vì giá trị mới được cập nhật.

Đây là cách mà nhiều cơ sở dữ liệu NoSQL chọn để đảm bảo hiệu suất cao và tính sẵn sàng, hy sinh tính nhất quán mạnh (strong consistency).

Ví dụ khi bạn đăng một bài viết lên Facebook thì ngay lập tức, bạn có thể thấy bài viết xuất hiện trên dòng thời gian của mình. Tuy nhiên, bạn bè của bạn có thể không nhìn thấy bài viết đó ngay lập tức vì:

  • Khi bạn đăng bài viết, dữ liệu được lưu trên một máy chủ chính (primary node).
  • Máy chủ này bắt đầu truyền bản sao của bài viết đến các nút khác (replica nodes).
  • Trong thời gian truyền tải, nếu bạn bè của bạn truy cập, họ có thể không thấy bài viết (dữ liệu chưa đồng bộ).
  • Sau một thời gian ngắn, khi quá trình đồng bộ hoàn tất, tất cả các nút sẽ hiển thị bài viết của bạn.

Các câu hỏi phỏng vấn NoSQL về quản lý và lưu trữ dữ liệu

CRUD trong NoSQL là gì và khác gì so với CRUD trong SQL?

CRUD là viết tắt của các thao tác cơ bản trong quản lý dữ liệu:

  • Create (Tạo dữ liệu): Thêm dữ liệu mới vào cơ sở dữ liệu.
  • Read (Đọc dữ liệu): Truy xuất dữ liệu từ cơ sở dữ liệu.
  • Update (Cập nhật dữ liệu): Thay đổi dữ liệu hiện có.
  • Delete (Xóa dữ liệu): Loại bỏ dữ liệu khỏi cơ sở dữ liệu.
Tiêu chí CRUD trong SQL CRUD trong NoSQL
Cấu trúc dữ liệu Cần tuân theo lược đồ (schema). Không yêu cầu lược đồ cố định, hỗ trợ dữ liệu phi cấu trúc.
Tạo dữ liệu Yêu cầu định nghĩa rõ ràng các cột và kiểu dữ liệu trước khi thêm. Linh hoạt, có thể thêm dữ liệu với cấu trúc thay đổi theo thời gian.
Truy vấn dữ liệu Sử dụng ngôn ngữ SQL với cú pháp truy vấn rõ ràng. Truy vấn đa dạng, phụ thuộc vào loại NoSQL (JSON, key-value, graph).
Cập nhật dữ liệu Cần tuân thủ lược đồ, có thể xảy ra lỗi nếu dữ liệu không hợp lệ. Linh hoạt, không bị ràng buộc bởi cấu trúc.
Xóa dữ liệu Xóa dữ liệu ngay lập tức và đồng bộ hóa toàn bộ bảng. Có thể xóa với độ trễ, đặc biệt trong các hệ thống phân tán.
Khả năng mở rộng Khả năng mở rộng hạn chế theo chiều dọc. Hỗ trợ mở rộng ngang, phù hợp với khối lượng lớn dữ liệu.
Tính nhất quán Đảm bảo tính nhất quán mạnh (Strong Consistency) cho tất cả các thao tác CRUD. Chấp nhận nhất quán cuối cùng (Eventual Consistency) trong hệ thống phân tán để tăng tốc độ xử lý.

CRUD trong NoSQL linh hoạt hơn so với SQL nhờ tính chất không ràng buộc lược đồ và khả năng mở rộng cao. Tuy nhiên, điều này cũng đồng nghĩa với việc phải quản lý cẩn thận để đảm bảo tính nhất quán và hiệu quả trong các hệ thống lớn.

CRUD trong NoSQL đặc biệt phù hợp với các ứng dụng yêu cầu xử lý dữ liệu phi cấu trúc hoặc bán cấu trúc, như mạng xã hội, IoT (Internet of Things) và thương mại điện tử.

Sharding là gì?

Sharding là một kỹ thuật phân mảnh dữ liệu, trong đó dữ liệu lớn được chia thành các phần nhỏ hơn gọi là shard, và phân phối trên nhiều máy chủ hoặc nút trong một hệ thống phân tán. Mỗi shard chứa một tập hợp con của dữ liệu và hoạt động độc lập như một cơ sở dữ liệu riêng biệt. Tuy nhiên, khi kết hợp lại, các shard tạo nên một cơ sở dữ liệu logic duy nhất, mang lại khả năng xử lý dữ liệu lớn một cách hiệu quả.

Sharding thường được sử dụng trong các cơ sở dữ liệu NoSQL như MongoDB, Cassandra và HBase để quản lý khối lượng dữ liệu lớn và đáp ứng các yêu cầu về hiệu suất và mở rộng.

Các thành phần trong Sharding:

  • Shard: Là một phần của cơ sở dữ liệu tổng thể, chứa một tập hợp con của dữ liệu. Mỗi shard có thể nằm trên một máy chủ riêng lẻ và dữ liệu được phân phối dựa trên một quy tắc nhất định (shard key).
  • Shard Key: Là một thuộc tính hoặc tập hợp thuộc tính trong dữ liệu dùng để xác định shard lưu trữ dữ liệu đó. Shard key ảnh hưởng trực tiếp đến cách dữ liệu được phân phối và cân bằng giữa các shard.
  • Router (Query Router): Là thành phần trung gian định tuyến các truy vấn của người dùng đến đúng shard chứa dữ liệu liên quan.
  • Cluster: Là tập hợp các máy chủ hoặc nút trong hệ thống, mỗi máy chủ có thể chứa một hoặc nhiều shard.
  • Config Server: Là máy chủ hoặc cụm máy chủ lưu trữ thông tin cấu trúc của shard, bao gồm: vị trí của từng shard trong hệ thống, quy tắc phân phối dữ liệu và thông tin cấu hình cần thiết để duy trì và quản lý cụm sharded cluster.
  • Replication (Nhân bản): Để đảm bảo tính sẵn sàng và dự phòng, mỗi shard thường có các bản sao dữ liệu (replica) trên nhiều máy chủ khác nhau.

Lưu ý: Replication là một thành phần không bắt buộc trong hệ thống sharding. Một số hệ thống NoSQL có sử dụng replication để đảm bảo khả năng chịu lỗi (ví dụ: MongoDB), trong khi một số hệ thống khác có thể không triển khai replication để tối ưu hiệu suất hoặc chi phí.

Tại sao sharding quan trọng trong NoSQL?

  • Tăng khả năng mở rộng (Scalability): Sharding cho phép các cơ sở dữ liệu NoSQL mở rộng ngang bằng cách thêm nhiều máy chủ. Khi lượng dữ liệu hoặc tải công việc tăng lên, bạn chỉ cần thêm máy chủ mới để lưu trữ các shard bổ sung, thay vì nâng cấp phần cứng cho một máy chủ duy nhất.
  • Tăng hiệu suất: Bằng cách phân phối dữ liệu trên nhiều máy chủ, sharding giảm tải trên mỗi máy chủ, giúp tăng tốc độ xử lý các truy vấn và giao dịch, đặc biệt là trong các hệ thống lớn.
  • Đảm bảo tính sẵn sàng (Availability): Nếu một shard bị lỗi, các shard khác vẫn tiếp tục hoạt động, giúp hệ thống duy trì tính sẵn sàng và giảm thiểu thời gian chết.
  • Giúp quản lý dữ liệu lớn hiệu quả: Các cơ sở dữ liệu NoSQL thường được thiết kế để xử lý lượng dữ liệu lớn và phi cấu trúc. Sharding giúp chia nhỏ dữ liệu để lưu trữ và quản lý hiệu quả hơn, đặc biệt khi kích thước dữ liệu vượt quá khả năng của một máy chủ.
  • Giúp tối ưu hóa chi phí: Thay vì đầu tư vào một máy chủ lớn và đắt tiền, sharding cho phép sử dụng nhiều máy chủ nhỏ hơn, giúp giảm chi phí tổng thể.

Ví dụ, trong một cơ sở dữ liệu NoSQL như MongoDB, sharding có thể được thực hiện dựa trên một “shard key” (khóa phân mảnh) như ID người dùng hoặc mã sản phẩm. Việc chọn khóa sharding phù hợp rất quan trọng để đảm bảo dữ liệu được phân phối đồng đều giữa các shard và tránh tình trạng “nút cổ chai” (bottleneck).

Thách thức của Sharding trong NoSQL là gì?

Mặc dù sharding là một giải pháp hiệu quả để xử lý dữ liệu lớn trong các hệ thống NoSQL, nhưng nó cũng đi kèm với nhiều thách thức phức tạp trong quá trình triển khai và quản lý:

  • Lựa chọn Shard Key phù hợp: Shard key đóng vai trò quyết định trong việc phân phối dữ liệu giữa các shard. Một shard key không phù hợp có thể dẫn đến phân mảnh dữ liệu không đồng đều (unbalanced shards), gây quá tải trên một số shard (hotspot) trong khi các shard khác ít được sử dụng dẫn đến giảm hiệu năng hệ thống.
  • Quản lý cân bằng dữ liệu (Data Balancing): Khi thêm hoặc xóa shard, hệ thống cần di chuyển dữ liệu giữa các shard để đảm bảo sự cân bằng tải. Quá trình này phức tạp, tiêu tốn tài nguyên và có thể làm giảm hiệu suất hệ thống trong thời gian di chuyển.
  • Phức tạp trong xử lý truy vấn (Query Complexity): Các truy vấn liên quan đến nhiều shard (query scatter) cần được phân tán và hợp nhất kết quả từ các shard, dẫn đến việc làm tăng độ trễ và giảm hiệu suất.
  • Khó khăn trong việc mở rộng và giảm quy mô (Scaling): Mặc dù sharding hỗ trợ mở rộng ngang, việc thêm hoặc xóa shard có thể yêu cầu cấu hình lại hệ thống và điều chỉnh dữ liệu. Điều này không phải lúc nào cũng dễ dàng, đặc biệt với khối lượng dữ liệu lớn.
  • Tính nhất quán dữ liệu (Data Consistency): Trong môi trường phân tán, việc đảm bảo dữ liệu nhất quán trên các shard, đặc biệt khi có các bản sao dữ liệu (replica), trở nên phức tạp. Đây là một thách thức lớn đối với các hệ thống yêu cầu tính nhất quán cao.
  • Chi phí bảo trì: Sharding làm tăng độ phức tạp của hệ thống, yêu cầu đội ngũ kỹ thuật có kiến thức chuyên môn cao để thiết kế, vận hành và giám sát hệ thống.

Mô tả các loại Sharding

1. Range-based Sharding (Sharding theo khoảng)

Cách hoạt động: Dữ liệu được phân chia thành các khoảng giá trị (range) dựa trên một shard key cụ thể. Mỗi khoảng sẽ tương ứng với một shard riêng biệt.

Ví dụ: Với một hệ thống sử dụng user_id làm shard key:

Khoảng (Range) Shard ID
[0, 1000) Shard A
[1000, 2000) Shard B
[2000, 3000) Shard C

Nếu truy vấn tìm dữ liệu với user_id trong khoảng từ 500 đến 1500, chỉ Shard A và Shard B cần được truy vấn.

Ưu điểm:

  • Dễ triển khai và phù hợp với các hệ thống có cấu trúc dữ liệu tuần tự.
  • Truy vấn theo khoảng (range queries) rất hiệu quả vì chỉ cần truy cập một số shard cụ thể.

Nhược điểm:

  • Lựa chọn shard key không phù hợp có thể dẫn đến tình trạng mất cân bằng tải (hotspot).
  • Lookup table có thể trở thành điểm tắc nghẽn khi hệ thống mở rộng lớn.

2. Hash-based Sharding (Sharding dựa trên hàm băm)

Cách hoạt động: Sử dụng một hàm băm (hash function) để tính toán shard dựa trên giá trị shard key. Giá trị băm được ánh xạ tới shard tương ứng.

Ví dụ: Sử dụng user_id làm shard key với hàm băm đơn giản:

shard = hash(user_id) % số lượng shard

Nếu hash(1001) % 3 = 1, dữ liệu sẽ được lưu vào Shard 1.

Ưu điểm:

  • Phân phối đồng đều dữ liệu trên các shard, giảm tình trạng mất cân bằng tải.
  • Không cần bảng tra cứu như range-based sharding.

Nhược điểm:

  • Truy vấn theo khoảng sẽ không hiệu quả vì dữ liệu đã được phân tán ngẫu nhiên.
  • Resharding (tái phân chia shard) rất tốn kém vì cần di chuyển nhiều dữ liệu khi thêm hoặc bớt shard.

3. Entity-based Sharding (Sharding theo thực thể)

Cách hoạt động: Dữ liệu liên quan đến một thực thể chính được lưu trữ trên cùng một shard để giảm truy vấn chéo shard.

Ví dụ: Trong một hệ thống thương mại điện tử, dữ liệu của người dùng và đơn hàng liên quan sẽ được lưu trữ cùng một shard:

{

  "user_id": "123",

  "name": "John Doe",

  "orders": [

    { "order_id": "101", "amount": 50 },

    { "order_id": "102", "amount": 100 }

  ]

}

Ưu điểm:

  • Tăng tốc độ truy vấn dữ liệu có mối quan hệ chặt chẽ.
  • Giảm thiểu số lượng truy vấn chéo shard (cross-shard queries).

Nhược điểm:

  • Dễ gặp tình trạng hotspot nếu một thực thể có khối lượng dữ liệu lớn.
  • Không phù hợp cho các hệ thống có dữ liệu độc lập giữa các thực thể.

4. Geography-based Sharding (Sharding theo địa lý)

Cách hoạt động: Dữ liệu được phân chia dựa trên vị trí địa lý của người dùng hoặc dữ liệu. Các shard thường được lưu trữ trên các máy chủ theo khu vực để giảm độ trễ.

Ví dụ: Một hệ thống toàn cầu có thể phân chia dữ liệu như sau:

Khu vực Shard
Bắc Mỹ Shard US
Châu Âu Shard EU
Châu Á Shard ASIA

Dữ liệu người dùng ở khu vực Bắc Mỹ sẽ được lưu trữ trên Shard US.

Ưu điểm:

  • Giảm độ trễ truy vấn bằng cách lưu trữ dữ liệu gần với người dùng.
  • Hỗ trợ tối ưu hóa các hệ thống phân tán trên toàn cầu.

Nhược điểm:

  • Có thể cần resharding khi dữ liệu tăng không đồng đều giữa các khu vực.
  • Khó xử lý khi người dùng có dữ liệu liên quan ở nhiều khu vực khác nhau.

Phân biệt giữa scaling horizontal và scaling vertical.

Khi cần mở rộng hệ thống để xử lý nhiều dữ liệu hơn hoặc tăng cường hiệu suất, có hai phương pháp chính được sử dụng: Scaling Horizontal (mở rộng ngang) và Scaling Vertical (mở rộng dọc). Dưới đây là sự khác biệt giữa hai phương pháp này:

Tiêu chí Scaling Horizontal Scaling Vertical
Cách thực hiện  Thêm nhiều máy chủ hoặc nút (nodes) mới vào hệ thống, phân phối dữ liệu và tải công việc giữa các máy chủ đó. Dữ liệu thường được phân chia thông qua các kỹ thuật như sharding hoặc replication. Nâng cấp phần cứng của máy chủ hiện tại (CPU, RAM, ổ cứng, SSD).
Khả năng mở rộng Không giới hạn – có thể thêm bao nhiêu máy chủ tùy theo nhu cầu. Giới hạn bởi khả năng nâng cấp phần cứng của máy chủ.
Khả năng chịu lỗi Cao – nếu một máy chủ hoặc nút gặp lỗi, các máy khác vẫn hoạt động. Thấp – nếu máy chủ bị lỗi, toàn bộ hệ thống có thể ngừng hoạt động.
Chi phí Thấp hơn – sử dụng nhiều máy chủ thông thường (commodity hardware). Cao hơn – cần phần cứng mạnh và chuyên dụng.
Độ phức tạp triển khai Cao hơn – cần thiết kế lại hệ thống để hỗ trợ đồng bộ hóa và phân phối tải. Thấp hơn – không cần thay đổi cấu trúc hệ thống.
Hiệu suất Cải thiện bằng cách phân tải công việc giữa các máy chủ. Cải thiện bằng cách tăng khả năng xử lý của một máy chủ duy nhất.
Khả năng triển khai Chậm hơn – cần thiết kế cơ chế cân bằng tải và đồng bộ hóa dữ liệu. Nhanh hơn – chỉ cần nâng cấp phần cứng.
Ứng dụng Hệ thống lớn, phân tán: NoSQL, Big Data, mạng xã hội, IoT. Hệ thống nhỏ hoặc cần cải thiện hiệu suất trong ngắn hạn.

Làm thế nào để quản lý xung đột dữ liệu trong eventual consistency?

Trong hệ thống eventual consistency, xung đột dữ liệu có thể xảy ra khi cùng một bản ghi được cập nhật trên nhiều nút (nodes) trước khi các thay đổi được đồng bộ hóa. Quản lý xung đột dữ liệu là một thách thức quan trọng trong các hệ thống phân tán. Dưới đây là một số phương pháp phổ biến để giải quyết xung đột dữ liệu:

  • Last Write Wins (LWW): Dữ liệu được gắn dấu thời gian (timestamp) và bản ghi với timestamp mới nhất được giữ lại. Phương pháp này đơn giản và nhanh nhưng có thể dẫn đến mất dữ liệu nếu các thay đổi trước đó bị ghi đè hoặc các nút có đồng hồ hệ thống không đồng bộ.
  • Hợp nhất dữ liệu (Data Merging): Các thay đổi từ nhiều nút được kết hợp lại thay vì ghi đè, đặc biệt hiệu quả nếu các thay đổi không xung đột trực tiếp (ví dụ: chỉnh sửa các trường khác nhau). Phương pháp này yêu cầu logic hợp nhất rõ ràng.
  • Vector Clock: Theo dõi lịch sử thay đổi của bản ghi thông qua một đồng hồ vector, cho phép hệ thống phát hiện và xử lý xung đột phức tạp một cách chính xác. Phương pháp này thường được sử dụng trong các hệ thống như DynamoDB.
  • Replication với Primary Node: Ưu tiên bản ghi từ nút chính (primary node) trong trường hợp xảy ra xung đột, giúp đơn giản hóa quá trình xử lý nhưng phụ thuộc vào nút chính và có thể giảm tính phân tán.
  • Conflict-Free Replicated Data Types (CRDTs): Sử dụng các cấu trúc dữ liệu đặc biệt để tự động giải quyết xung đột mà không cần can thiệp từ người dùng. Ví dụ: các phép toán như tăng bộ đếm hoặc thêm phần tử vào danh sách có thể được hợp nhất tự động.
  • Quorum-Based Resolution: Xung đột được giải quyết bằng đồng thuận từ một nhóm nút (quorum). Ví dụ: một thay đổi chỉ được chấp nhận nếu nó nhận được xác nhận từ đa số nút, qua đó giúp tăng độ chính xác nhưng có thể làm giảm tốc độ ghi hoặc đọc dữ liệu.

Làm thế nào NoSQL giải quyết vấn đề phân tán dữ liệu?

Hệ thống NoSQL được thiết kế để hoạt động trong môi trường phân tán, nơi dữ liệu được lưu trữ trên nhiều máy chủ hoặc nút (nodes). Để giải quyết các thách thức của việc phân tán dữ liệu, NoSQL sử dụng một số chiến lược chính:

Replication (Sao chép dữ liệu)

Dữ liệu được sao chép trên nhiều máy chủ hoặc nhiều nút để đảm bảo tính sẵn sàng và khả năng chịu lỗi. Có hai loại replication phổ biến:

  • Master-Slave Replication: Một nút chính (master) thực hiện ghi dữ liệu, trong khi các nút phụ (slaves) sao chép và phục vụ các yêu cầu đọc.
  • Multi-Master Replication: Tất cả các nút đều có thể đọc và ghi, phù hợp với các hệ thống phân tán lớn nhưng yêu cầu xử lý xung đột phức tạp hơn.

Sharding (Phân mảnh dữ liệu)

Dữ liệu được chia nhỏ thành các phần nhỏ hơn (shards) và phân phối trên nhiều nút. Sharding giúp cân bằng tải giữa các máy chủ, tăng hiệu suất và giảm áp lực lên từng nút.

Xử lý xung đột dữ liệu

Trong môi trường phân tán, xung đột có thể xảy ra khi nhiều nút cập nhật cùng một dữ liệu. NoSQL sử dụng các cơ chế như Last Write Wins, Vector Clocks, hoặc hợp nhất dữ liệu để giải quyết các xung đột này.

Quorum-based Consistency

Thay vì đòi hỏi tất cả các máy chủ phải đồng thuận với nhau (như trong SQL), NoSQL chỉ yêu cầu một số lượng tối thiểu các máy chủ (gọi là quorum) đồng thuận trước khi chấp nhận một thao tác ghi (write) hoặc đọc (read), giúp tăng hiệu suất và tính sẵn sàng, nhưng vẫn duy trì mức độ nhất quán cần thiết.

Trong đó:

  • W (Write Quorum): Số lượng máy chủ phải xác nhận một thao tác ghi (write) trước khi nó được coi là thành công.
  • R (Read Quorum): Số lượng máy chủ phải xác nhận và trả về dữ liệu cho một thao tác đọc (read).
  • Để đảm bảo dữ liệu nhất quán, tổng số W + R > N, trong đó N là tổng số máy chủ lưu trữ dữ liệu.

Hệ thống điều hướng truy vấn (Query Routing): là một cơ chế trong các cơ sở dữ liệu phân tán, đặc biệt phổ biến trong NoSQL, được sử dụng để định tuyến các truy vấn của người dùng đến đúng máy chủ hoặc nút (node) chứa dữ liệu cần thiết.

Thay vì tìm kiếm trên toàn bộ hệ thống, query routing tối ưu hóa quá trình xử lý bằng cách xác định vị trí dữ liệu dựa trên các khóa định tuyến (routing key) hoặc shard key.

Các câu hỏi phỏng vấn NoSQL về hiệu suất và tối ưu hoá

TTL (Time to Live) trong NoSQL là gì và được sử dụng để làm gì?

TTL (Time to Live) là một tính năng trong NoSQL cho phép bạn đặt thời gian tồn tại cho dữ liệu. Khi thời gian TTL hết hạn, dữ liệu sẽ tự động bị xóa khỏi cơ sở dữ liệu. TTL được thiết kế để quản lý dữ liệu tạm thời, giảm tải lưu trữ và tự động hóa việc dọn dẹp dữ liệu không cần thiết.

Cách hoạt động của TTL

  • Khi một tài liệu, bản ghi, hoặc mục dữ liệu được thêm vào cơ sở dữ liệu, bạn có thể đặt một giá trị TTL (tính bằng giây, phút hoặc giờ).
  • Hệ thống NoSQL sẽ theo dõi thời gian tồn tại của dữ liệu này. Khi thời gian TTL hết hạn, cơ sở dữ liệu sẽ tự động xóa dữ liệu mà không cần can thiệp thủ công.
  • TTL thường dựa trên một trường cụ thể (ví dụ: expiration_time) hoặc thời gian kể từ khi dữ liệu được tạo.

Ứng dụng của TTL trong NoSQL

  • Quản lý dữ liệu tạm thời: TTL rất hữu ích trong các ứng dụng lưu trữ dữ liệu tạm thời, như session của người dùng, mã xác minh (OTP) hoặc bộ nhớ cache. Ví dụ: Một ứng dụng web có thể lưu session của người dùng với TTL là 30 phút. Sau 30 phút, session sẽ tự động bị xóa.
  • Dọn dẹp dữ liệu cũ: TTL giúp tự động xóa dữ liệu không còn cần thiết, giảm gánh nặng lưu trữ và tăng hiệu suất. Ví dụ: Lưu trữ lịch sử giao dịch trong 90 ngày, sau đó tự động xóa.
  • Quản lý bộ nhớ đệm (Cache Management): TTL thường được sử dụng trong các hệ thống bộ nhớ đệm (cache) để xóa các bản ghi hoặc tài nguyên cũ. Điều này giúp đảm bảo bộ nhớ đệm luôn chứa dữ liệu mới và có giá trị. Ví dụ: Redis sử dụng TTL để tự động xóa các key-value đã hết hạn trong bộ nhớ đệm, đảm bảo dữ liệu được cập nhật liên tục.
  • Quản lý thông báo đẩy (Push Notifications): TTL có thể được sử dụng trong hệ thống thông báo đẩy, nơi các tin nhắn hoặc thông báo chỉ có giá trị trong một khoảng thời gian cụ thể. Ví dụ: Một hệ thống gửi thông báo giảm giá cho người dùng với TTL là 24 giờ. Sau khoảng thời gian này, thông báo sẽ tự động bị xóa để tránh gửi các thông tin không còn hợp lệ.

Cách một số hệ quản trị cơ sở dữ liệu sử dụng TTL:

  • Redis: Hỗ trợ TTL trên mỗi khóa (key) bằng lệnh Expire, giúp quản lý bộ nhớ cache hiệu quả.
  • MongoDB: Cung cấp TTL Index, cho phép xóa các tài liệu trong một bộ sưu tập (collection) dựa trên giá trị thời gian được đặt trong trường TTL.
  • Cassandra: TTL có thể được đặt khi chèn dữ liệu, và hệ thống sẽ tự động xóa dữ liệu khi TTL hết hạn.

Làm thế nào để xử lý bottleneck trong hệ thống write-heavy?

Bottleneck là điểm nghẽn trong hệ thống, nơi tài nguyên hoặc thành phần cụ thể (như CPU, bộ nhớ, ổ cứng, hoặc mạng) bị quá tải dẫn đến hiện tượng nghẽn cổ chai, làm giảm hiệu suất tổng thể của toàn bộ hệ thống. Trong bối cảnh NoSQL, bottleneck thường xảy ra khi khối lượng ghi dữ liệu (write operations) vượt quá khả năng xử lý của hệ thống.

Write-heavy đề cập đến các hệ thống mà khối lượng ghi dữ liệu (write requests) chiếm phần lớn so với các thao tác đọc (read requests). Các ứng dụng như ghi log, theo dõi sự kiện thời gian thực, hoặc hệ thống IoT thường có đặc điểm write-heavy.

Một số cách xử lý bottleneck trong hệ thống write-heavy là:

  • Tối ưu hóa cấu trúc dữ liệu và ghi đồng loạt (Batch Writes): Thay vì ghi dữ liệu từng bản ghi riêng lẻ, hãy ghi theo lô (batch) sẽ giúp giảm số lượng kết nối và thao tác ghi, tăng hiệu suất tổng thể. Ví dụ như trong Cassandra có hỗ trợ batch writes để tối ưu hiệu suất.
  • Phân mảnh dữ liệu (Sharding): Phân chia dữ liệu thành các shard nhỏ hơn và phân phối chúng trên nhiều máy chủ. Điều này giúp chia tải công việc ghi giữa các máy chủ khác nhau, giảm áp lực cho từng máy. Lưu ý là cần chọn shard key phù hợp để tránh mất cân bằng tải.
  • Sử dụng bộ nhớ đệm (Write Cache): Dữ liệu ghi tạm thời được lưu trữ trong bộ nhớ đệm (cache) trước khi được ghi vào ổ cứng. Điều này giảm độ trễ và tăng tốc độ ghi. Ví dụ như Redis thường được dùng như một write cache cho các hệ thống NoSQL.
  • Tối ưu hóa chỉ mục (Index Optimization): Sử dụng ít chỉ mục hơn trên các trường dữ liệu ghi nhiều vì chỉ mục quá nhiều làm tăng chi phí ghi dữ liệu.
  • Scaling Horizontal (Mở rộng ngang): Thêm nhiều máy chủ để xử lý tải ghi lớn. NoSQL hỗ trợ mở rộng ngang dễ dàng, giúp tăng khả năng xử lý write-heavy.
  • Log-structured Storage: là phương pháp sử dụng cấu trúc lưu trữ theo log, trong đó các bản ghi mới được thêm tuần tự vào cuối file, giúp giảm chi phí ghi ngẫu nhiên.
  • Ghi không đồng bộ (Asynchronous Writes): Các thao tác ghi không quan trọng có thể được chuyển sang các quy trình không đồng bộ hoặc hàng đợi (queue). Phương pháp này giúp tách biệt ghi dữ liệu khỏi luồng chính của ứng dụng, từ đó cải thiện khả năng phản hồi và mở rộng.
  • Write-ahead Logging (WAL): Sử dụng WAL để ghi log thay đổi dữ liệu trước khi ghi trực tiếp vào bộ nhớ chính, từ đó giúp đảm bảo tính bền vững (durability) của dữ liệu và giảm I/O ngẫu nhiên trên đĩa trong quá trình ghi.
  • Chèn dữ liệu hàng loạt (Bulk Inserts): Thay vì chèn từng dòng dữ liệu, sử dụng bulk insert để chèn dữ liệu theo nhóm lớn trong một lần giao dịch. Phương pháp này không giảm chi phí phát sinh từ việc tạo nhiều giao dịch nhỏ mà còn cải thiện throughput của hệ thống.
  • Phân vùng dữ liệu (Partitioning): Phân chia các bảng lớn thành các phần nhỏ hơn (partition) để phân tán tải ghi giữa nhiều ổ đĩa hoặc máy chủ. Phân vùng theo chiều ngang (horizontal partitioning) sẽ giúp giảm tình trạng tranh chấp và cải thiện khả năng xử lý đồng thời.

Các công cụ hỗ trợ xử lý write-heavy trong NoSQL

Các hệ thống write-heavy đòi hỏi cơ sở dữ liệu NoSQL có khả năng tối ưu hóa cho khối lượng lớn thao tác ghi dữ liệu. Một số công cụ NoSQL được thiết kế đặc biệt để xử lý hiệu quả các tác vụ write-heavy như: 

  1. Cassandra: sử dụng kiến trúc phân tán peer-to-peer và cơ chế lưu trữ log-structured, giúp ghi dữ liệu tuần tự vào ổ đĩa mà không cần ghi đè. Các thao tác ghi được tối ưu hóa thông qua batch writes, giảm chi phí khi xử lý khối lượng lớn yêu cầu ghi. Ngoài ra, Cassandra hỗ trợ mở rộng ngang, giúp phân phối tải ghi giữa nhiều máy chủ, giữ hiệu suất ổn định ngay cả khi dữ liệu tăng trưởng lớn.
  2. Redis: Là một cơ sở dữ liệu in-memory, Redis xử lý write-heavy bằng cách lưu trữ dữ liệu trong bộ nhớ tạm thời, giúp thao tác ghi diễn ra với độ trễ rất thấp. Redis hỗ trợ cơ chế append-only file (AOF) để ghi dữ liệu vào ổ đĩa tuần tự, đảm bảo độ bền dữ liệu mà không làm giảm hiệu suất xử lý ghi.
  3. MongoDB: tối ưu hóa ghi dữ liệu trong hệ thống write-heavy bằng cách sử dụng replica set để phân phối thao tác ghi giữa các nút và sharding để chia nhỏ dữ liệu theo shard key. Cơ chế write-concern cho phép cấu hình mức độ cam kết của thao tác ghi, từ mức tối thiểu (ghi tại một nút) đến mạnh mẽ (ghi trên nhiều nút), giúp linh hoạt theo nhu cầu của hệ thống.

Lựa chọn cấu trúc dữ liệu nào cho hiệu suất write cao?

Để đạt hiệu suất ghi (write) cao, việc chọn cấu trúc dữ liệu phù hợp là rất quan trọng. Các cấu trúc dữ liệu sau đây thường được sử dụng trong hệ thống NoSQL nhờ khả năng tối ưu hóa cho thao tác ghi:

  • Log-Structured Storage: Cấu trúc này ghi dữ liệu tuần tự vào một file log trên ổ đĩa thay vì ghi ngẫu nhiên vào nhiều vị trí. Cách tiếp cận này giảm chi phí ghi I/O và tận dụng tối đa hiệu suất của ổ đĩa từ tính hoặc SSD. Vì không cần ghi đè nhiều lần, log-structured storage rất phù hợp cho các hệ thống write-heavy với yêu cầu cao về tốc độ ghi. Log-structured Storage thường được sử dụng trong các cơ sở dữ liệu như Cassandra và HBase để xử lý khối lượng lớn thao tác ghi trong thời gian ngắn.
  • Bộ nhớ đệm (In-Memory Data Store): Dữ liệu được lưu tạm thời trong RAM để xử lý nhanh các thao tác ghi. Sau đó, dữ liệu được đồng bộ hóa định kỳ vào ổ đĩa hoặc cơ sở dữ liệu chính để đảm bảo không bị mất khi hệ thống gặp sự cố. Cách tiếp cận này đặc biệt hiệu quả trong các ứng dụng yêu cầu tốc độ nhanh và dữ liệu không cần tồn tại lâu dài. Redis và Memcached là những ví dụ điển hình của cơ sở dữ liệu in-memory tối ưu cho write-heavy.
  • Column-Family Store: Trong cấu trúc này, dữ liệu được tổ chức và lưu trữ dưới dạng cột thay vì hàng như trong cơ sở dữ liệu quan hệ. Khi cần ghi dữ liệu, chỉ các cột thay đổi được ghi lại, giúp giảm khối lượng thao tác ghi so với việc ghi toàn bộ hàng. Nhờ đó column-family store phù hợp với các ứng dụng ghi dữ liệu lớn nhưng chỉ thay đổi một phần dữ liệu trong mỗi bản ghi. Các cơ sở dữ liệu như HBase và Cassandra sử dụng cấu trúc này để tối ưu hóa ghi và lưu trữ.
  • Key-Value Store: là một trong những cấu trúc đơn giản nhất, lưu trữ dữ liệu dưới dạng cặp khóa-giá trị. Khi ghi dữ liệu, cơ sở dữ liệu chỉ cần lưu giá trị tương ứng với khóa, mà không cần xử lý các cấu trúc phức tạp khác, giúp giảm chi phí xử lý và tăng tốc độ ghi. Các cơ sở dữ liệu như DynamoDB và Riak, sử dụng cấu trúc key-value và là lựa chọn phù hợp với các ứng dụng write-heavy nhờ thiết kế đơn giản nhưng hiệu quả.
  • LSM Trees (Log-Structured Merge Trees): LSM Trees ghi dữ liệu mới vào bộ nhớ (RAM) trước khi tổ chức lại thành các mức (levels) và ghi tuần tự vào ổ đĩa. Bằng cách giảm số lần ghi ngẫu nhiên và chỉ xử lý dữ liệu khi cần, cấu trúc này giúp tăng hiệu suất ghi đáng kể. LSM Trees thường được sử dụng trong các cơ sở dữ liệu write-heavy vì khả năng ghi nhanh, kết hợp với khả năng lưu trữ dữ liệu lớn một cách hiệu quả. Các cơ sở dữ liệu sử dụng LSM Trees là RocksDB và LevelDB.

Khi nào nên sử dụng batch processing trong NoSQL?

Batch Processing là một kỹ thuật xử lý dữ liệu trong đó nhiều thao tác hoặc công việc được gom lại thành một lô (batch) và thực hiện cùng lúc thay vì xử lý từng thao tác riêng lẻ. Thay vì gửi yêu cầu đến cơ sở dữ liệu cho từng bản ghi, batch processing thực hiện một yêu cầu duy nhất để xử lý toàn bộ dữ liệu trong lô, giúp giảm chi phí về tài nguyên, mạng và thời gian.

Phương pháp này phù hợp trong các trường hợp yêu cầu ưu tiên hiệu suất ghi và xử lý dữ liệu, đặc biệt là khi hệ thống cần giảm số lượng kết nối hoặc thao tác truy vấn đến cơ sở dữ liệu.

Các trường hợp nên sử dụng Batch Processing

  • Xử lý khối lượng lớn dữ liệu: Khi cần nhập hoặc ghi hàng triệu bản ghi vào cơ sở dữ liệu, như tải dữ liệu từ file log, backup, hoặc hệ thống ETL. Batch processing cho phép tối ưu hóa việc xử lý số lượng lớn dữ liệu mà không làm hệ thống bị quá tải.
  • Tối ưu hóa hiệu suất ghi: Trong hệ thống write-heavy, batch processing giúp giảm số lượng thao tác ghi đơn lẻ, từ đó giảm chi phí I/O và tăng tốc độ ghi dữ liệu.
  • Giảm chi phí mạng: Nếu cơ sở dữ liệu NoSQL được triển khai trên nhiều nút hoặc trên đám mây (cloud), batch processing giúp giảm số lượng yêu cầu qua mạng bằng cách gộp nhiều thao tác trong một kết nối.
  • Xử lý dữ liệu định kỳ hoặc không thời gian thực: Phù hợp với các ứng dụng không yêu cầu dữ liệu được xử lý ngay lập tức, như tổng hợp dữ liệu hàng ngày, xử lý log hoặc phân tích dữ liệu lịch sử.
  • Khi cần duy trì tính nhất quán tạm thời: Batch processing cho phép hệ thống thực hiện nhiều thay đổi cùng một lúc, giúp giảm khả năng xảy ra xung đột dữ liệu khi có nhiều thao tác ghi đồng thời.

So sánh NoSQL và SQL về khả năng backup dữ liệu

Tiêu chí SQL NoSQL
Cơ chế hoạt động Sao lưu toàn bộ hoặc từng bảng với công cụ tích hợp. – Sao lưu theo shard hoặc cụm (cluster).

– Backup phân tán theo từng nút.

Cách lưu trữ Dữ liệu được lưu tập trung dưới dạng file SQL hoặc snapshot. Lưu trữ dữ liệu phân tán, thường là file binary hoặc snapshot của từng nút.
Thời gian backup – Sao lưu nhanh với dữ liệu nhỏ.

– Với dữ liệu lớn, cần nhiều thời gian hơn.

– Backup diễn ra đồng thời trên nhiều nút, nhanh hơn khi dữ liệu lớn.
Downtime khi backup – Có thể cần downtime để tránh xung đột trong quá trình sao lưu. – Không cần downtime, backup song song giữa các nút trong hệ thống phân tán.
Tính nhất quán – Đảm bảo nhất quán nhờ giao dịch ACID. – Phụ thuộc vào loại NoSQL (strong hoặc eventual consistency).
Công cụ hỗ trợ – MySQL: mysqldump, mysqlhotcopy.

– PostgreSQL: pg_dump.

– MongoDB: mongodump.

– Cassandra: snapshot qua nodetool.

Chi phí lưu trữ Tốn dung lượng lớn do backup tập trung. Lưu trữ hiệu quả hơn nhờ nén và phân mảnh dữ liệu trên nhiều nút.
Tự động hóa Dễ dàng lên lịch backup định kỳ với công cụ tích hợp (ví dụ cron). Phụ thuộc vào dịch vụ hoặc công cụ tích hợp (ví dụ: MongoDB Ops Manager).
Khả năng mở rộng Khó khăn với dữ liệu lớn hoặc hệ thống phức tạp. Dễ mở rộng nhờ backup phân tán và đồng thời trên nhiều máy chủ.

So sánh NoSQL và SQL về khả năng restore dữ liệu

Tiêu chí SQL NoSQL
Cơ chế hoạt động Dễ dàng bằng cách chạy file SQL hoặc snapshot toàn bộ cơ sở dữ liệu. – Restore theo từng shard hoặc nút.

– Yêu cầu đồng bộ hóa dữ liệu sau khi restore.

Thời gian Nhanh nếu dữ liệu nhỏ, nhưng với dữ liệu lớn có thể mất nhiều thời gian. – Phụ thuộc vào số lượng nút và khối lượng dữ liệu phân tán.

– Thời gian đồng bộ lâu hơn trong hệ thống lớn.

Tính nhất quán – Đảm bảo toàn vẹn dữ liệu nhờ ACID. – Dựa vào mức độ nhất quán thiết lập trước (strong hoặc eventual consistency).
Downtime khi restore Thường yêu cầu downtime khi khôi phục toàn bộ cơ sở dữ liệu. Restore không cần downtime nhưng yêu cầu thời gian để đồng bộ dữ liệu.
Phục hồi từng phần Hỗ trợ tốt, có thể phục hồi bảng hoặc giao dịch cụ thể. Thường phục hồi theo shard hoặc nút, khó khăn hơn khi phục hồi từng phần.
Công cụ hỗ trợ – MySQL: mysql < backup.sql.

– PostgreSQL: pg_restore.

– MongoDB: mongorestore.

– Cassandra: nodetool refresh.

Độ phức tạp Dễ dàng nhờ các công cụ chuẩn hóa. Phức tạp hơn do dữ liệu phân tán, cần quản lý đồng bộ giữa các nút.

SQL dễ dàng hơn trong việc backup và restore nhờ các công cụ chuẩn hóa và giao dịch ACID, phù hợp cho hệ thống dữ liệu tập trung.

Trong khi đó, NoSQL ưu tiên khả năng xử lý dữ liệu lớn và phân tán, nhưng việc backup và restore đòi hỏi kỹ thuật phức tạp hơn để đảm bảo tính nhất quán và đồng bộ. Mỗi hệ thống có ưu và nhược điểm riêng nên việc lựa chọn hệ thống nào cần cân nhắc về yêu cầu về quy mô và tính chất dữ liệu.

Khi nào nên dùng caching trong NoSQL?

Caching là một kỹ thuật lưu trữ tạm thời dữ liệu trong bộ nhớ đệm (cache) để truy cập nhanh hơn khi cần. Dữ liệu được lưu trong cache thường là các kết quả truy vấn hoặc nội dung thường xuyên được yêu cầu, giúp giảm tải cho hệ thống lưu trữ chính hoặc cơ sở dữ liệu. Caching thường được sử dụng trong các trường hợp sau:

  • Hệ thống có khối lượng truy vấn cao (High Read Load): Khi hệ thống có nhiều yêu cầu đọc lặp lại từ người dùng hoặc ứng dụng, caching giúp giảm số lượng truy vấn trực tiếp đến cơ sở dữ liệu, giảm tải và cải thiện tốc độ phản hồi.
  • Dữ liệu ít thay đổi (Static or Semi-static Data): Với các loại dữ liệu ít thay đổi như danh sách sản phẩm, thông tin người dùng hoặc cấu hình hệ thống, caching đảm bảo phản hồi nhanh mà không cần truy vấn lại cơ sở dữ liệu.
  • Ứng dụng yêu cầu độ trễ thấp (Low-latency Applications): Caching giúp đáp ứng các ứng dụng thời gian thực như mạng xã hội, hệ thống gợi ý hoặc giao dịch trực tuyến cần phản hồi nhanh chóng.
  • Tăng hiệu suất khi truy cập dữ liệu phức tạp: Khi truy vấn yêu cầu xử lý nhiều tính toán hoặc kết hợp dữ liệu phức tạp, lưu kết quả truy vấn trong cache giúp tránh thực hiện lại các tác vụ nặng.
  • Giảm chi phí và tối ưu tài nguyên: Sử dụng caching giúp giảm số lượng truy vấn trực tiếp đến cơ sở dữ liệu, giảm chi phí tài nguyên trên các máy chủ NoSQL, đặc biệt trong các hệ thống phân tán hoặc cloud-based.
  • Phân phối tải trong hệ thống lớn: Trong các hệ thống NoSQL write-heavy, caching cho phép ghi dữ liệu vào lớp đệm tạm thời trước khi đồng bộ vào cơ sở dữ liệu chính, giúp giảm tải cho máy chủ lưu trữ.

Các câu hỏi phỏng vấn NoSQL về bảo mật

NoSQL injection là gì? Giải thích về cách hoạt động và cách phòng ngừa

Tương tự với SQL Injection, NoSQL Injection là một kỹ thuật tấn công trong đó kẻ xâm nhập chèn các đoạn mã độc hại hoặc truy vấn không mong muốn vào hệ thống NoSQL thông qua đầu vào người dùng không được kiểm soát chặt chẽ. Mục tiêu của NoSQL Injection là truy cập, sửa đổi hoặc phá hủy dữ liệu trong cơ sở dữ liệu NoSQL mà không cần có quyền hợp lệ.

NoSQL Injection đặc biệt nguy hiểm vì cơ sở dữ liệu NoSQL thường không có chuẩn hóa về ngôn ngữ truy vấn và các cơ chế bảo vệ tích hợp sẵn thường không đủ mạnh nếu không được thiết lập đúng cách.

Cách hoạt động của NoSQL Injection

NoSQL Injection xảy ra khi ứng dụng cho phép đầu vào của người dùng được đưa trực tiếp vào truy vấn cơ sở dữ liệu mà không được kiểm tra hoặc xử lý đúng cách. Có ba hình thức phổ biến:

Syntax Injection (Chèn cú pháp)

Kẻ tấn công sẽ phá vỡ cấu trúc truy vấn của hệ thống bằng cách chèn các điều kiện luôn đúng để lấy được dữ liệu trái phép hoặc “qua mặt” (bypass) phần xác thực.

Cách thức hiện: Kẻ tấn công sẽ chèn vào các điều kiện logic luôn đúng như:

  • 1==1
  • ‘a’==’a’
  • ”==”
  • true || false

Ví dụ trong MongoDb: Một ứng dụng cho phép người dùng đăng nhập bằng cách nhập tên tài khoản và mật khẩu. Khi nhận được thông tin, hệ thống tạo truy vấn:

db.users.find({ "username": input.username, "password": input.password });

Trong đó, input.usernameinput.password là dữ liệu do người dùng nhập.

Nếu kẻ tấn công nhập chuỗi như sau vào input.username:

{ "$or": [ { "username": "admin" }, { "1": { "$eq": "1" } } ] }

Truy vấn sẽ trở thành:

db.users.find({

  "username": {

    "$or": [

      { "username": "admin" },

      { "1": { "$eq": "1" } }

    ]

  },

"password": input.password });

Trong truy vấn này, điều kiện ‘1’==’1′ luôn đúng, dẫn đến việc hệ thống trả về tất cả tài khoản, bao gồm cả tài khoản quản trị.

Operator Injection (Chèn toán tử)

Kẻ tấn công sử dụng các toán tử đặc biệt trong NoSQL để thao túng truy vấn, thay đổi logic kiểm tra đầu vào của hệ thống.

Cách thức hiện: Thay vì nhập giá trị bình thường, kẻ tấn công sẽ chèn các toán tử như:

  • $ne (not equal – khác với): Trả về tất cả các bản ghi khác giá trị được kiểm tra.
  • $gt/$lt (greater than/less than): So sánh với giá trị rỗng hoặc nhỏ hơn/lớn hơn một điều kiện cụ thể.
  • $regex (regular expression – khớp biểu thức chính quy): So khớp mọi giá trị theo biểu thức chính quy.

Ví dụ với câu truy vấn trên, nếu  input.username chứa:

{ "$ne": null }

input.username chứa:

{ "$regex": ".*" }

Truy vấn sẽ trở thành:

db.users.find({ "username": { "$ne": null }, "password": { "$regex": ".*" } });

Trong trường hợp này, điều kiện $ne đảm bảo trả về tất cả tài khoản có username không rỗng, bất kể password là gì.

Ví dụ: Nếu input.password được nhập là: 

{ "$gt": "" }

Truy vấn sẽ trở thành:

db.users.find({ "username": input.username, "password": { "$gt": "" } });

Câu truy vấn trên có thể trả về tất cả các tài khoản có mật khẩu lớn hơn chuỗi rỗng, bỏ qua xác thực.

Exploitation via JavaScript Injection (Tiêm mã JavaScript)

Một số cơ sở dữ liệu NoSQL như MongoDB hỗ trợ chèn mã JavaScript vào truy vấn, kẻ tấn công có thể thực thi mã độc trên cơ sở dữ liệu thông qua đầu vào người dùng để truy xuất dữ liệu nhạy cảm, gây gián đoạn hệ thống, hoặc khai thác thêm lỗ hổng bảo mật.

Kẻ tấn công thường dùng:

  • Toán tử $where để phép chèn mã JavaScript trực tiếp.
  • Các hàm JavaScript phổ biến như startsWith(), match() hoặc vòng lặp for để tạo ra điều kiện tùy chỉnh nhằm dò tìm dữ liệu nhạy cảm.

Ví dụ với câu truy vấn trên, nếu kẻ tấn công nhập:

input = { "$where": "this.password.startsWith('admin')" };

Truy vấn sẽ trở thành:

db.users.find({ 

"username": input.username, "$where": "this.password.startsWith('admin')" 

});

Trong đó:

  • Mã JavaScript “this.password.startsWith(‘admin’)” kiểm tra tất cả các tài khoản có mật khẩu bắt đầu bằng “admin”
  • Kẻ tấn công có thể sử dụng cách này để dò tìm mật khẩu hoặc tài khoản hợp lệ.

Tác động của NoSQL Injection

  • Truy cập trái phép: Kẻ tấn công có thể vượt qua các bước xác thực và đăng nhập vào hệ thống mà không cần thông tin hợp lệ.
  • Rò rỉ dữ liệu: Các thông tin nhạy cảm như mật khẩu, thông tin cá nhân có thể bị truy xuất.
  • Phá hủy hoặc sửa đổi dữ liệu: Dữ liệu quan trọng có thể bị thay đổi hoặc xóa, gây thiệt hại lớn.
  • Tấn công từ chối dịch vụ (DoS): Các truy vấn độc hại có thể làm quá tải cơ sở dữ liệu, gây gián đoạn hoạt động của hệ thống.

Nêu một số cách phòng ngừa NoSQL Injection

Hậu quả của một cuộc tấn công NoSQL Injection có thể rất nghiêm trọng, bao gồm việc kẻ tấn công truy cập trái phép vào dữ liệu nhạy cảm, thay đổi hoặc xóa dữ liệu quan trọng hoặc thậm chí làm gián đoạn toàn bộ hệ thống thông qua các truy vấn độc hại. Những thiệt hại này không chỉ ảnh hưởng đến uy tín của tổ chức mà còn dẫn đến mất mát tài chính hoặc vi phạm các quy định về bảo mật dữ liệu.

Vì vậy, để bảo vệ hệ thống và giảm thiểu rủi ro từ NoSQL Injection, cần áp dụng các biện pháp phòng ngừa một cách toàn diện như sau:

  • Kiểm tra và làm sạch dữ liệu đầu vào: Sử dụng danh sách ký tự hợp lệ (allowlist); Loại bỏ các ký tự đặc biệt như ‘, “, $, {, }
  • Hạn chế sử dụng các tính năng nguy hiểm: như các toán tử $where hoặc $regex nếu không cần thiết.
  • Ẩn thông tin lỗi: Không hiển thị lỗi chi tiết để tránh bị khai thác.
  • Giới hạn quyền: Chỉ cấp quyền tối thiểu cho tài khoản truy vấn cơ sở dữ liệu.
  • Kiểm tra và cập nhật thường xuyên: bằng cách sử dụng các công cụ quét bảo mật để phát hiện lỗ hổng và đảm bảo cơ sở dữ liệu được cập nhật bản vá bảo mật mới nhất.

Những thách thức bảo mật trong NoSQL là gì?

Mặc dù NoSQL được thiết kế để xử lý dữ liệu lớn và hỗ trợ hệ thống phân tán hiệu quả, nó cũng đối mặt với nhiều thách thức bảo mật do kiến trúc phi truyền thống và sự đa dạng trong các loại cơ sở dữ liệu. Dưới đây là những thách thức bảo mật phổ biến trong NoSQL:

  • Thiếu kiểm soát truy cập chặt chẽ: Một số cơ sở dữ liệu NoSQL không có hoặc chỉ cung cấp các cơ chế kiểm soát truy cập cơ bản, như xác thực người dùng và phân quyền, dẫn đến việc dữ liệu bị truy cập trái phép.
  • Mã hóa dữ liệu không đầy đủ: Nhiều hệ thống NoSQL không mặc định hỗ trợ mã hóa dữ liệu khi lưu trữ (encryption at rest) hoặc khi truyền qua mạng (encryption in transit), làm tăng rủi ro rò rỉ dữ liệu nếu hệ thống bị tấn công.
  • Tính nhất quán và khả năng chịu lỗi: Các cơ chế như eventual consistency có thể dẫn đến tình trạng dữ liệu tạm thời không đồng bộ, làm tăng nguy cơ tấn công vào các điểm yếu trong quá trình đồng bộ hóa dữ liệu.
  • Tấn công injection: Giống như SQL injection, NoSQL cũng dễ bị NoSQL injection, trong đó kẻ tấn công chèn các đoạn mã độc vào truy vấn để truy cập hoặc thay đổi dữ liệu trái phép.
  • Thiếu nhật ký (logging) và giám sát bảo mật: Một số hệ thống NoSQL không hỗ trợ đầy đủ tính năng ghi nhật ký hoặc giám sát các hoạt động truy cập, khiến việc phát hiện và ứng phó với sự cố bảo mật khó khăn hơn.
  • Các biện pháp triển khai phức tạp: Do dữ liệu được phân tán trên nhiều nút hoặc shard, việc đảm bảo bảo mật nhất quán trên toàn bộ hệ thống trở nên phức tạp hơn, đặc biệt khi sao lưu hoặc di chuyển dữ liệu.

Vai trò của ACL (Access Control List) trong NoSQL?

ACL (Access Control List) là một danh sách các quy tắc được sử dụng để kiểm soát quyền truy cập vào tài nguyên trong một hệ thống, chẳng hạn như cơ sở dữ liệu, tệp tin hoặc ứng dụng. Mỗi mục trong danh sách (entry) xác định:

  1. Ai có quyền truy cập (ví dụ: người dùng, nhóm người dùng hoặc vai trò).
  2. Hành động nào được phép thực hiện trên tài nguyên (ví dụ: đọc, ghi, sửa, xóa).
  3. Tài nguyên được áp dụng quy tắc (ví dụ: một tệp tin cụ thể, bảng dữ liệu hoặc URL).

Khi làm việc với cơ sở dữ liệu NoSQL, đặc biệt trong các dự án yêu cầu quản lý dữ liệu người dùng nhạy cảm, kỹ năng thiết lập ACL (Access Control List) là một trong những yếu tố cốt lõi để đảm bảo bảo mật.

ACL giúp kiểm soát quyền truy cập vào tài nguyên dữ liệu, đảm bảo rằng chỉ những người hoặc hệ thống được ủy quyền mới có thể thực hiện các thao tác trên dữ liệu.

Vai trò của ACL trong bảo mật NoSQL

  • Kiểm soát truy cập linh hoạt: Với NoSQL, dữ liệu thường không có cấu trúc chặt chẽ như SQL, do đó ACL cần được thiết kế linh hoạt để phù hợp với từng tài nguyên (collections, documents, etc.).
  • Phân quyền dựa trên vai trò: ACL trong NoSQL thường được thiết lập dựa trên các vai trò (roles) như Admin, User, hoặc Service. Điều này đảm bảo mỗi nhóm chỉ có quyền truy cập cần thiết, giảm thiểu nguy cơ bị lạm dụng.
  • Tăng cường bảo mật: ACL giúp giảm thiểu quyền không cần thiết, hạn chế quyền ghi hoặc xóa dữ liệu ở các cấp truy cập không phù hợp, bảo vệ hệ thống trước các tấn công như NoSQL Injection.

Kỹ năng cần có khi thiết lập ACL trong NoSQL

  • Hiểu cấu trúc NoSQL: Phân biệt giữa các loại cơ sở dữ liệu NoSQL như MongoDB, Firebase, CouchDB và cách ACL được lưu trữ hoặc tích hợp trong từng loại.
  • Sử dụng công cụ bảo mật nội bộ: Một số NoSQL (như MongoDB Atlas hoặc Firebase) cung cấp sẵn công cụ ACL để thiết lập quyền. Biết cách sử dụng chúng là một kỹ năng quan trọng.
  • Xây dựng logic kiểm tra quyền: Trong các hệ thống không có hỗ trợ ACL tích hợp, lập trình viên cần thiết kế logic kiểm tra quyền thủ công trong ứng dụng. Và việc này đòi hỏi kỹ năng lập trình và quản lý cấu trúc dữ liệu ACL.

Tính năng hỗ trợ mã hoá dữ liệu trong NoSQL

Hầu hết các hệ quản trị cơ sở dữ liệu NoSQL hiện đại đều hỗ trợ mã hóa dữ liệu nhằm đảm bảo tính bảo mật, đặc biệt trong các hệ thống yêu cầu lưu trữ thông tin nhạy cảm. Mã hóa dữ liệu trong NoSQL thường được triển khai ở hai cấp độ chính:

Mã hóa dữ liệu khi lưu trữ (Encryption at Rest)

Dữ liệu được mã hóa khi lưu trong đĩa cứng hoặc các môi trường lưu trữ như SSD và HDD.

  • Một số hệ quản trị NoSQL có tính năng này gồm:
  • MongoDB: Hỗ trợ mã hóa dữ liệu tại chỗ bằng Encrypted Storage Engine. Người dùng có thể bật mã hóa tại tầng lưu trữ thông qua các khóa mã hóa được quản lý bởi hệ thống quản lý khóa (KMS) như AWS KMS, Azure Key Vault hoặc GCP KMS.
  • Cassandra: Hỗ trợ mã hóa dữ liệu tại rest bằng cách cấu hình các encryption providers.
  • Firebase: Google Cloud Firestore mã hóa toàn bộ dữ liệu lưu trữ bằng các tiêu chuẩn AES-256.

Mã hóa dữ liệu khi truyền tải (Encryption in Transit)

Dữ liệu được mã hóa khi truyền qua mạng, đảm bảo không bị đọc lén hoặc chỉnh sửa trong quá trình truyền tải.

  • Các hệ quản trị NoSQL như MongoDB, CouchDB và Cassandra đều hỗ trợ kết nối mã hóa thông qua giao thức TLS/SSL (Transport Layer Security/Secure Sockets Layer).

Một số lưu ý về mã hóa trong NoSQL

Mã hóa có thể làm giảm tốc độ hệ thống

Khi kích hoạt mã hóa, cơ sở dữ liệu phải thực hiện thêm các thao tác mã hóa (encrypt) và giải mã (decrypt) dữ liệu mỗi khi lưu trữ hoặc truy xuất dẫn đến tiêu tốn tài nguyên CPU và làm tăng độ trễ xử lý, đặc biệt với các hệ thống xử lý khối lượng lớn dữ liệu hoặc yêu cầu tốc độ cao.

Ví dụ, khi thực hiện các truy vấn phức tạp trên dữ liệu đã mã hóa, thời gian xử lý có thể tăng lên đáng kể. Vì vậy, trước khi áp dụng mã hóa toàn diện, lập trình viên cần kiểm tra và đánh giá hiệu suất hệ thống, đảm bảo rằng việc mã hóa không gây ảnh hưởng quá lớn đến trải nghiệm người dùng hoặc hoạt động của hệ thống.

Khóa mã hóa cần được bảo vệ an toàn

Khóa mã hóa là yếu tố quan trọng nhất trong cơ chế mã hóa dữ liệu, vì nó chính là chìa khóa để giải mã dữ liệu. Nếu khóa này bị lộ hoặc bị đánh cắp, toàn bộ dữ liệu mã hóa có thể bị giải mã và rò rỉ. Do đó, việc bảo vệ khóa mã hóa cần được ưu tiên hàng đầu.

Một số dịch vụ quản lý khoá chuyên dụng mà lập trình viên có thể cân nhắc sử dụng để lưu trữ và quản lý khoá một cách an toàn là AWS KMS, Azure Key Vault hoặc Google Cloud KMS. Đồng thời, hạn chế quyền truy cập vào khóa mã hóa, chỉ cho phép các dịch vụ hoặc người dùng thực sự cần thiết sử dụng khóa.

Mức độ mã hóa khác nhau tùy vào nhu cầu

Không phải tất cả dữ liệu trong cơ sở dữ liệu đều cần được mã hóa. Dữ liệu nhạy cảm như mật khẩu, số thẻ tín dụng hoặc thông tin cá nhân cần được mã hóa mạnh để bảo vệ khỏi truy cập trái phép. Tuy nhiên, các dữ liệu ít quan trọng hơn như tên sản phẩm, mô tả hoặc thông tin công khai có thể không cần mã hóa để tiết kiệm tài nguyên và tối ưu hiệu suất.

Một số hệ quản trị NoSQL như MongoDB, cung cấp tính năng mã hóa từng trường (field-level encryption), cho phép lập trình viên chỉ mã hóa những trường dữ liệu quan trọng, tránh lãng phí tài nguyên không cần thiết.

Không nên phụ thuộc hoàn toàn vào mã hóa

Mã hóa là một lớp bảo mật mạnh mẽ, nhưng nó không thể thay thế cho các biện pháp bảo mật khác. Nếu hệ thống không có cơ chế kiểm tra quyền truy cập (ACL) hoặc xác thực người dùng mạnh (strong authentication), kẻ tấn công vẫn có thể truy cập vào dữ liệu dù đã được mã hóa.

Ví dụ, nếu ứng dụng bị tấn công bằng NoSQL Injection, mã hóa có thể không ngăn chặn được kẻ tấn công truy cập vào dữ liệu trước khi nó được mã hóa.

Vì vậy, mã hóa nên được kết hợp với các lớp bảo mật khác như xác thực người dùng, phân quyền và kiểm tra nhật ký truy cập để đảm bảo toàn diện.

Chọn công nghệ mã hóa hiện đại

Để đảm bảo dữ liệu được bảo vệ hiệu quả, bạn nên sử dụng các thuật toán mã hóa mạnh mẽ và được tiêu chuẩn hóa. Tránh sử dụng các thuật toán cũ hoặc đã lỗi thời như DES hoặc RC4, vì chúng có thể dễ dàng bị tấn công bằng các công cụ hiện đại.

Ngoài ra, bạn cần đảm bảo rằng hệ thống luôn được cập nhật để tận dụng các cải tiến mới nhất trong công nghệ mã hóa và bảo mật.

Phân biệt giữa xác thực máy khách và người dùng trong MongoDB

Trong MongoDB, xác thực máy khách (client authentication) và xác thực người dùng (user authentication) là hai cơ chế quan trọng được sử dụng để bảo vệ hệ thống, nhưng chúng phục vụ các mục đích và cấp độ bảo mật khác nhau.

  • Xác thực máy khách (Client Authentication): là quá trình kiểm tra danh tính của một ứng dụng hoặc hệ thống đang cố gắng kết nối với MongoDB. Quá trình này thường xảy ra ở cấp độ mạng hoặc giao thức trước khi bất kỳ truy vấn nào được thực hiện trên cơ sở dữ liệu. 
  • Xác thực người dùng (User Authentication): Xác thực người dùng hoạt động bên trong MongoDB, tập trung vào quản lý quyền truy cập dữ liệu. Sau khi một kết nối được thiết lập, mỗi người dùng cần được xác thực bằng tên, mật khẩu và các thao tác của họ sẽ bị giới hạn dựa trên vai trò (role).

Một số khác biệt chính giữa xác thực máy khách và người dùng trong MongoDB:

Tiêu chí Xác thực máy khách Xác thực người dùng
Đối tượng xác thực Ứng dụng, máy chủ hoặc hệ thống muốn kết nối tới MongoDB. Người dùng hoặc tài khoản cố gắng thực hiện các thao tác trên cơ sở dữ liệu.
Mục đích chính Đảm bảo rằng chỉ các ứng dụng hoặc máy chủ được ủy quyền mới được phép kết nối với MongoDB. Đảm bảo rằng chỉ những người dùng hợp lệ mới có thể truy cập và thao tác trên tài nguyên cơ sở dữ liệu.
Cấp độ bảo mật Bảo mật ở cấp độ kết nối mạng, xác minh danh tính trước khi truy cập cơ sở dữ liệu. Bảo mật ở cấp độ truy cập dữ liệu, xác minh quyền thao tác trên các tài nguyên cụ thể.
Phương pháp xác thực – Dựa trên chứng chỉ số (TLS/SSL để bảo mật và xác thực kết nối, X.509 certificates để định danh máy khách). – Dựa trên tên người dùng và mật khẩu hoặc qua dịch vụ xác thực bên ngoài như LDAP hoặc Kerberos.

– Phân quyền cho người dùng bằng Role-Based Access Control (RBAC)

Cách thiết lập – Cấu hình máy chủ MongoDB yêu cầu chứng chỉ hợp lệ khi kết nối.

– Kích hoạt chế độ TLS/SSL để mã hóa và xác thực kết nối.

– Tạo người dùng trong cơ sở dữ liệu MongoDB với vai trò cụ thể.

– Gán quyền hạn cho từng vai trò dựa trên RBAC.

Quyền truy cập dữ liệu Không cung cấp quyền truy cập dữ liệu, chỉ đảm bảo kết nối đến máy chủ MongoDB là hợp lệ. Quyền truy cập cụ thể vào dữ liệu được gán dựa trên vai trò (Admin, ReadOnly, ReadWrite, …).
Bảo mật nâng cao Ngăn kẻ tấn công truy cập trái phép từ máy khách không được xác thực hoặc không có chứng chỉ hợp lệ. Ngăn người dùng thực hiện các thao tác trái phép trên cơ sở dữ liệu hoặc vượt quá quyền hạn được cấp.

Các câu hỏi phỏng vấn ​​NoSQL Integration (tích hợp NoSQL)

Polyglot Persistence là gì?

Polyglot Persistence là khái niệm sử dụng nhiều loại cơ sở dữ liệu khác nhau trong cùng một hệ thống để tận dụng ưu điểm của từng loại cơ sở dữ liệu cho các tác vụ cụ thể. Thay vì chỉ dựa vào một loại cơ sở dữ liệu duy nhất, Polyglot Persistence cho phép bạn chọn cơ sở dữ liệu phù hợp nhất với từng trường hợp sử dụng, chẳng hạn như:

  • Sử dụng MongoDB cho lưu trữ dữ liệu tài liệu.
  • Sử dụng Cassandra cho dữ liệu phân tán.
  • Sử dụng SQL Server cho dữ liệu giao dịch.

Lợi ích và thách thức của Polyglot Persistence

Lợi ích Thách thức
Tối ưu hóa hiệu suất: Tận dụng điểm mạnh của từng loại cơ sở dữ liệu. Quản lý phức tạp: Phải thiết lập, vận hành và bảo trì nhiều loại cơ sở dữ liệu cùng lúc, đòi hỏi đội ngũ kỹ thuật có kiến thức đa dạng.
Linh hoạt: Phù hợp với các ứng dụng đa dạng với nhiều yêu cầu lưu trữ khác nhau. Chi phí cao: Chi phí phát triển, triển khai và bảo trì có thể cao hơn so với việc sử dụng một loại cơ sở dữ liệu duy nhất.
Tăng khả năng mở rộng: Mỗi cơ sở dữ liệu được tối ưu hóa cho một nhiệm vụ cụ thể. Phức tạp trong đồng bộ hóa dữ liệu: Đảm bảo dữ liệu nhất quán giữa các cơ sở dữ liệu khác nhau là một thách thức lớn, đặc biệt trong các hệ thống phân tán
Cải thiện bảo mật: Giảm rủi ro bằng cách phân tán dữ liệu nhạy cảm vào các hệ quản trị an toàn.

Khi nào sử dụng Polyglot Persistence?

Mặc dù Polyglot Persistence có thể gây ra một số hạn chế nhất định nhưng với khả năng tận dụng tối đa thế mạnh riêng của từng công cụ, nó trở thành một giải pháp phù hợp cho các hệ thống lớn và đa dạng với một số trường hợp như:

  • Ứng dụng yêu cầu hiệu suất cao: Khi cần tăng tốc độ truy xuất dữ liệu hoặc giảm độ trễ trong các thành phần khác nhau của hệ thống. Ví dụ Redis được sử dụng làm bộ nhớ đệm để giảm tải cho cơ sở dữ liệu chính trong các ứng dụng thương mại điện tử.
  • Hệ thống phức tạp và đa chức năng: Các hệ thống lớn như thương mại điện tử hoặc mạng xã hội thường cần tích hợp nhiều loại cơ sở dữ liệu để xử lý các tác vụ khác nhau (gợi ý sản phẩm, quản lý đơn hàng, phân tích hành vi người dùng) và xử lý đa dạng loại dữ liệu. Ví dụ với một hệ thống thương mại điện tử có thể sử dụng SQL (MySQL, PostgreSQL) để lưu thông tin giao dịch, khách hàng, sử dụng (NoSQL (MongoDB) để lưu thông tin sản phẩm với cấu trúc linh hoạt và sử dụng Key-Value Store (Redis) lưu trữ giỏ hàng để tăng tốc độ truy cập.
  • Ứng dụng có khối lượng dữ liệu lớn và yêu cầu khả năng mở rộng linh hoạt: Khi cần lưu trữ dữ liệu khổng lồ và yêu cầu mở rộng theo chiều ngang mà không làm giảm hiệu suất.Ví dụ DynamoDB được sử dụng để lưu trữ dữ liệu IoT với khả năng xử lý write-heavy và kết hợp với HDFS để lưu trữ lâu dài.
  • Khi hệ thống cần tích hợp nhiều nguồn dữ liệu: Nếu hệ thống phải thu thập và tích hợp dữ liệu từ nhiều nguồn (API, logs, dữ liệu người dùng, dữ liệu bên ngoài) thì Polyglot Persistence là giải pháp phù hợp. Ví dụ bạn có thể sử dụng MongoDB để lưu trữ dữ liệu người dùng, sử dụng Redis làm bộ nhớ đệm cho dữ liệu tạm thời và sử dụng PostgreSQL quản lý các bảng báo cáo.

Làm thế nào để di chuyển dữ liệu từ SQL sang NoSQL? 

Việc chuyển dữ liệu từ SQL sang NoSQL đòi hỏi sự chuyển đổi cả về dữ liệu lẫn tư duy thiết kế vì cách lưu trữ dữ liệu ở SQL và NoSQL hoàn toàn khác nhau. Dưới đây là các bước chính:

Phân tích dữ liệu

Phân tích dữ liệu hiện tại: Trước khi di chuyển dữ liệu, cần phân tích kỹ lưỡng cấu trúc dữ liệu hiện tại trong SQL để xác định cách tổ chức dữ liệu trong NoSQL. Các đặc trưng cần phân tích lưu ý như:

  • Xác định bảng và vai trò của chúng
  • Phân tích các mối quan hệ giữa các bảng
  • Phân loại kiểu dữ liệu để chọn cách chuyển đổi cho phù hợp

Thiết kế cấu trúc mới

Sau khi hiểu được đặc điểm của dữ liệu và tuỳ vào loại dữ liệu mà đưa ra lựa chọn loại cơ sở dữ liệu NoSQL với các yếu tố như:

Loại cơ sở dữ liệu NoSQL phù hợp:

  • Document-based (MongoDB): Phù hợp với dữ liệu bán cấu trúc hoặc phi cấu trúc.
  • Key-Value Store (Redis): Tốt cho caching hoặc lưu trữ dữ liệu tạm thời.
  • Columnar Store (Cassandra): Phù hợp với dữ liệu chuỗi thời gian hoặc xử lý khối lượng lớn dữ liệu.
  • Graph Database (Neo4j): Phân tích mối quan hệ phức tạp giữa các thực thể.

Xác định cách tổ chức dữ liệu:

  • Nhúng dữ liệu (Embedding): Lưu trữ thông tin liên quan trong cùng một tài liệu. Ví dụ một người dùng cùng danh sách đơn hàng của họ được lưu trong một tài liệu MongoDB.
  • Tham chiếu dữ liệu (Referencing): Sử dụng ID để liên kết các tài liệu riêng biệt. Ví dụ như lưu thông tin người dùng trong một tài liệu và các đơn hàng trong một tài liệu khác.

Ví dụ ta có 2 bảng usersorders như sau trong SQL:

users:

| user_id |    name  | 

|---------|----------| 

|    1    | John Doe | 

orders: 

| order_id | user_id | amount |

|----------|---------|--------| 

|101       | 1       | 50     | 

| 102      | 1       | 100    |

Nếu ta chuyển thành tài liệu NoSQL với cấu trúc nhúng (embedded) thì sẽ có dạng sau:

{

  "user_id": "1",

  "name": "John Doe",

  "orders": [

     { "order_id": "101", "amount": 50 }, 

     { "order_id": "102", "amount": 100} 

  ] 

}

Xuất dữ liệu từ SQL

Dữ liệu từ cơ sở dữ liệu SQL được xuất sang các định dạng phù hợp như CSV, JSON hoặc XML. Ví dụ trong MySQL sẽ có cú pháp như sau:

mysqldump -u root -p --no-create-info --tab=/path/to/export mydatabase

Với cú pháp trên ta sẽ được 2 file là users.csv chứa thông tin người dùng và orders.csv chứa thông tin đơn hàng.

Chuyển đổi dữ liệu sang định dạng NoSQL

Tiếp theo ta sẽ chuyển đổi dữ liệu SQL để tương thích với cấu trúc NoSQL.

Ví dụ nếu bạn sử dụng Python để chuyển đổi thì sẽ có cú pháp như sau:

import json

 # Chuyển đổi dữ liệu từ SQL sang JSON 

sql_data = { 

     "user_id": 1,

     "name": "John Doe",

     "orders": [ 

            {"order_id": 101, "amount": 50},

            {"order_id": 102, "amount": 100} ] 

     } 

json_data = json.dumps(sql_data) 

Nhập dữ liệu vào NoSQL

Tiếp theo, ta sẽ sử dụng các công cụ hoặc API của NoSQL để nhập dữ liệu

Ví dụ trong MongoDb, ta sẽ sử dụng mongoimport để nhập tệp JSON với cú pháp như sau:

mongoimport --db mydatabase --collection users --file users.json --jsonArray

Ví dụ trong Cassandra, ta sẽ sử dụng CQLSH để nhập dữ liệu từ tệp CSV với cú pháp như sau:

COPY users (user_id, name) FROM 'users.csv' WITH HEADER = TRUE;

Kiểm tra và xác thực dữ liệu

Cuối cùng, ta sẽ so sánh dữ liệu trong NoSQL với dữ liệu gốc từ SQL để đảm bảo dữ liệu không bị mất hoặc sai lệch. Để cẩn thận hơn thì bạn có thể thử nghiệm một số truy vấn trên NoSQL để đảm bảo rằng dữ liệu được tổ chức và truy xuất đúng cách.

Làm thế nào để tối ưu hóa và bảo trì sau khi di chuyển?

Sau khi hoàn tất việc di chuyển, cần thực hiện tối ưu hóa và bảo trì để đảm bảo hệ thống hoạt động hiệu quả và ổn định:

Tối ưu hóa truy vấn

  • Phân tích các truy vấn thực tế trên NoSQL để phát hiện điểm yếu.
  • Tạo chỉ mục phù hợp cho các trường thường xuyên được truy vấn để tăng tốc độ đọc.
  • Tránh lạm dụng chỉ mục vì có thể ảnh hưởng đến tốc độ ghi.

Phân bổ và cân bằng dữ liệu

Đối với cơ sở dữ liệu phân tán như MongoDB hoặc Cassandra, cần đảm bảo dữ liệu được phân mảnh (sharding) và phân phối đồng đều giữa các nút.

Tối ưu hóa dung lượng lưu trữ

  • Sử dụng cơ chế TTL (Time-to-Live) để tự động xóa dữ liệu cũ hoặc không còn cần thiết.
  • Kiểm tra và dọn dẹp các bản ghi dư thừa để tiết kiệm tài nguyên.

Giám sát và bảo trì hệ thống

  • Triển khai các công cụ giám sát để theo dõi hiệu suất đọc/ghi và phát hiện các vấn đề như bottleneck hoặc lỗi hệ thống.
  • Lên kế hoạch sao lưu định kỳ để đảm bảo an toàn dữ liệu.
  • Kiểm tra và cập nhật các phiên bản phần mềm NoSQL để tận dụng tính năng mới và vá lỗi bảo mật.

Tổng kết câu hỏi phỏng vấn NoSQL

NoSQL không chỉ là một xu hướng, mà còn là công cụ mạnh mẽ để xử lý dữ liệu lớn và tối ưu hóa hệ thống. Và không chỉ dừng lại ở lý thuyết, việc chứng minh bạn đã thực sự sử dụng và giải quyết các thách thức liên quan đến NoSQL qua các ví dụ cụ thể và kinh nghiệm sử dụng thực tế sẽ giúp bạn ghi điểm trong mắt nhà tuyển dụng.

ITviec hy vọng bài viết trên đã cung cấp cho bạn những câu hỏi phỏng vấn NoSQL hữu ích để sẵn sàng cho buổi phỏng vấn NoSQL.