Xây dựng hệ thống thông báo [đã đóng]


170

Tôi đang bắt đầu xây dựng một hệ thống thông báo kiểu Facebook cho trang của chúng tôi (loại trò chơi xã hội) và tôi hiện đang nghiên cứu cách tốt nhất để thiết kế hệ thống đó là gì. Tôi không quan tâm đến cách đẩy thông báo đến người dùng hoặc bất cứ điều gì tương tự (ngay cả bây giờ). Tôi đang nghiên cứu cách xây dựng hệ thống trên máy chủ (cách lưu trữ thông báo, nơi lưu trữ chúng, cách tìm nạp chúng, v.v ...).

Vì vậy, ... một số yêu cầu mà chúng tôi có:

  • vào những lúc cao điểm, chúng tôi có khoảng 1k người dùng đăng nhập đồng thời (và nhiều khách nữa, nhưng họ không quan trọng ở đây vì họ sẽ không có thông báo) sẽ tạo ra nhiều sự kiện
  • sẽ có nhiều loại thông báo khác nhau (người dùng A đã thêm bạn với tư cách bạn bè, người dùng B đã nhận xét về hồ sơ của bạn, người dùng C đã thích hình ảnh của bạn, người dùng D đã đánh bại bạn trên trò chơi X, ...)
  • hầu hết các sự kiện sẽ tạo 1 thông báo cho 1 người dùng (người dùng X thích hình ảnh của bạn), nhưng sẽ có trường hợp một sự kiện sẽ tạo ra nhiều thông báo (ví dụ như sinh nhật của người dùng Y)
  • thông báo nên được nhóm lại với nhau; ví dụ: bốn người dùng khác nhau thích một số hình ảnh, chủ sở hữu của hình ảnh đó sẽ nhận được một thông báo cho biết bốn người dùng đã thích hình ảnh đó chứ không phải bốn thông báo riêng biệt (giống như FB vậy)

OK, điều tôi nghĩ là tôi nên tạo ra một số hàng đợi nơi tôi sẽ lưu trữ các sự kiện khi chúng xảy ra. Sau đó, tôi sẽ có một công việc nền ( gearman ?) Sẽ xem xét hàng đợi đó và tạo thông báo dựa trên những sự kiện đó. Công việc này sau đó sẽ lưu trữ thông báo trong cơ sở dữ liệu cho mỗi người dùng (vì vậy nếu một sự kiện ảnh hưởng đến 10 người dùng, sẽ có 10 thông báo riêng biệt). Sau đó, khi người dùng mở một trang với danh sách các thông báo, tôi sẽ đọc tất cả các thông báo đó cho anh ta (chúng tôi nghĩ sẽ giới hạn 100 thông báo mới nhất này) và nhóm chúng lại với nhau và cuối cùng hiển thị chúng.

Những điều tôi quan tâm với phương pháp này:

  • phức tạp như địa ngục :)
  • là cơ sở dữ liệu lưu trữ tốt nhất ở đây (chúng tôi đang sử dụng MySQL) hoặc tôi nên sử dụng cái gì khác (redis có vẻ cũng phù hợp)
  • Tôi nên lưu trữ những gì như một thông báo? ID người dùng, ID người dùng đã khởi tạo sự kiện, loại sự kiện (để tôi có thể nhóm chúng và hiển thị văn bản phù hợp) nhưng sau đó tôi không biết cách lưu trữ dữ liệu thực tế của thông báo (ví dụ: URL & tiêu đề của hình ảnh đã thích). Tôi chỉ nên "nướng" thông tin đó khi tôi tạo thông báo hoặc tôi nên lưu ID của bản ghi (hình ảnh, hồ sơ, ...) bị ảnh hưởng và kéo thông tin ra khỏi DB khi hiển thị thông báo.
  • hiệu suất sẽ ổn ở đây, ngay cả khi tôi phải xử lý 100 thông báo nhanh chóng khi hiển thị trang thông báo
  • vấn đề hiệu suất có thể xảy ra đối với mọi yêu cầu vì tôi sẽ phải hiển thị số lượng thông báo chưa đọc cho người dùng (đây có thể là sự cố do tôi sẽ nhóm các thông báo cùng nhau). Điều này có thể tránh được mặc dù nếu tôi tạo chế độ xem thông báo (nơi chúng được nhóm) ở chế độ nền và không hoạt động

Vì vậy, bạn nghĩ gì về giải pháp đề xuất của tôi và mối quan tâm của tôi? Hãy bình luận nếu bạn nghĩ tôi nên đề cập đến bất cứ điều gì khác có liên quan ở đây.

Ồ, chúng tôi đang sử dụng PHP cho trang của mình, nhưng đó không phải là một yếu tố lớn ở đây tôi nghĩ.


Bạn mất bao nhiêu thời gian để xây dựng hệ thống thông báo này khi một người nỗ lực. Tôi chỉ muốn có một ước tính để đưa ra các mốc thời gian phù hợp.
Shaharyar

@Shaharyar Tôi nghĩ nó phụ thuộc vào độ phức tạp của hệ thống thông báo.
tyan

Tôi đã sử dụng cùng một hệ thống với MySQL để xây dựng một hệ thống thông báo dựa trên mức độ ưu tiên. Điều tốt là nó có quy mô tới vài nghìn người dùng, nếu nó đi nhiều hơn thế, nó sẽ nổ tung, đặc biệt là với Android và GCM. Tôi muốn biết các lựa chọn thay thế cho MySQL như redis, rabbitMQ, Kafka, một cách tự nhiên thể hiện một hàng đợi tin nhắn, loại chức năng.
Ankit Marothi

Câu trả lời:


168

Một thông báo là về một cái gì đó (object = event, Friendship ..) đang được thay đổi (verb = thêm, yêu cầu ..) bởi ai đó (diễn viên) và báo cáo cho người dùng (chủ đề). Đây là cấu trúc dữ liệu được chuẩn hóa (mặc dù tôi đã sử dụng MongoDB). Bạn cần thông báo cho người dùng nhất định về những thay đổi. Vì vậy, đó là thông báo cho mỗi người dùng .. có nghĩa là nếu có 100 người dùng tham gia, bạn sẽ tạo ra 100 thông báo.

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
║notification ║      ║notification_object║      ║notification_change ║
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
║ID           ║—1:n—→║ID                 ║—1:n—→║ID                  ║
║userID       ║      ║notificationID     ║      ║notificationObjectID║
╚═════════════╝      ║object             ║      ║verb                ║
                     ╚═══════════════════╝      ║actor               ║
                                                ╚════════════════════╝

(Thêm các trường thời gian mà bạn thấy phù hợp)

Điều này về cơ bản là để nhóm các thay đổi cho mỗi đối tượng, để bạn có thể nói "Bạn có 3 yêu cầu kết bạn". Và nhóm theo từng diễn viên là hữu ích, do đó bạn có thể nói "Người dùng James Bond đã thực hiện thay đổi trên giường của bạn". Điều này cũng cung cấp khả năng dịch và đếm thông báo theo ý muốn.

Nhưng, vì đối tượng chỉ là một ID, bạn sẽ cần nhận được tất cả thông tin bổ sung về đối tượng bạn muốn bằng các cuộc gọi riêng biệt, trừ khi đối tượng thực sự thay đổi và bạn muốn hiển thị lịch sử đó (ví dụ: "người dùng đã thay đổi tiêu đề của sự kiện thành ... ")

Vì các thông báo gần với thời gian thực cho người dùng trên trang web, tôi sẽ liên kết chúng với máy khách nodejs + websockets với php đẩy cập nhật lên nodejs cho tất cả người nghe khi thay đổi được thêm vào.


1
notify_object.object xác định loại thay đổi, như chuỗi "tình bạn" Tham chiếu thực tế đến đối tượng đã thay đổi với dữ liệu bổ sung mà tôi nói đến là trong
notify_change.notificationObjectID

2
Đây có thể là một câu hỏi ngớ ngẩn nhưng với thiết lập này, bạn sẽ làm gì khi người dùng đã nhìn thấy hoặc hành động theo thông báo? Bạn chỉ cần xóa nó khỏi cơ sở dữ liệu hoặc chỉ sử dụng ngày để xem người dùng đã đăng nhập kể từ khi thông báo được tạo chưa?
Jeffery Mills

4
Tôi biết chủ đề này đã khá cũ, tuy nhiên tôi hơi bối rối về bảng đầu tiên, mục đích chính xác của bảng này là gì? lợi thế của việc có cái này như một bảng riêng biệt so với việc đặt userID vào bảng notify_object là gì? Nói cách khác, khi nào bạn sẽ tạo một mục mới trong thông báo và khi nào bạn sẽ thêm một đối tượng và thay đổi thành thông báo hiện có với cấu trúc này?
Bas Goossen

3
@JefferyMills Bạn có thể có một trường trạng thái như is_notification_readtrong notificationbảng và đánh dấu nó một cách thích hợp nếu có unread, readhoặc deleted.
Kevin

2
Tôi cũng đã đấu tranh để hiểu một số khía cạnh của giải pháp này và đưa ra một câu hỏi riêng về nó: dba.stackexchange.com/questions/99401/ Lỗi
user45623

27

Đây thực sự là một câu hỏi trừu tượng, vì vậy tôi đoán chúng ta sẽ phải thảo luận về nó thay vì chỉ ra những gì bạn nên hoặc không nên làm.

Đây là những gì tôi nghĩ về mối quan tâm của bạn:

  • Vâng, một hệ thống thông báo là phức tạp, nhưng không phải là địa ngục. Bạn có thể có nhiều cách tiếp cận khác nhau về mô hình hóa và thực hiện các hệ thống như vậy, và chúng có thể có từ mức độ trung bình đến mức độ phức tạp cao;

  • Bên cạnh đó, tôi luôn cố gắng tạo ra các công cụ dựa trên cơ sở dữ liệu. Tại sao? Bởi vì tôi có thể đảm bảo có toàn quyền kiểm soát mọi thứ đang diễn ra - nhưng đó chỉ là tôi, bạn có thể kiểm soát mà không cần cách tiếp cận dựa trên cơ sở dữ liệu; hãy tin tôi, bạn sẽ muốn kiểm soát trường hợp đó;

  • Hãy để tôi làm gương cho một trường hợp thực sự cho bạn, để bạn có thể bắt đầu từ một nơi nào đó. Trong năm qua, tôi đã lập mô hình và triển khai một hệ thống thông báo trong một loại mạng xã hội nào đó (tất nhiên không giống như facebook). Cách tôi sử dụng để lưu trữ thông báo ở đó? Tôi đã có một notificationsbảng, nơi tôi giữ generator_user_id(ID của người dùng đang tạo thông báo), target_user_id(loại rõ ràng, phải không?), notification_type_id(Được tham chiếu đến một bảng khác với các loại thông báo) và tất cả những thứ cần thiết chúng ta cần điền vào bảng của mình (dấu thời gian, cờ, v.v.). notification_typesBảng của tôi đã từng có mối quan hệ với một notification_templatesbảng, lưu trữ các mẫu cụ thể cho từng loại thông báo. Chẳng hạn, tôi có một POST_REPLYkiểu, có kiểu như thế {USER} HAS REPLIED ONE OF YOUR #POSTS. Từ đó, tôi mới điều trị{}như một biến và #là một liên kết tham chiếu;

  • Có, hiệu suất nênphải ổn. Khi bạn nghĩ về thông báo, bạn nghĩ đến việc máy chủ đẩy từ đầu đến chân. Hoặc nếu bạn sẽ làm điều đó với các yêu cầu ajax hoặc bất cứ điều gì, bạn sẽ phải lo lắng về hiệu suất. Nhưng tôi nghĩ đó là mối quan tâm lần thứ hai;

Tất nhiên, mô hình mà tôi đã thiết kế không phải là mô hình duy nhất mà bạn có thể làm theo, cũng không phải là tốt nhất. Tôi hy vọng câu trả lời của tôi, ít nhất, theo bạn đi đúng hướng.


Tại sao tôi không có quyền kiểm soát với một số cửa hàng dữ liệu khác?
Jan Hančič

Chà, tôi đã không nói thế. Điều tôi đã nói là tôi chỉ có thể đảm bảo kiểm soát dữ liệu với cách tiếp cận dựa trên cơ sở dữ liệu; nhưng đó chỉ là tôi. Tôi sẽ viết lại điều đó.
Daniel Ribeiro

@DanielRibeiro trình giữ chỗ ({...}) trong mẫu thông báo cần thay thế dữ liệu của trình giữ chỗ từ nhóm bảng khác nhau trong cơ sở dữ liệu cho các loại thông báo khác nhau. Ví dụ: một mẫu là "{user} đã thích ảnh của bạn.", Một mẫu khác là "{Pagename} của bạn có lượt thích mới". V.v. {PageName} và {user} và các trình giữ chỗ khác sẽ ánh xạ từ bảng cơ sở dữ liệu khác nhau, do đó, lược đồ nên lấy giá trị giữ chỗ một cách linh hoạt.
Ashish Shukla

DanielRibeiro làm thế nào bạn thay thế trình giữ chỗ như được hỏi bởi @Ashish Shukla,
Tupe

@AshishShukla bạn đã sử dụng hoặc thay thế giữ chỗ, và làm thế nào?
Trì Tupe

8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Đây có vẻ là một câu trả lời tốt hơn là có 2 bộ sưu tập. Bạn có thể truy vấn theo tên người dùng, đối tượng và isRead để nhận các sự kiện mới (như 3 yêu cầu kết bạn đang chờ xử lý, 4 câu hỏi được hỏi, v.v.)

Hãy cho tôi biết nếu có vấn đề với lược đồ này.


3
Câu trả lời hàng đầu đã sử dụng cấu trúc dữ liệu chuẩn hóa, có nghĩa là không có dự phòng trong các bảng. Câu trả lời của bạn có làm điều đó không?
Aaron Hall

4

Cá nhân tôi không hiểu rõ sơ đồ cho câu trả lời được chấp nhận, vì vậy tôi sẽ đính kèm sơ đồ cơ sở dữ liệu dựa trên những gì tôi có thể học được từ câu trả lời được chấp nhận và các trang khác.

nhập mô tả hình ảnh ở đây

Những cải tiến được đón nhận.


Có vẻ như message_template sẽ nằm trong bảng Thông báo. Cũng có vẻ như main_url sẽ nằm trong bảng thông báo, sau đó bạn có thể loại bỏ bảng Notification_Message. Bạn có thể giải thích lý do bạn có bảng NotificationMessage không?
Jeff Ryan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.