Cách tốt nhất để thực hiện một luồng hoạt động xã hội là gì? [đóng cửa]


265

Tôi muốn nghe ý kiến ​​của bạn, đó là cách tốt nhất để thực hiện luồng hoạt động xã hội (Facebook là ví dụ nổi tiếng nhất). Các vấn đề / thách thức liên quan là:

  • Các loại hoạt động khác nhau (đăng, bình luận ..)
  • Các loại đối tượng khác nhau (đăng, bình luận, ảnh ..)
  • Người dùng 1-n liên quan đến các vai trò khác nhau ("Người dùng x đã trả lời nhận xét của Người dùng y trên bài đăng Z của Người dùng")
  • Các chế độ xem khác nhau của cùng một mục hoạt động ("bạn đã nhận xét .." so với "bạn của bạn x đã nhận xét" so với "người dùng x đã nhận xét .." => 3 đại diện cho hoạt động "nhận xét")

.. và một số thứ khác, đặc biệt là nếu bạn đưa nó lên mức độ tinh vi cao, chẳng hạn như Facebook, kết hợp một số mục hoạt động thành một ("người dùng x, y và z đã nhận xét về bức ảnh đó"

Bất kỳ suy nghĩ hoặc con trỏ về các mẫu, giấy tờ, vv về các cách tiếp cận linh hoạt, hiệu quả và mạnh mẽ nhất để thực hiện một hệ thống, mô hình dữ liệu, vv sẽ được đánh giá cao.

Mặc dù hầu hết các vấn đề là bất khả tri về nền tảng, nhưng rất có thể tôi sẽ thực hiện một hệ thống như vậy trên Ruby on Rails

Câu trả lời:


143

Tôi đã tạo ra hệ thống như vậy và tôi đã thực hiện phương pháp này:

Bảng cơ sở dữ liệu với các cột sau: id, userId, loại, dữ liệu, thời gian.

  • userId là người dùng đã tạo ra hoạt động
  • loại là loại hoạt động (ví dụ: Viết bài đăng trên blog, thêm ảnh, nhận xét về ảnh của người dùng)
  • dữ liệu là một đối tượng được tuần tự hóa với siêu dữ liệu cho hoạt động mà bạn có thể đặt bất cứ thứ gì bạn muốn

Điều này giới hạn các tìm kiếm / tra cứu, bạn có thể thực hiện trong các nguồn cấp dữ liệu, cho người dùng, thời gian và loại hoạt động, nhưng trong nguồn cấp dữ liệu hoạt động kiểu facebook, điều này thực sự không giới hạn. Và với các chỉ số chính xác trên bàn, việc tra cứu rất nhanh .

Với thiết kế này, bạn sẽ phải quyết định siêu dữ liệu mà mỗi loại sự kiện cần yêu cầu. Ví dụ: một hoạt động nguồn cấp dữ liệu cho một bức ảnh mới có thể trông giống như thế này:

{id:1, userId:1, type:PHOTO, time:2008-10-15 12:00:00, data:{photoId:2089, photoName:A trip to the beach}}

Bạn có thể thấy rằng, mặc dù tên của ảnh chắc chắn được lưu trữ trong một số bảng khác có chứa ảnh và tôi có thể truy xuất tên từ đó, tôi sẽ sao chép tên trong trường siêu dữ liệu, vì bạn không muốn làm bất kỳ tham gia trên các bảng cơ sở dữ liệu khác nếu bạn muốn tốc độ. Và để hiển thị, giả sử 200, các sự kiện khác nhau từ 50 người dùng khác nhau, bạn cần tốc độ.

Sau đó, tôi có các lớp mở rộng một lớp FeedActivity cơ bản để hiển thị các loại mục hoạt động khác nhau. Nhóm các sự kiện cũng sẽ được xây dựng trong mã kết xuất, để tránh sự phức tạp khỏi cơ sở dữ liệu.


3
Đúng, đúng vậy. Gần đây tôi đã sử dụng MongoDB ( mongodb.org ) trong một vài dự án, với cách tiếp cận giản lược của nó làm cho nó rất phù hợp để tạo ra một luồng hoạt động xã hội hiệu quả theo thiết kế này.
heyman

6
TheApprentice: Yep, bạn cũng có thể muốn ném vào trường tên người dùng. Trong hệ thống của chúng tôi, chúng tôi chỉ hiển thị các sự kiện do bạn bè của người dùng tạo và tôi tin rằng chúng tôi đã có bản đồ tên người dùng của bạn bè-> trong bộ nhớ, vì vậy việc tìm kiếm tên người dùng không yêu cầu THAM GIA và nhanh chóng.
heyman

2
Bạn sẽ phải xử lý trường hợp đó bằng tay. Có lẽ tốt nhất để làm điều đó khi ảnh bị xóa (tìm mục nguồn cấp dữ liệu trong nguồn cấp dữ liệu của người dùng và xóa / cập nhật nó).
heyman

21
Tôi không hiểu những gì tuyệt vời về câu trả lời này? Làm thế nào để tạo một bảng đơn giản dịch sang nguồn cấp dữ liệu hoạt động có trọng số tương tự như facebook? Tất cả ngần ngại làm là lưu trữ tất cả các hoạt động. Mà vẫn để lại câu hỏi làm thế nào để biến một bảng dữ liệu thành một nguồn cấp dữ liệu hoạt động có trọng số động?
ChuckKelly

4
@ChuckKelly: Nếu tôi nhớ lại một cách chính xác, vào năm 2008, khi tôi viết câu trả lời, nguồn cấp dữ liệu Facebook hoàn toàn không có trọng lượng. Nó chỉ là một nguồn cấp dữ liệu theo thời gian với tất cả các hoạt động từ bạn bè của bạn.
heyman

117

Đây là một bài trình bày rất hay phác thảo cách Etsy.com kiến ​​trúc các luồng hoạt động của họ. Đó là ví dụ tốt nhất mà tôi đã tìm thấy về chủ đề này, mặc dù nó không phải là cụ thể.

http://www.sl slideshoware.net/danmckinley/etsy-activity-feed-arch architecture


21
^^ Bởi vì bạn phải quay lại SO sau khi truy cập trang web. lol
Stephen Corwin

1
Bài thuyết trình tuyệt vời giải thích chi tiết cách hệ thống hoạt động trên một trang web có lưu lượng truy cập cao thực sự.
ramirami

44

Chúng tôi đã mở nguồn tiếp cận của chúng tôi: https://github.com/tschellenbach/Stream-Framework Đây hiện là thư viện mã nguồn mở lớn nhất nhằm giải quyết vấn đề này.

Cùng một nhóm đã xây dựng Stream Framework cũng cung cấp API được lưu trữ, xử lý sự phức tạp cho bạn. Hãy xem getstream.io Có các ứng dụng khách có sẵn cho Node, Python, Rails và PHP.

Ngoài ra, hãy xem bài đăng có khả năng mở rộng cao này, chúng tôi đã giải thích một số quyết định thiết kế có liên quan: http://highscalability.com/blog/2013/10/28/design-decutions-for-scaling-your-high-traffic- feed.html

Hướng dẫn này sẽ giúp bạn thiết lập một hệ thống như nguồn cấp dữ liệu của Pinterest bằng Redis. Nó khá dễ dàng để bắt đầu với.

Để tìm hiểu thêm về thiết kế nguồn cấp dữ liệu, tôi khuyên bạn nên đọc một số bài viết mà chúng tôi dựa trên Feedly:

Mặc dù Stream Framework dựa trên Python nhưng nó sẽ không quá khó sử dụng từ ứng dụng Ruby. Bạn chỉ có thể chạy nó như một dịch vụ và dán một API http nhỏ phía trước nó. Chúng tôi đang xem xét việc thêm API để truy cập Feedly từ các ngôn ngữ khác. Tại thời điểm này, bạn sẽ phải đóng vai trò của riêng bạn.


19

Các vấn đề lớn nhất với các luồng sự kiện là khả năng hiển thị và hiệu suất; bạn cần hạn chế các sự kiện được hiển thị chỉ là những sự kiện thú vị cho người dùng cụ thể đó và bạn cần giữ thời gian cần thiết để sắp xếp và xác định những sự kiện đó có thể quản lý được. Tôi đã xây dựng một mạng xã hội nhỏ; Tôi thấy rằng ở quy mô nhỏ, việc giữ một bảng "sự kiện" trong cơ sở dữ liệu hoạt động, nhưng nó trở thành một vấn đề về hiệu suất dưới tải vừa phải.

Với một dòng tin nhắn và người dùng lớn hơn, có lẽ tốt nhất là đi cùng với một hệ thống nhắn tin, nơi các sự kiện được gửi dưới dạng tin nhắn đến từng hồ sơ cá nhân. Điều này có nghĩa là bạn không thể dễ dàng đăng ký các luồng sự kiện của mọi người và xem các sự kiện trước đó rất dễ dàng, nhưng bạn chỉ đơn giản là hiển thị một nhóm nhỏ các thông điệp khi bạn cần kết xuất luồng cho một người dùng cụ thể.

Tôi tin rằng đây là lỗ hổng thiết kế ban đầu của Twitter - Tôi nhớ rằng họ đã nhấn vào cơ sở dữ liệu để kéo vào và lọc các sự kiện của họ. Điều này có mọi thứ liên quan đến kiến ​​trúc và không liên quan gì đến Rails, điều mà (không may) đã sinh ra meme "ruby không quy mô". Gần đây tôi đã thấy một bài thuyết trình trong đó nhà phát triển đã sử dụng Dịch vụ xếp hàng đơn giản của Amazon làm phần phụ trợ nhắn tin của họ cho một ứng dụng giống như twitter có khả năng mở rộng cao hơn nhiều - có thể đáng để xem xét SQS như một phần của hệ thống của bạn, nếu tải của bạn đủ cao .


Tim, bạn có còn nhớ tên của bài thuyết trình hay người thuyết trình không?
Danita

đó là tại Oreilly và Associate's Ignite Boston thuyết trình số 3 hoặc 4- Tôi tin rằng người trình bày đã có một cuốn sách về nhân rộng RoR với Oreilly. Xin lỗi tôi không thể cụ thể hơn!
Tim Howland

Cảm ơn Tim :) Nhân tiện, bạn có ý nghĩa gì với "mạng xã hội nhỏ"? Có bao nhiêu người dùng, hoặc người dùng hoạt động tại một thời điểm nhất định?
Danita

3
Trong trường hợp bất cứ ai cần nó, tôi nghĩ đây là bài thuyết trình mà Tim đang nói về: "Dan Chak - Mở rộng quy mô vấn đề của bạn" radar.oreilly.com/2008/09/ignite-boston-4----ideo -uplo.html
Danita

Nhỏ trong trường hợp này là "chọn * từ các sự kiện trong đó event.is hiển thị cho người dùng này" trả về kết quả trong ít hơn một hoặc hai giây cho các sự kiện trị giá vài trăm nghìn hàng.
Tim Howland

12

Nếu bạn sẵn sàng sử dụng một phần mềm riêng biệt, tôi đề xuất máy chủ Graphity giải quyết chính xác vấn đề cho các luồng hoạt động (xây dựng trên cơ sở dữ liệu đồ thị neo4j).

Các thuật toán đã được triển khai như một máy chủ REST độc lập để bạn có thể lưu trữ máy chủ của riêng mình để phân phối các luồng hoạt động: http://www.rene-pickhardt.de/graphity-server-for-social-activity-streams-release-gplv3 /

Trong bài báo và điểm chuẩn tôi đã chỉ ra rằng việc truy xuất các luồng tin tức chỉ phụ thuộc tuyến tính vào số lượng mục bạn muốn truy xuất mà không có bất kỳ sự dư thừa nào bạn sẽ nhận được từ việc không chuẩn hóa dữ liệu:

http://www.rene-pickhardt.de/graphity-an-ffic-graph-model-for-retrieving-the-top-k-news-feed-for-users-in-social-networks/

Trên liên kết trên, bạn tìm thấy screencasts và điểm chuẩn của phương pháp này (cho thấy rằng đồ thị có thể truy xuất hơn 10k luồng mỗi giây).


10

Tôi đã bắt đầu triển khai một hệ thống như thế này ngày hôm qua, đây là nơi tôi đã đến ...

Tôi đã tạo một lớp StreamEvent với các thuộc tính Id , ActorId , TypeId , Date , ObjectId và hàm băm của các cặp khóa / giá trị chi tiết bổ sung . Này được thể hiện trong cơ sở dữ liệu bằng một StreamEvent bảng ( Id , ActorId , typeid , ngày , ObjectId ) và một StreamEventDetails bảng ( StreamEventId , DetailKey , DetailValue ).

Các ActorId , typeidObjectId phép cho một sự kiện Chủ đề-Động từ-Object để được chụp (và sau đó truy vấn). Mỗi hành động có thể dẫn đến một số trường hợp StreamEvent được tạo.

Sau đó, tôi đã tạo một lớp con cho StreamEvent cho từng loại sự kiện, ví dụ: LoginEvent , PictureVerEvent . Mỗi lớp con này có các thuộc tính cụ thể theo ngữ cảnh hơn như PictureId , ThumbNail , CommenText , v.v (bất cứ điều gì cần thiết cho sự kiện) thực sự được lưu trữ dưới dạng cặp khóa / giá trị trong bảng hashtable / StreamEventDetail.

Khi kéo các sự kiện này trở lại từ cơ sở dữ liệu, tôi sử dụng một phương thức xuất xưởng (dựa trên TypeId ) để tạo lớp StreamEvent chính xác.

Mỗi lớp con của StreamEvent có Render ( bối cảnh Như StreamContext phương pháp) mà kết quả đầu ra các sự kiện vào màn hình dựa trên thông qua StreamContext lớp. Lớp StreamContext cho phép các tùy chọn được đặt dựa trên ngữ cảnh của khung nhìn. Nếu bạn xem Facebook chẳng hạn như nguồn cấp tin tức của bạn trên trang chủ liệt kê tên đầy đủ (và liên kết đến hồ sơ của họ) của mọi người liên quan đến từng hành động, trong khi tìm kiếm nguồn cấp dữ liệu của một người bạn, bạn chỉ thấy tên của họ (nhưng tên đầy đủ của các diễn viên khác) .

Tôi chưa triển khai nguồn cấp dữ liệu tổng hợp (nhà Facebook) nhưng tôi tưởng tượng mình sẽ tạo bảng AggregateFeed có các trường UserId , StreamEventId được điền dựa trên một số loại thuật toán 'Hmmm, bạn có thể tìm thấy thuật toán thú vị này'.

Bất kỳ ý kiến ​​sẽ được đánh giá cao.


Tôi đang làm việc trên một hệ thống như thế này rất quan tâm đến bất kỳ kiến ​​thức nào về nó, bạn đã bao giờ hoàn thành của bạn chưa?
JasonDavis

Câu trả lời chính xác! Tuyệt vời tách mối quan tâm, sạch sẽ và thanh lịch!
Mosh

Đây là một khởi đầu tốt! Nó rất giống với cách tôi bắt đầu thực hiện luồng đầu tiên của mình. Tuy nhiên, khi bạn nhận được nguồn cấp dữ liệu tổng hợp, mọi thứ bắt đầu trở nên phức tạp nhanh chóng. Bạn đúng rằng bạn cần một thuật toán mạnh mẽ. Tìm kiếm của tôi đã đưa tôi đến thuật toán của Rene Pickhardt (anh ấy nói về nó trong câu trả lời của anh ấy ở đây), sau đó tôi đã triển khai dịch vụ của mình, hiện là thương mại (xem collabinate.com và câu trả lời của tôi về câu hỏi này để biết thêm).
Mafuba

10
// một mục nhập cho mỗi sự kiện thực tế
sự kiện {
  id, dấu thời gian, loại, dữ liệu
}

// một mục nhập cho mỗi sự kiện, mỗi nguồn cấp có chứa sự kiện đó
event_feed {
  event_id, feed_id
}

Khi sự kiện được tạo, hãy quyết định nguồn cấp dữ liệu nào sẽ xuất hiện và thêm chúng vào event_feed. Để nhận nguồn cấp dữ liệu, hãy chọn từ event_feed, tham gia vào các sự kiện, sắp xếp theo dấu thời gian. Lọc và tổng hợp sau đó có thể được thực hiện trên kết quả của truy vấn đó. Với mô hình này, bạn có thể thay đổi các thuộc tính sự kiện sau khi tạo mà không cần làm thêm.


1
Giả sử người khác được thêm làm bạn bè sau khi sự kiện được thêm vào, bạn cần xem sự kiện này trong nguồn cấp dữ liệu của họ? sau đó, nó sẽ không hoạt động
Joshua Kis gió

8

Nếu bạn quyết định rằng bạn sẽ triển khai trong Rails, có lẽ bạn sẽ thấy plugin sau hữu ích:

ActivityStreams: http://github.com/face/activity_streams/tree/master

Nếu không có gì khác, bạn sẽ xem xét việc triển khai, cả về mô hình dữ liệu, cũng như API được cung cấp cho các hoạt động đẩy và kéo.


6

Tôi đã có một cách tiếp cận tương tự như của heyman - một bảng không chuẩn hóa chứa tất cả dữ liệu sẽ được hiển thị trong một luồng hoạt động nhất định. Nó hoạt động tốt cho một trang web nhỏ với hoạt động hạn chế.

Như đã đề cập ở trên, nó có khả năng phải đối mặt với các vấn đề về khả năng mở rộng khi trang web phát triển. Cá nhân, tôi không lo lắng về các vấn đề mở rộng ngay bây giờ. Tôi sẽ lo lắng về điều đó sau.

Facebook rõ ràng đã làm rất tốt việc mở rộng quy mô vì vậy tôi khuyên bạn nên đọc blog kỹ thuật của họ, vì nó có rất nhiều nội dung tuyệt vời -> http://www.facebook.com/notes.php?id=9445547199

Tôi đã xem xét các giải pháp tốt hơn so với bảng không chuẩn hóa mà tôi đã đề cập ở trên. Một cách khác mà tôi đã tìm thấy để thực hiện điều này là cô đọng tất cả nội dung sẽ có trong một luồng hoạt động nhất định thành một hàng duy nhất. Nó có thể được lưu trữ dưới dạng XML, JSON hoặc một số định dạng nối tiếp mà ứng dụng của bạn có thể đọc được. Quá trình cập nhật cũng sẽ đơn giản. Khi hoạt động, đặt hoạt động mới vào hàng đợi (có thể sử dụng Amazon SQS hoặc thứ gì khác) và sau đó tiếp tục thăm dò hàng đợi cho mục tiếp theo. Lấy mục đó, phân tích cú pháp và đặt nội dung của nó vào đối tượng nguồn cấp dữ liệu thích hợp được lưu trữ trong cơ sở dữ liệu.

Điểm hay của phương pháp này là bạn chỉ cần đọc một bảng cơ sở dữ liệu bất cứ khi nào nguồn cấp dữ liệu cụ thể đó được yêu cầu, thay vì lấy một loạt các bảng. Ngoài ra, nó cho phép bạn duy trì một danh sách các hoạt động hữu hạn vì bạn có thể bật ra mục hoạt động cũ nhất bất cứ khi nào bạn cập nhật danh sách.

Hi vọng điêu nay co ich! :)


Chính xác là suy nghĩ của tôi, tôi chỉ cần xác nhận những suy nghĩ của tôi mà bây giờ tôi có thể có, chúc mừng!
Sohail

5

Có hai bản phát sóng về một luồng hoạt động như vậy:

Những giải pháp đó không bao gồm tất cả các yêu cầu của bạn, nhưng nó sẽ cung cấp cho bạn một số ý tưởng.


1
PublicActivity rất tuyệt và có thể xử lý tất cả các trường hợp sử dụng trong câu hỏi.
DaveStephens

3

Tôi nghĩ cách tiếp cận của Plurk rất thú vị: họ cung cấp toàn bộ dòng thời gian của bạn ở định dạng trông rất giống biểu đồ chứng khoán của Google Finance.

Có thể đáng để nhìn vào Ning để xem mạng xã hội hoạt động như thế nào. Các trang phát triển trông đặc biệt hữu ích.


2

Tôi đã giải quyết điều này một vài tháng trước, nhưng tôi nghĩ việc thực hiện của tôi quá cơ bản.
Tôi đã tạo các mô hình sau:

HISTORY_TYPE

ID           - The id of the history type
NAME         - The name (type of the history)
DESCRIPTION  - A description

HISTORY_MESSAGES

ID
HISTORY_TYPE - A message of history belongs to a history type
MESSAGE      - The message to print, I put variables to be replaced by the actual values

HISTORY_ACTIVITY

ID
MESSAGE_ID    - The message ID to use
VALUES        - The data to use

Thí dụ

MESSAGE_ID_1 => "User %{user} created a new entry"
ACTIVITY_ID_1 => MESSAGE_ID = 1, VALUES = {user: "Rodrigo"}

2

Sau khi triển khai các luồng hoạt động để kích hoạt các nguồn cấp dữ liệu xã hội, tiểu blog và các tính năng cộng tác trong một số ứng dụng, tôi nhận ra rằng chức năng cơ bản khá phổ biến và có thể được chuyển thành một dịch vụ bên ngoài mà bạn sử dụng thông qua API. Nếu bạn đang xây dựng luồng vào ứng dụng sản xuất và không có nhu cầu độc đáo hoặc phức tạp sâu sắc, sử dụng dịch vụ đã được chứng minh có thể là cách tốt nhất để đi. Tôi chắc chắn sẽ khuyến nghị điều này cho các ứng dụng sản xuất thay vì đưa giải pháp đơn giản của riêng bạn lên trên cơ sở dữ liệu quan hệ.

Công ty Collabinate của tôi ( http://www.collabinate.com ) đã phát triển từ nhận thức này và chúng tôi đã triển khai một công cụ dòng hoạt động hiệu suất cao, có thể mở rộng trên cơ sở dữ liệu đồ thị để đạt được nó. Chúng tôi thực sự đã sử dụng một biến thể của thuật toán Graphity (được điều chỉnh từ công trình đầu tiên của @RenePickhardt, người cũng đã cung cấp câu trả lời ở đây) để xây dựng công cụ.

Nếu bạn muốn tự lưu trữ động cơ hoặc yêu cầu chức năng chuyên dụng, mã lõi thực sự là nguồn mở cho các mục đích phi thương mại, vì vậy bạn có thể xem qua.

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.