Kiến trúc hệ thống tracking người dùng đáp ứng dữ liệu lớn

Nguyễn Minh Đức
Edumall Engineering
7 min readNov 23, 2019

Đặt vấn đề

Có một câu nói rất hay thế này : “Ai hiểu khách hàng hơn, người đó sẽ bán được nhiều hơn”.
Việc hiểu khách hàng là rất quan trọng, quan trọng với mọi doanh nghiệp bán hàng. Với bất kỳ một lĩnh vực nào, việc hiểu được khách hàng sử dụng dịch vụ của mình sẽ giúp hiểu hơn về khách hàng quan tâm điều gì, có thấy hứng thú không! Từ đó có thể chăm sóc được cho từng cá nhân khách hàng tốt hơn.
Với thời đại công nghệ số, việc thu thập data của người dùng thông qua các website của mỗi doanh nghiệp không còn gì xa lạ. Nhưng với những doanh nghiệp lớn, việc thu thập cũng như những lưu trữ lên đến hàng TB dữ liệu như thế này, sẽ cần việc thiết kế hệ thống nhằm đáp ứng được hai vấn đề lớn:

  • Đáp ứng được lượng concurrent request lớn.
  • Đảm bảo không thất thoát data tracking.

Giải pháp thiết kế thế nào để đảm bảo hai yếu tố trên, cùng mổ xẻ vào 1 kiến trúc hệ thống tracking mà người viết đã tham gia xây dựng.

Sơ đồ kiến trúc hệ thống tracking tổng quan

Kiến trúc hệ thống tracking tổng quan

Chia kiến trúc hệ thống thành 4 thành phần chính gồm có

  1. Phần gateway hứng request
  2. Message queue
  3. Service đứng sau
  4. Document Database

Luồng đi của hệ thống tracking sẽ như sau:

Cổng gateway sẽ trực tiếp hứng request từ user.

Đẩy các request này đến 1 message queue (Kafka) lưu trữ tạm thời (đầu pub).

Trong lúc đó đầu sub của message queue chính là service đứng sau, service này sẽ nhặt những message trong Message Queue đẩy vào một queue cài đặt riêng của nó.

Các worker trong service sẽ nhặt những message trong queue riêng này để đẩy vào document database.

Vậy tại sao lại thiết kế như vậy, tại sao lựa chọn các công nghệ trên, chúng là gì ? Chúng ta hãy cùng tìm hiểu qua nhé!

Công nghệ được lựa chọn

  1. Phần gateway hứng request

Mục tiêu là phải đảm bảo chịu được số lượng concurrent request lớn.

Lựa chọn công nghệ: Nodejs

Lí do lựa chọn:

Đầu tiên nên chọn công nghệ mang tính scripting vì bản thân cổng gateway chỉ có vai trò là chuyển request data về kho queue đằng sau. Việc chọn những công nghệ như Rails, Java sẽ phải load nhiều thứ đi kèm, sẽ nặng và không cần thiết.

Nodejs là một công nghệ phù hợp vì nó mang tính scripting, dễ viết và dễ tiếp cận (Javascript).

Thứ hai và cũng là yếu tố chính đó chính là Nodejs hỗ trợ cơ chế non-blocking. Và với những bài toán đặc thù như việc phản ứng với các event được bắn ra từ client vốn là đất diễn của Nodejs nhờ vào non-blocking.

Nodejs chạy trên cơ chế non-blocking và event Driven Loop, vì vậy nó chỉ single thread cho nên tốc độ nhanh và nhẹ. Nodejs có "Single Thread Event Loop" để handle multiple concurrent clients. Trong khi các web application technologies như JSP, SpringMVC, ASP.NET sử dụng kiến trúc "Multi-Threaded Request-Response". Vậy giữa chúng có điểm gì khác nhau ?

Với kiến trúc MTRR, chúng ta có thể gọi đơn giản là nó sử dụng Request/Response model.

Client gửi request cho server, sau đó server xử lý trả về kết quả cho client. Model này sử dụng giao thức HTTP (là Stateless Protocol).

Nhìn vào hình ảnh, ta thấy luồng đi như sau:

  • Clients gửi request đến web server
  • Web server có 1 cái pool chứa 1 số giới hạn các thread (limited thread) nhằm cung cấp các service phục vụ cho request đến. Đồng thời web server có một vòng lặp vô hạn quét và đợi request đến.
  • Khi một request đến, webserver sẽ chọn 1 thread trong pool và assign request đến cho nó. Thread này sẽ care việc đọc request, xử lý, thực hiện bất cứ 1 Blocking IO operations và chuẩn bị response
  • Thread này gửi response cho web server và web server trả về cho client tương ứng

Kiểu model kiến trúc này sẽ gắn 1 thread cho 1 client request. Như vậy nếu càng nhiều request yêu cầu Blocking IO Operations, dẫn đến tất cả các thread đều bận, các request đến sau sẽ phải chờ.

Như vậy khi lượng request đồng thời đến của các client tăng lên, web server sẽ sử dụng nhiều thread, như vậy sẽ tốn nhiều memory hơn.

Vậy thì Single Thread Event Loop sẽ khác ra sao ?

NodeJs tuân theo kiến trúc Single Threaded với Event Loop Model. Việc xử lý của NodejJs dựa trên Javascript Event based model với cơ chế Callback.

Trái tim của NodeJS Processing model là "Event Loop".

  • Clients gửi request đến Web server.
  • Nodejs Web server cũng có một pool chứa limited Thread để cấp các service cho request.
  • NodeJs Web server nhận các request và đặt chúng vào 1 cái Queue, gọi là "Event Queue".
  • Nodejs Web server có 1 component là "Event Loop". Tên như vậy vì nó là một vòng lặp vô hạn nhận request và xử lý chúng.
  • Event Loop sử dụng đơn luồng (Single Thread). Event loop check nếu có request, bắt đầu quá trình xử lý.
  • Nếu Request ko yêu cầu bất cứ Blocking IO Operations nào cả hoặc task tính toán dễ dàng thì Event Loop sẽ tự tay xử lý mọi thứ trả về cho client.
  • Nếu request yêu cầu 1 vài cái Blocking IO Operation như tương tác vs DB, hệ thống khác thì sẽ check nếu còn sẵn thread trong pool thì assgn request cho thread đó. Thread nhận request, xử lý và trả về cho Event Loop. Event Loop nhận và trả về cho client tương ứng

Như vậy thì có thể thấy việc handle nhiều concurrent client's request là dễ dàng. Mặc dù NodeJS Application nhận nhiều concurrent request hơn nhưng nó ko phải tạo nhiều thread hơn.

2. Message queue

Lựa chọn công nghệ: Kafka

Apache Kafka là hệ thống truyền thông điệp phân tán, độ tin cậy cao, dễ dàng mở rộng và có thông lượng cao. Kafka cung cấp cơ chế offset (có thể hiểu tương tự như chỉ số của một mảng) để lấy thông điệp một cách linh hoạt, cho phép các ứng dụng xử lý có thể xử lý lại dữ liệu nếu việc xử lý trước đó bị lỗi.

Điều này rất hữu ích, lúc trước người viết có sử dụng 1 service đọc từ kafka ra lưu vào kudu nhưng check thấy sót 1 số bản ghi. Nhờ điểm offset có thể đẩy lại tại message có chỉ số đó mà ko phải đẩy lại từ đầu. Ngoài ra, cơ chế "đăng kí" theo dỗi cho phép việc lấy thông điệp ra gần như tức thời ngay khi dữ liệu đi vào hàng đợi. Kafka được thiết kế hỗ trợ tốt cho vệc thu thập dữ liệu thời gian thực. Apache Kafka có những đặc điểm như:

  • Tốc độ nhanh
  • Khả năng mở rộng
  • Độ tin cậy

So sánh với các hệ thống truyền thông điệp lâu đời như RabbitMQ thì cùng 1 cấu hình, Kafka cho thấy lượng đọc ghi dữ liệu cao hơn mà lại chiếm ít tài nguyên hơn. Do đó Kafka thích hợp hơn cho các ứng dụng xử lý thời gian thực với lượng dữ liệu lớn.

3. Service đứng sau

Công nghệ sử dụng: Ruby Rails + Sidekiq.

Lí do lựa chọn:

Rails là ngôn ngữ viết service phổ biến, tương thích với hệ sinh thái trong trong doanh nghiệp của người viết. Đó là lí do lựa chọn nó.

Service viết bằng Rails này đọc message từ kafka ra đổ vào sidekiq. Sau đó service có 5 worker sẽ đồng thời tiêu thụ chỗ message trong sidekiq này để đổ vào Database.Việc thiết lập số lượng worker này có thể tùy biến được trong service

Sidekiq có trình quản lý cho phép xem được thông tin lượng request tiêu thụ.

4. Database

Lựa chọn công nghệ: MongoDB

MongoDB rất nhanh cho việc ghi dữ liệu.

Theo tìm hiểu của người viết thì việc ghi dữ liệu vào MongoDB nhanh hơn rất nhiều so với Sql. Với cấu hình Ram 4Gb, chip 4 core i5 có thể nhận được lượng ghi khoảng 80000 request đồng thời.

Kết luận

Thực ra trong kiến trúc này có nhiều điểm còn chưa tối ưu. Ví dụ như sử dụng tận 2 message queue là Kafka và Sidekiq.

Và cũng có nhiều bàn luận quay quanh các điểm trong kiến trúc:

  1. Có thể bỏ hết tất cả cụm Message Queue (Kafka) và Service đi, vì MongoDB có thể nhận được lượng request lớn ghi vào đồng thời.
  2. Sử dụng Message Queue (Kafka) vì như giới thiệu nó có cơ chế offset, hơn nữa có thể lưu trữ các bản ghi tạm thời xuống ổ cứng. Như vậy sẽ không bị thất thoát dữ liệu.
  3. Sidekiq có thể config lượng worker tiêu thụ message cũng như có trình quản lý.

Người viết hi vọng sẽ nhận được các ý kiến khác nhau nhằm tìm hiểu sâu hơn về các yếu tố trong kiến trúc này.

Vài dòng chia sẻ tới các bạn.

Tài liệu tham khảo

https://viblo.asia/p/hang-doi-thong-diep-apache-kafka-jvEla6145kw

--

--