2012-04-09 39 views
42

Tôi đã cố gắng tìm hiểu về các khái niệm của Akka và các hệ thống dựa trên diễn viên gần đây. Mặc dù tôi có một sự hiểu biết khá tốt về các nguyên tắc cơ bản của Akka bây giờ tôi vẫn đang vật lộn với một vài điều khi nói đến các nhóm và các diễn viên từ xa.Khám phá các diễn viên Akka trong cụm

Tôi sẽ cố gắng minh họa sự cố bằng cách sử dụng WebSocket chat example that comes with Play Framework 2.0: Có một diễn viên chứa WebSockets và giữ danh sách người dùng hiện được kết nối. Các diễn viên về cơ bản đại diện cho phòng chat cả về mặt kỹ thuật và hợp lý. Điều này hoạt động hoàn toàn tốt miễn là có một phòng trò chuyện duy nhất chạy trên một máy chủ duy nhất.

Bây giờ tôi đang cố gắng hiểu làm thế nào ví dụ này sẽ phải được mở rộng khi chúng ta nói về nhiều phòng chat năng động (phòng mới có thể được mở/đóng bất cứ lúc nào) chạy trên một cụm máy chủ (với các nút đơn được thêm hoặc xóa theo nhu cầu hiện tại). Trong trường hợp người dùng A có thể kết nối với máy chủ 1 trong khi người dùng B kết nối với máy chủ 2. Cả hai có thể đang nói chuyện trên cùng một phòng trò chuyện. Trên mỗi máy chủ sẽ vẫn có một diễn viên (đối với mỗi phòng chat?) Giữ các cá thể WebSocket để nhận và xuất bản các sự kiện (tin nhắn) cho đúng người dùng. Nhưng về mặt logic, chỉ nên có một diễn viên phòng trò chuyện trên máy chủ 1 hoặc máy chủ 2 chứa danh sách người dùng hiện được kết nối (hoặc các tác vụ tương tự).

Làm thế nào bạn sẽ đạt được điều này, tốt nhất là trong "akka nguyên chất" và không thêm một hệ thống nhắn tin bổ sung như ZeroMQ hoặc RabbitMQ?

Đây là những gì tôi đã đưa ra cho đến nay, xin vui lòng cho tôi biết liệu điều này làm cho bất kỳ ý nghĩa:

  1. dùng A kết nối với máy chủ 1 và một diễn viên được phân bổ chứa WebSocket của mình.
  2. Tác nhân kiểm tra (sử dụng Bộ định tuyến? EventBus? Cái gì khác?) Cho dù "diễn viên phòng trò chuyện" cho phòng trò chuyện hiện hoạt có tồn tại trên bất kỳ nút cụm được kết nối nào không. Vì nó không phải là nó sẽ yêu cầu tạo ra một diễn viên phòng chat mới bằng cách nào đó và sẽ gửi và nhận tin nhắn trò chuyện trong tương lai đến/từ diễn viên này.
  3. Người dùng B kết nối trên máy chủ 2 và một diễn viên được phân bổ cho WebSocket của mình.
  4. Nó cũng kiểm tra xem một diễn viên cho phòng trò chuyện được yêu cầu tồn tại ở đâu đó và tìm thấy nó trên máy chủ 1.
  5. Diễn viên phòng trò chuyện trên máy chủ 1 hiện hoạt động như trung tâm của phòng trò chuyện đã gửi, gửi tin nhắn cho tất cả ” "Diễn viên thành viên trò chuyện và phân phối những người đến.

Nếu máy chủ 2 ngừng hoạt động, diễn viên phòng trò chuyện sẽ phải được tạo lại/chuyển đến máy chủ 2 bằng cách nào đó, mặc dù đây không phải là mối quan tâm chính của tôi ngay bây giờ. Tôi tự hỏi nhất về cách phát hiện năng động này của các diễn viên lan truyền về các máy khác nhau, về cơ bản độc lập có thể được thực hiện bằng cách sử dụng bộ công cụ của Akka.

Tôi đã xem tài liệu của Akka trong một thời gian ngắn, vì vậy có thể tôi đang thiếu điều hiển nhiên ở đây. Nếu vậy, xin vui lòng khai sáng cho tôi :-)

Trả lời

11

Tôi đang làm việc trên một dự án riêng tư cơ bản là một phiên bản mở rộng của ví dụ chatroom và tôi cũng gặp vấn đề khởi động với akka và toàn bộ suy nghĩ "phi tập trung". Vì vậy, tôi có thể cho bạn biết cách tôi "giải quyết" phòng trò chuyện mở rộng của tôi:

Tôi muốn một máy chủ có thể dễ dàng triển khai nhiều lần mà không cần cấu hình thêm. Tôi đang sử dụng redis làm bộ nhớ cho tất cả các phiên người dùng mở (serialization đơn giản của ActorRefs của họ) và cho tất cả các phòng chat.

Các máy chủ có các diễn viên sau:

  • WebsocketSession: mà giữ kết nối đến một người sử dụng và xử lý các yêu cầu từ người sử dụng và chuyển tiếp tin nhắn từ hệ thống.
  • ChatroomManager: đây là đài truyền hình trung tâm, được triển khai trên mọi phiên bản của máy chủ. Nếu một người dùng muốn gửi một tin nhắn đến một phòng chat, WebSocketSession-Actor sẽ gửi tất cả thông tin đến ChatroomManager-Actor, sau đó phát tin nhắn đến tất cả các thành viên của phòng chat.

Vì vậy, đây là thủ tục của tôi:

  1. dùng A kết nối với máy chủ 1 mà phân bổ một WebsocketSession mới. Diễn viên này chèn đường dẫn tuyệt đối cho diễn viên này vào redis.
  2. Người dùng A tham gia phòng chat X cũng chèn đường dẫn tuyệt đối của mình (tôi sử dụng ID này làm ID duy nhất của phiên người dùng) thành redis (mỗi phòng chat có bộ "kết nối")
  3. Người dùng B kết nối với máy chủ 2 - > redis
  4. Người dùng B tham gia phòng chat X -> redis
  5. Người dùng B gửi thư của mình qua Websocket đến diễn viên phiên của anh ấy, (sau khi một số kiểm tra) gửi một diễn viên -message đến ChatroomManager. Nam diễn viên này thực sự truy xuất danh sách người dùng của phòng chat từ redis (đường dẫn tuyệt đối được sử dụng với akka's actorFor -method) và sau đó gửi thông điệp đến từng diễn viên phiên. Những diễn viên phiên này sau đó ghi vào websockets của họ.

Trong mỗi phòng chatQuản lý diễn viên Tôi thực hiện một số bộ nhớ cache có tốc độ bổ sung. Tôi nghĩ điều này khác với cách tiếp cận của bạn, đặc biệt là các ChatroomManager này xử lý các yêu cầu cho tất cả các phòng chat. Nhưng có một diễn viên cho một phòng chat là một điểm thất bại mà tôi muốn tránh. Hơn nữa điều này sẽ gây ra rất nhiều bài viết, ví dụ:

  • dùng A và B là người sử dụng trên máy chủ 1.
  • Chatroom X là trên máy chủ 2.

Nếu người dùng A muốn nói chuyện với người dùng B, cả hai đều phải giao tiếp qua phòng chat-diễn viên trên máy chủ 1.

Ngoài ra tôi đã sử dụng các chức năng của akka như (round-robin) -routers để tạo nhiều phiên bản của diễn viên ChatroomManager trên mỗi hệ thống xử lý nhiều yêu cầu.

Tôi dành một số ngày để thiết lập toàn bộ cơ sở hạ tầng từ xa akka kết hợp với serialization và redis. Nhưng bây giờ tôi có thể tạo ra bất kỳ số lượng các trường hợp của các ứng dụng máy chủ mà sử dụng redis để chia sẻ có ActorRef s (serialized như đường dẫn tuyệt đối với ip + port).

Điều này có thể giúp bạn thêm một chút và tôi mở cho các câu hỏi mới (vui lòng không nói về tiếng Anh của tôi;).

+1

tôi phải đồng ý với câu trả lời Freed và tôi có thể vừa di dời các vấn đề của một điểm duy nhất của thất bại về phía lưu trữ. Tất nhiên một cache được phân phối là một sự cải tiến nhưng như Freed nói không hoàn hảo. Thực ra tôi đang truy cập redis thông qua một 'Storage'-Actor được triển khai hiện đang xử lý các yêu cầu dữ liệu (như nhận danh sách các thành viên hiện tại). Nếu tôi hiểu đúng, để thực hiện điều này, đây sẽ là nơi để tránh một nút cổ chai với việc thực hiện cụm Akka trong tương lai. – th3hamm0r

+0

bạn không cần phải đợi các tiện ích mở rộng phân nhóm của Akka, hãy xem các bài đăng trên blog được liên kết trong câu trả lời của tôi. Akka là một chặng đường dài để hỗ trợ phân cụm hoàn toàn. – SoftMemes

+0

Danh sách thành viên của phòng chat có thể được tổ chức trong hai diễn viên trên hai máy chủ để chịu lỗi với các bản cập nhật được gửi tới cả hai. Xem bài báo này mô tả cách làm điều này với paxos và băm mod của id phòng chat để phân bổ máy chủ chính/phụ cho phòng chat. Sau đó, mỗi websocket khách hàng tính hai máy chủ chính nó để biết chính để truy vấn khác rơi trở lại thứ cấp nếu máy chủ đó đi xuống https://www.dropbox.com/s/iihpq9bjcfver07/VLDB-Paper.pdf (rõ ràng là tốt hơn để mua rằng bộ nhớ cache của phiên làm việc ngay bây giờ được gọi là không gian vũ trụ hơn là tự viết nó nhưng thuật toán và thiết kế của chúng rất thông tin). – simbo1905

9

Chìa khóa để mở rộng trên nhiều máy là để giữ trạng thái có thể thay đổi khi được phân tách càng tốt. Mặc dù bạn có thể sử dụng bộ nhớ cache được phân phối để điều phối trạng thái trên tất cả các nút, điều này sẽ cung cấp cho bạn sự đồng bộ hóa cũng như các vấn đề về cổ chai khi mở rộng ra một số lượng lớn các nút.Lý tưởng nhất là, sẽ có một diễn viên duy nhất biết về các tin nhắn và người tham gia trong một phòng chat.

Cốt lõi của vấn đề là, nếu một phòng trò chuyện được đại diện bởi một diễn viên duy nhất chạy trên một máy tính duy nhất - hoặc thực sự nếu một căn phòng như vậy tồn tại. Bí quyết là định tuyến các yêu cầu liên quan đến phòng trò chuyện cụ thể bằng cách sử dụng số nhận dạng, chẳng hạn như tên của phòng trò chuyện. Tính toán giá trị băm của tên và tùy thuộc vào số, chọn một trong số các hộp n của bạn. Nút này sẽ biết về các phòng trò chuyện hiện tại của nó và có thể tìm thấy hoặc tạo một diễn viên phòng chat chính xác cho bạn một cách an toàn.

Bạn có thể có một cái nhìn tại các bài đăng trên blog sau thảo luận nhóm và nhân rộng ra trong Akka:

http://blog.softmemes.com/2012/06/16/clustered-akka-building-akka-2-2-today-part-1/

http://blog.softmemes.com/2012/06/16/clustered-akka-building-akka-2-2-today-part-2/

6

Tôi sẽ sử dụng Zookeeper + Norbert biết về những host đi lên và xuống:

http://www.ibm.com/developerworks/library/j-zookeeper/

Bây giờ mọi nút trong trang trại máy chủ của phòng chat của tôi đều có thể biết tất cả các máy chủ trong cụm lôgic. Họ sẽ nhận được một cuộc gọi lại khi một nút chuyển sang ngoại tuyến (hoặc trực tuyến). Giờ đây, bất kỳ nút nào cũng có thể lưu danh sách các thành viên cụm hiện tại, băm ID phòng chat và sửa đổi theo kích thước danh sách để có chỉ mục trong danh sách là nút lưu trữ bất kỳ phòng trò chuyện cụ thể nào. Chúng ta có thể thêm 1 và rehash để chọn một chỉ mục thứ hai (yêu cầu một vòng lặp cho đến khi bạn nhận được một chỉ mục mới) để tính toán máy chủ thứ hai để giữ một bản sao thứ hai của phòng chat để dự phòng. Trên mỗi máy chủ của hai phòng chat là một diễn viên phòng chat, chỉ chuyển tiếp tất cả các tin nhắn trò chuyện tới mỗi diễn viên Websocket, một thành viên của phòng chat.

Giờ đây, chúng tôi có thể gửi tin nhắn trò chuyện qua cả hai diễn viên phòng trò chuyện hoạt động với bộ định tuyến Akka tùy chỉnh. Một khách hàng chỉ gửi thông báo một lần và router sẽ thực hiện các sửa đổi băm và gửi đến hai diễn viên phòng trò chuyện từ xa. Tôi sẽ sử dụng thuật toán bông tuyết twitter để tạo id 64 bit duy nhất cho các thư được gửi. Xem thuật toán trong phương thức nextId() của mã tại liên kết sau. Các datacenterId và workerId thể được thiết lập bằng cách sử dụng thuộc tính Norbert để đảm bảo không có va chạm ID được tạo ra trên các máy chủ khác nhau:

https://github.com/twitter/snowflake/blob/master/src/main/scala/com/twitter/service/snowflake/IdWorker.scala

Bây giờ hai bản sao của mỗi thông điệp sẽ đi đến từng thiết bị đầu cuối của khách hàng qua mỗi của hai hoạt động diễn viên phòng chat. Tại mỗi diễn viên khách hàng Websocket tôi sẽ un-bitmask các ID bông tuyết để tìm hiểu số datacenterId + workerId gửi tin nhắn và theo dõi số lượng tin nhắn trò chuyện cao nhất được nhìn thấy từ mỗi máy chủ trong cụm. Sau đó, tôi sẽ bỏ qua bất kỳ tin nhắn nào không cao hơn những gì đã được nhìn thấy tại máy khách đã cho cho một máy chủ người gửi đã cho. Điều này sẽ loại bỏ các cặp thông điệp đến thông qua hai diễn viên phòng chat đang hoạt động.

Cho đến nay rất tốt; chúng tôi sẽ có tin nhắn đàn hồi trong đó nếu bất kỳ nút nào bị chết, chúng tôi sẽ không xóa bản sao còn lại của các phòng chat. Tin nhắn sẽ không bị gián đoạn thông qua phòng trò chuyện thứ hai tự động.

Tiếp theo, chúng ta cần xử lý các nút thả ra khỏi cụm hoặc được thêm trở lại vào cụm. Chúng tôi sẽ nhận được một cuộc gọi lại norbert trong mỗi nút để thông báo cho chúng tôi về thay đổi thành viên cụm. Trong lần gọi lại này, chúng ta có thể gửi một tin nhắn akka thông qua router tùy chỉnh cho biết danh sách thành viên mới và tên máy chủ hiện tại. Bộ định tuyến tùy chỉnh trên máy chủ lưu trữ hiện tại sẽ thấy thông báo đó và cập nhật trạng thái của nó để biết về thành viên cụm mới để tính toán cặp nút mới để gửi bất kỳ lưu lượng truy cập phòng chat cụ thể nào qua.Sự thừa nhận thành viên cluster mới này sẽ được router gửi tới tất cả các nút để mọi máy chủ có thể theo dõi khi tất cả các máy chủ đã bắt kịp với sự thay đổi thành viên và hiện đang gửi tin nhắn chính xác.

Phòng trò chuyện còn lại có thể vẫn hoạt động sau khi thay đổi thành viên. Trong trường hợp đó tất cả các bộ định tuyến trên tất cả các nút sẽ tiếp tục gửi đến nó như bình thường nhưng cũng sẽ gửi một thông điệp đến máy chủ lưu trữ trò chuyện thứ hai mới. Đó là phòng chat thứ hai có thể chưa được lên nhưng đó không phải là một vấn đề như tin nhắn sẽ chảy qua người sống sót. Nếu phòng chat còn sống không còn hoạt động sau khi các thành viên thay đổi tất cả các bộ định tuyến trên tất cả các máy chủ lúc đầu sẽ gửi đến ba máy chủ; người sống sót và hai nút mới. Cơ chế theo dõi cái chết của akka có thể được sử dụng để tất cả các nút cuối cùng có thể nhìn thấy việc tắt phòng chat còn lại để quay lại định tuyến lưu lượng truy cập trò chuyện qua hai máy chủ.

Tiếp theo, chúng tôi cần di chuyển phòng trò chuyện từ máy chủ còn sống lên một hoặc hai máy chủ mới tùy thuộc vào hoàn cảnh. Các diễn viên phòng chat surving sẽ tại một số điểm có được một tin nhắn nói với nó về các thành viên cluster mới. Nó sẽ bắt đầu bằng cách gửi một bản sao của thành viên phòng chat đến các nút mới. Thông báo này sẽ tạo bản sao mới của diễn viên phòng chat với tư cách thành viên chính xác trên các nút mới. Nếu người sống sót không còn là một trong hai nút mà nên giữ phòng chat nó sẽ đi vào chế độ ngừng hoạt động. Trong chế độ ngừng hoạt động, nó sẽ chỉ chuyển tiếp bất kỳ tin nhắn nào đến các nút chính và phụ mới không cho bất kỳ thành viên chatroom nào. Chuyển tiếp tin nhắn Akka là hoàn hảo cho việc này.

Phòng chat ngừng hoạt động sẽ lắng nghe thông báo xác nhận thành viên nhóm norbert từ mỗi nút. Cuối cùng nó sẽ thấy rằng tất cả các nút trong cluster đã thừa nhận thành viên cluster mới. Sau đó nó biết nó sẽ không còn nhận được bất kỳ tin nhắn nữa để chuyển tiếp. Sau đó nó có thể tự sát. Akka hotswapping là hoàn hảo để thực hiện hành vi ngừng hoạt động.

Cho đến nay rất tốt; chúng tôi có một thiết lập nhắn tin linh hoạt mà sẽ không bị mất tin nhắn cho một vụ tai nạn nút. Tại thời điểm mà các thành viên cluster thay đổi, chúng tôi sẽ nhận được lưu lượng truy cập intranode tăng đột biến để sao chép các chatroom sang các nút mới. Chúng tôi cũng có một loạt các chuyển tiếp intranode của tin nhắn đến các nút cho đến khi tất cả các máy chủ đã bắt kịp với các chatroom đã chuyển hai máy chủ đó. Nếu chúng ta muốn mở rộng hệ thống, chúng ta có thể đợi cho đến khi một điểm thấp trong lưu lượng người dùng và chỉ bật một nút mới. Các phòng chat sẽ được phân phối lại trên các nút mới một cách tự động.

Các mô tả ở trên được dựa trên đọc giấy sau và dịch nó thành khái niệm AKKA:

https://www.dropbox.com/s/iihpq9bjcfver07/VLDB-Paper.pdf

+0

Nếu một nút thêm một nút mới vào cụm, thì hầu hết các diễn viên sẽ được cân bằng lại thành các nút mới (phải không?). Bạn có biết khoảng thời gian cần thiết để cluster cân bằng lại? (Nếu đó là 1 trung tâm dữ liệu và chỉ có 10 nút.) (Lý do các diễn viên sẽ di chuyển xung quanh sẽ là: * "băm ID phòng chat và chỉnh sửa kích thước danh sách * [cụm thành viên] * để lấy chỉ mục bên trong danh sách là nút sẽ lưu trữ bất kỳ phòng chat cụ thể nào "*) – KajMagnus

Các vấn đề liên quan