0

[Series Hệ thống chịu tải cao] Bài 3: Elasticsearch – Tốc độ tìm kiếm "tia chớp" đến từ đâu?

Chào anh em! Trong bài trước, chúng ta đã đưa dữ liệu quẹt thẻ Metro vào Kafka an toàn rồi. Nhưng giờ sếp bảo: "Cho anh xem danh sách tất cả những người dùng thẻ sinh viên, quẹt ở ga Suối Tiên trong 5 phút vừa qua".

Nếu bạn quăng câu Query này vào một table SQL có vài trăm triệu dòng, khả năng cao là bạn sẽ có đủ thời gian để đi pha một ly cà phê trước khi kết quả hiện ra. Nhưng với Elasticsearch, kết quả sẽ hiện ra ngay khi bạn vừa dứt ngón tay khỏi phím Enter.

Tại sao nó lại nhanh đến mức "phi lý" như vậy? Bí mật nằm ở 3 từ khóa: Inverted Index.

1. Inverted Index: Bảng mục lục "đảo ngược"

Hãy tưởng tượng bạn có 3 cuốn sách (Document):

  • Doc 1: "Hành khách quẹt thẻ tại ga Bến Thành"
  • Doc 2: "Sinh viên quẹt thẻ tại ga Suối Tiên"
  • Doc 3: "Hành khách nạp tiền tại ga Bến Thành"

Thay vì đi đọc từng Doc để tìm chữ "Bến Thành" (giống như lệnh LIKE %...% trong SQL), ES sẽ bóc tách tất cả các từ ra và lập một cái bảng như sau:

Từ khóa (Term) Xuất hiện ở Document nào?
Hành khách Doc 1, Doc 3
Quẹt thẻ Doc 1, Doc 2
Hành khách Doc 1, Doc 3
Suối Tiên Doc 2

Khi bạn search "Bến Thành", ES chỉ cần liếc qua cái bảng này và biết ngay nó nằm ở Doc 1 và Doc 3. Nó không cần quan tâm hệ thống có 1 triệu hay 1 tỷ bản ghi, tốc độ truy xuất gần như là hằng số.

2. Document-oriented: Lưu trữ kiểu "Sẵn sàng để đọc"

Khác với SQL chia dữ liệu ra nhiều table rồi dùng JOIN (cực kỳ tốn tài nguyên), ES lưu trữ dữ liệu dưới dạng JSON Documents.

Mọi thông tin liên quan đến một sự kiện (User, Ga, Loại thẻ, Thời gian) đều nằm gọn trong một Document. Khi cần lấy dữ liệu, ES chỉ việc bốc nguyên cái "gói" đó ra. Việc hy sinh không gian lưu trữ (ghi lặp dữ liệu) để đổi lấy tốc độ đọc chính là triết lý của ES.

3. Chia để trị: Sharding và Replication

Tương tự như Partition trong Kafka, ES chia một Index (tương đương với một Table trong SQL) thành nhiều Shards:

  • Mỗi Shard là một đơn vị tìm kiếm độc lập.
  • Khi bạn gửi một câu truy vấn, tất cả các Shards trên nhiều server khác nhau sẽ cùng làm việc cùng lúc (Parallel Processing) để tìm kết quả, sau đó gộp lại trả về cho bạn.

Ngoài ra, mỗi Shard đều có bản sao (Replica). Nếu một node (server) bị sập, hệ thống vẫn hoạt động bình thường và dữ liệu vẫn an toàn.

Kinh nghiệm thực tế: Khi nào "Thủ thư" ES mệt mỏi?

Dù mạnh mẽ, nhưng ES có một điểm yếu: Nó cực kỳ lười khi phải ghi (Write). Vì mỗi khi có dữ liệu mới, ES phải thực hiện hàng loạt thao tác: Tách từ (Tokenize), đánh chỉ mục (Indexing)... nên tốc độ ghi không bao giờ bằng Kafka hay các Database chuyên ghi.

Đó là lý do tại sao trong hệ thống Metro (AFC), mình không bao giờ bắt ES làm nhiệm vụ ghi dữ liệu trực tiếp từ cổng quẹt thẻ.

  1. Cổng quẹt thẻ đẩy data vào Kafka (Ghi cực nhanh).
  2. Một service khác sẽ lẳng lặng nhặt data từ Kafka rồi "bón" dần dần cho Elasticsearch.

Tạm kết

Elasticsearch nhanh vì nó biết cách tổ chức dữ liệu thông minh và tận dụng tối đa sức mạnh của tính toán song song. Nếu Kafka là "xương sống" để vận chuyển dữ liệu, thì ES chính là "bộ não" để truy xuất và phân tích dữ liệu đó.

Trong bài tiếp theo (Bài 4), mình sẽ hướng dẫn anh em cách thiết lập "cuộc hẹn hò" giữa hai gã khổng lồ này: Kết nối Kafka với Elasticsearch để dữ liệu chảy tự động và tức thì.

Anh em đã bao giờ thử dùng Elasticsearch để làm tính năng Autocomplete (gợi ý tìm kiếm) chưa? Cảm giác "mượt" lắm đúng không? Hãy comment chia sẻ trải nghiệm nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí