Thiết kế hệ thống phục vụ hàng triệu người dùng
Hôm nay cuối tuần ở nhà rảnh rỗi không có gì làm nên lại ngứa tay viết một bài để chia sẻ lại hệ thống nhận diện user spam comment...
Hôm nay cuối tuần ở nhà rảnh rỗi không có gì làm nên lại ngứa tay viết một bài để chia sẻ lại hệ thống nhận diện user spam comment có thể phục vụ hàng triệu người dùng mà không có điểm chết
Sau bài viết này tôi hi vọng có thể giúp các bạn thiết kế ra một hệ thống mà với hệ thống đó các bạn có thể tự tin tuyên bố rằng Hệ thống của tôi là trường tồn với thời gian, sống cùng trời đất bất chấp số lượng user, CCU có nhiều đến đâu :))
Nào bắt đầu thôi !!!

Việc đầu tiên khi thiết kế một hệ thống hay bắt đầu của một dự án là chúng ta cần làm rõ đề bài là gì, khách hàng cần gì. Đấy nhắc đến những thứ này tôi lại có cảm xúc dạt dào khi đi làm một BA bất đắc dĩ. Làm sao để giải thích cho người không hiểu về kỹ thuật để họ hiểu về kỹ thuật, làm sao để khai thác những thứ cần thiết từ khách hàng để thiết kế hệ thống cho đúng trong khi họ không biết được họ muốn những gì. Nói chung là nhiều lúc chỉ muốn đấm nhau :)))
Mà thôi lại lan man, quay lại chủ đề chính. Chúng ta cần lấy đề bài và yêu cầu.
#Đề bài: Hãy thiết kế hệ thống nhận diện người dùng spam có khả năng nhận diện 14 triệu comment một ngày và có khoảng 1 triệu người dùng trong 1 ngày
#Yêu cầu: Nhận diện được user spam càng sớm càng tốt và tỉ lệ sai sót thấp.

Không sao tôi là super man lại thêm nhiệt tình nên tôi sẽ làm cho bạn thoả mãn :))

Khi đã có đầy đủ yêu cầu việc tiếp theo chúng ta cần làm là xác định các thành phần chính cần có trong hệ thống.
#Xác định các thành phần của hệ thống
Nhận diện spam comment dựa trên nội dung để có thể phát hiện realtime, ngăn chặn sớm các tin lừa đảo, mua bán dâm,…Nhận diện spam comment dựa trên hành vi: để có thể phát hiện ra các trường hợp mà nhận diện dựa trên nội dung không phát hiện ra. Bởi vì nội dung có thể có nhiều cách thay đổi để lách luật nhưng hành vi thì hầu như là không thay đổi.Hệ thống hybrid để tận dụng điểm mạnh của 2 phần trên và để khắc phục ưu nhược điểm của nhau từ đó để có kết quả tốt nhất.CMS: để cảnh báo cho các admin quản trị hệ thống
Xác định được các thành phần chính rồi giờ thì chúng ta sẽ làm gì để xử lý được dữ liệu lớn trong thời gian realtime đây.
Và đây là cách

Với mô hình trên các khối sẽ giao tiếp với nhau qua Queue. Vì sao tôi lại lựa chọn dùng queue thay vì gọi API như mô hình truyền thống ? Câu trả lời là vì để xử lý một lượng dữ liệu lớn trong khoảng thời gian ngắn thì chúng ta cần chia nhỏ dữ liệu ra và xử lý phân tán và song song trên nhiều server trong cùng 1 lúc. Tức là nếu ta xử lý 1 request hết 10s thì nếu ra phân tán và xử lý song song 1000 request cùng 1 lúc thì 1000 request cũng chỉ hết 10s mà mà thôi.
#Cách thức hoạt động của hệ thống
Cụ thể, với mô hình này luồng làm việc sẽ như sau:
Bước 1: Khi người dùng comment sẽ được chuyển lên queue. Từ đây, sẽ có n số lượng consumer trên m của khối Comment Consumer tiếp nhận comment và nhận diện dựa trên nội dung bằng AI và bằng luật có sẵn (khối Rule based xử lý).
Bước 2: Sau khi comment của người dùng được nhận diện dựa trên nội dung xong thì sẽ được ghi vào file local lưu vào HDFS, kết quả nhận diện và user id của người dùng sẽ gửi lại queue và được các consumer của khối Behavior based nhận diện dựa trên hành vi từ trong log lịch sử được ghi vào HDFS (Khối File local storage).
Bước 3: Kết quả nhận diện hành vi và nhận diện dựa trên nội dung sẽ được chuyển đến khối Hybrid để tận dụng ưu điểm của cả 2 khối hành vi và nội dung. Cuối cùng kết quả sẽ được gửi về queue để cho các phần mềm bên thứ 3 nhận kết quả và hiển thị cảnh báo lên CMS.
Các khối hỗ trợ nhưng không thể thiếu là Monitor và Central Log.
#Monitor
Tôi thường thấy phần này các bạn nhất là các bạn mới vào nghề hay quên đi phần monitor. Đối với hệ thống nhỏ thì có thể các bạn ít khi phải quan tâm đến sự sống chết, lỗi phát sinh có hay không. Nhưng đối với các hệ thống lớn nhất là hệ thống phân tán thì việc quản lý tiến trình nào đang chạy, tiến trình nào bị chết, trong quá trình chạy có exception không rất là quan trọng để đảm bảo cho service luôn luôn trong trạng thái active hoặc có sự cố thì khắc phục kịp thời.
Trong phần này thì các bạn nên cảnh báo tất cả các vấn đền đến điện thoại của các bạn thông qua các api free như api của telegram hoặc các api nội bộ miễn là các cảnh báo đó luôn hiển thị đến mắt bạn khi cần thiết.
Ngoài việc check service của bạn sống hay chết thì việc cảnh báo các exception và traceback phát sinh bất kỳ cũng nên được đặt vào monitor. Vì trong quá trình dev thì việc để lọt case hay bạn không lường trước được exception là điều bình thường nên hãy luôn đặt try catch và trong catch sẽ get traceback và gửi đoạn traceback đó về điện thoại của bạn.
Đối với hệ thống này của tôi có một luật rất chặt chẽ và cũng rất nguy hiểm đó là với những user spam sẽ bị khoá tài khoản trong khi đó, việc AI nhận diện nhầm là việc không thể tránh khỏi nên một ngày đẹp trời khi bạn deploy mô hình mới hay admin thêm một luật mới và làm cho toàn bộ user trong hệ thống bị khoá tài khoản. Để tránh cái ngày đẹp trời đó thì trong hệ thống Monitor tôi làm ra một cơ chế mà tôi gọi là cơ chế Áp-tô-mát. Đó là khi số lượng user được phát hiện là spam tăng bất thường, đột biến so với các ngày thì sẽ không tự động khoá tài khoản người dùng nữa mà chuyển sang cơ chế chỉ cảnh báo trên CMS và thông báo đến toàn bộ đến những người có “chức trách” để nhận định rằng hệ thống có phát sinh lỗi không. Nếu không lỗi gì thì sẽ cho tắt Áp-tô-mát để tiếp tục tự động khoá tài khoản sau khi phát hiện được người dùng spam.
À một phần quan trọng nữa là bạn nên gửi hostname và ip của server kèm theo log để còn biết node nào trong cụm bị lỗi nhé
#Central Log
Vì đây là hệ thống phân tán nên thông tin 1 request của bạn sẽ được ngẫu nhiên 1 server nào đó trong hệ thống phân tán của bạn xử lý (Nói là ngẫu nhiên thôi chứ thực tế là thằng server nào khoẻ hơn, nhanh hơn thì tỉ lệ cao rơi vào thằng đó). Như vậy phát sinh ra một vấn đề khi bạn cần check log thì bạn phải vào tất cả server đó để check. 1,2 server thì ok chứ 100 server thì ssh vào được hết chắc mất cả ngày rồi nói gì đến việc check rồi fix lỗi. Như vậy, vấn đề cần đẩy log về một nơi tập trung là việc cần thiết.
#Ưu và nhược điểm
“Cái gì cũng có 2 mặt của nó và khó khăn không bao giờ là hết chỉ là chuyển từ trạng thái này sang trạng thái khác” và hệ thống này cũng vậy.
Ưu điểm:
Xử lý song song và phân tán, dữ liệu được lưu trữ trên tất cả các server nên nó luôn hoạt động dựa trên mô hình active – active. Tức là dù có 1 server chết thì cũng không ảnh hưởng đến hệ thống. Hệ thống chỉ chết khi tất cả server cùng chết.Tận dụng cơ chết FIFO của Queue nên server nào mạnh, xử lý nhanh thì sẽ get được nhiều message từ queue về xử lý nhiều hơn các server yếu hơn. Vì vậy, vấn đề quản lý tài nguyên cho cụm phân tán được giải quyết phần nào. Còn nếu muốn control kỹ hơn về tài nguyên và phân loại tài nguyên thì bạn nên nghiên cứu thử YARN.Dễ dàng scale: vì là mô hình phân tán active – active nên bạn chỉ cần thêm server hoặc ổ cứng miễn là server cứ có ram, có cpu và có điện là join và cụm phân tán là chạy được đồng nghĩ với việc tiết kiệm chi phí.
Nhược điểm:
#Túm cái váy lại
Điểm mấu chốt của hệ thống này là việc bạn dùng queue làm thứ trung gian để giao tiếp giữa các khối hay các service và việc chia nhỏ các khối hay chia 1 service to thành service nhỏ, điều luồng một cách tài tình từ đồng bộ thành bất đồng bộ và ngược lại để tận dụng tối đa khả năng xử lý song song.
Hãy luôn nhớ câu chuyện bó đũa Cái gì to thì mình cứ chia nhỏ nó ra.
Một hệ thống không chỉ có thiết kế phần mềm mà việc thiết kế hạ tầng vật lý và công nghệ sử dụng cũng hết sức quan trọng nhưng bài viết dài quá rồi nên tôi sẽ nói tiếp trong một bài viết khác.
1s quảng cáo :3

Khoa học - Công nghệ
/khoa-hoc-cong-nghe
Bài viết nổi bật khác
- Hot nhất
- Mới nhất
SG Han
Cảm ơn về bài viết của bạn, mình cũng làm dev nhưng còn thiếu kinh nghiệm. Chưa có cơ hội làm với hệ thống có lượng người dùng lớn như vậy ? Rất mong được bạn chia sẻ kinh nghiệm
- Báo cáo

Đức Thắng
Nếu bạn cần gì có thể comment hoặc inbox trực tiếp cho mình 

- Báo cáo
SG Han
Cảm ơn bạn đã trả lời. Mình học trái ngành và mới chuyển qua làm bên dev khoảng 2 năm nay. Mình cảm thấy bản thân khá yếu vì nhiều lúc chỉ biết cách làm thông qua tìm kiếm trên google. Mình muốn hỏi là theo bạn cần phải học 1 số môn nào bắt buộc để có thể tiến xa hơn trong ngành?
- Báo cáo

Đức Thắng
Theo kinh nghiệm cá nhân thì ban đầu bạn nên chọn 1 ngôn ngữ và 1 công nghệ để làm quen và dần có tư duy lập trình và tư duy giải quyết bài toán. Khi bạn có 2 điều trên rồi thì bạn có thể bất cứ thứ gì trong ngành công nghệ. Rồi sau đó tùy theo định hướng của bạn mà chọn 1 cái đi sâu để đi tiếp hoặc tạo ra sản phẩm và đem đi bán - startup đó ạ :v
- Báo cáo
SG Han
Cảm ơn bạn ! Mình đang làm nhiều bên Angular
- Báo cáo

Ntech 

Message queue không phải là tối ưu cho mọi dự án nhé. Điểm thứ nhất là message size có giới hạn nếu bạn truyền quá lớn sẽ văng exception. Queue chết hệ thống bạn xử lý tiếp thế nào. Điểm thứ 2 là tính toàn vẹn dữ liệu, khi trễ hoặc mất message trong queue sẽ khiến flow của bạn bị đứt quãng thì bạn sẽ làm gì. Thứ 3 là độ trễ, mình biết có một số dạng message queue streaming tốc độ rất nhanh nhưng mà dù sao đi nữa nó như 1 sợi dây nối dài, càng dài càng dễ đứt và đường truyền tín hiệu bạn càng rủi ro liệu khi bạn cần dữ liệu đồng bộ tại 1 điểm cuối thì bạn quản lý nó ra sao?
Mình muốn nghe ý kiến của bạn!
- Báo cáo

Đức Thắng
Nhận xét của bạn rất đúng. Message queue không phải thứ toàn năng cho mọi dự án được nhất là những dự án cần sự đồng bộ. Với các hệ thống Queue nếu Queue bị chết thì nó sẽ chết cả hệ thống thôi. giống như các hệ thống khác bị chết server vậy. Còn làm sao để queue k bị chết thì có nhiều cách như cài đặt cụm cluster hoặc dùng LB trỏ vào nhiều cụm queue khác nhau. Như vậy Queue chết khi và chỉ khi tất cả server cùng chết.
Về vấn đề độ trễ thì nó phụ thuộc vào nhiều yếu tố có thể là do bản thân queue, có thể do đường truyền cũng có thể do server,... Nhưng như mình trình bày việc thiết kế một hệ thống thì thiết kế hạ tầng vật lý cũng rất quan trọng mà đôi khi chúng ta quên mất điều quan trọng này. Bạn không thể dùng 1 hệ thống mạng kém cho cụm server được hay dùng mạng 1gbs để truyền dữ liệu lớn, rồi điểm đặt server ở đâu, qua mấy switch, switch loại nào. Tất cả những điều đó hội tụ lại mới có 1 hệ thống tốt. Còn nếu muốn nhanh thì bạn chỉ cần tăng consumer, tăng server để chạy song song hoặc chia nhỏ ra hết sức có thể. Nhưng việc chia nhỏ thì đồng thời khó khăn là phải quản lý nhiều.
- Báo cáo

Ntech 

Nếu khách hàng muốn bạn chứng minh code của mình đủ tốt chưa hay tìm ngưỡng giới hạn của infrastructure hiện tại trước khi bơm tiền nâng cấp cơ sở hạ tầng thì sao ạ. Bạn chứng minh với hệ thống message queue và code hiện tại tốt như thế nào? Bạn có idea gì cho vấn đề này không ạ
- Báo cáo

Đức Thắng
Vấn đề này thì thường sẽ phải dựa trên yếu tố lịch sử. Tức là bạn đã triển khai trên 1 hạ tầng nhất định. Từ đó suy ra cái tương lai. Vd bạn đang chạy 100K user trên hạ tầng 1 server 32 cores, 64GB ram và nó ngốn hết 50% CPU, 50% ram thì nếu tăng 200K user lên thì bạn phải có hạ tầng gấp 2.5 lần hiện tại. Nói chung là bạn sizing hạ tầng sao cho hạ tầng cần mua = hạ tầng tính * 1.1. Trong đó hạ tầng tính là hạ tầng đáp ứng khi deploy CPU chiếm k quá 70%, ram k chiếm quá 80% và ổ cứng k chiếm 80% dung lượng. 1.1 là hệ số để cho trường hợp dự phòng hoặc trường hợp tăng tải đột biến
- Báo cáo

Ntech 

Yếu tố lịch sử, tức là bạn đã và đang chạy trên production rồi và có thông số rồi. Cái ý mình hỏi là khởi nguyên ý, bạn chứng mình với solution hiện tại và cấu hình hạ tầng hiện tại chịu được ngưỡng là bao nhiêu. Vì không đơn giản là khách hàng bỏ một cục tiền nâng cấp hạ tầng. Họ sẽ bắt mình chứng minh trước.
- Báo cáo

Toi Khong Ngu
Theo mình thấy vần đề queue chỉ là mô tả một cách tổng quát ràng tất cả dữ liệu cần xử lý sẽ được đẩy đến một chỗ (đầu vào queue) và sau đó sẽ được lấy ra mỗ chỗ và phần phối đi các nới (đầu ra queue). Ưu điểm là sẽ không cần thay đổi lại mô hình (vẫn như một layer lọc giữa đầu vào đầu ra) nhưng nhược điểm là sẽ có nguy cơ bị ngẽn lại do tất cả yêu cầu đều phải chạy qua một đường đi duy nhất. Tuy nhiên vấn đề không lớn vì đa phần thiết kế queue cho các hệ thống phân tán chỉ có mỗi một việc là chuyển gói tin đi mà không xử lý gì (các server phân tán phía sau chịu tải) nên sẽ không gặp vấn đề đầy hoặc lỗi (tạo 2 queue dự phòng) chủ yếu là vấn đề mạng bị nghẽn thôi nhưng chắc còn xa.
- Báo cáo

Đức Thắng
rất chuẩn ạ 

- Báo cáo

Ntech 

Không hẳn là mạng nghẽn mà là giới hạn của message ý. ví dụ cả RabbitMQ và Azure Service Bus đều có 1MB message ah. Mình toàn phải mượn redis lưu value rồi chỉ send key đi để khi nhận được message thì vào redis lấy ra ngược lại.
- Báo cáo

Toi Khong Ngu
1M là cho 1 message và thế cũng đủ rồi.. Theo cá nhân mình là thế.
- Báo cáo

Văn Khôi Ngô

A đã đọc blog của e, sao e ms 96 mà giỏi vậy =))
- Báo cáo

Đức Thắng
Cảm ơn anh. e đang start up công ty giải pháp công nghệ nếu a cần thì mong a liên hệ ạ :3
- Báo cáo