2015-05-08 55 views
2

假設我有一個典型的Web服務器,它向客戶端提供標準的HTML頁面,並且與它一起運行的websocket服務器用於實時更新(聊天,通知等)。擴展標準的網絡服務器旁邊的解耦實時服務器

我的一般工作流是當主服務器上發生什麼事情觸發需要實時消息時,主服務器將該消息發送到實時服務器(通過消息隊列),實時服務器將其分發給任何相關的連接。

我擔心的是,如果我想擴大了一點東西,並添加另一個實時服務器,似乎我唯一的選擇是:

  1. 有主服務器跟蹤哪些實時服務器的客戶端 連接到。當客戶端收到通知/消息 消息時,主服務器將該消息轉發給客戶端連接的實時服務器 。這裏的缺點是代碼複雜度爲 ,因爲主服務器必須做一些額外的預訂 保留。
  2. 或者,主服務器只需將該消息 一起傳遞給每個實時服務器;只有連接到客戶端的服務器 實際上會對它做任何事情。這會導致 被大量浪費的消息傳遞。

我在這裏錯過了另一個選擇嗎?我只是試圖確保我不會在這些路徑中走得太遠,並意識到我正在做的事情完全錯誤。

+0

您也可以使用像pusher.com或realtime.co這樣的實時雲服務。他們會爲你處理重負載,你不需要擔心可擴展性。永遠。 –

+0

@JoãoParreira - 希望避免外部解決方案。我已經有了一個可以正常工作的系統,我只是因爲好奇而感興趣。 – repole

回答

1

如果方案是

一)主要的Web服務器時的操作提出了一個消息(比方說,一個記錄插入) b)他通知相應的實時服務器

你可以通過使用中間pub/sub架構將這些消息轉發給接收者來解耦這兩個步驟。

的實現將是

1)您有其中在連接到一個實時插座一個客戶,你開始在該通道中

2)當主應用程序偵聽Redis的發佈 - 訂閱通道想要通過實時服務器通知用戶,它會向該通道推送一條消息,實時服務器獲取該消息並將其轉發給目標用戶。

通過這種方式,您可以將實時通知從主應用程序中分離出來,並且不必跟蹤用戶的位置。

+0

Pub-sub聽起來像我正在尋找的東西,它並沒有告訴我,我可以使用一個頻道來說每個客戶端,而不是每個服務器的頻道。欣賞故障。 – repole

+0

@repole如果您在websocket服務器前使用類似haproxy的東西,您可以實現實時組件的橫向可伸縮性,與主服務器分開 –

0

對於少數幾臺實時服務器,您可以想象,只需在主服務器上保存一份它們的列表,然後通過它們輪詢即可。其他方法是使用load balancer

基本上,您將有一個專用節點來接收來自主服務器的請求,然後讓該負載均衡器節點負責選擇將請求轉發給哪個websocket /實時服務器。

當然,這只是將代碼複雜度從主服務器轉移到新的組件,但從概念上講,我認爲它更好,更分離。

+0

但即使使用負載均衡器,問題在於每個客戶端仍然最終連接到該負載均衡器後面的潛在許多實時服務器之一。我留在我的問題中描述的完全相同的情況下,我必須跟蹤客戶端實際連接到哪個實時服務器,或者我仍然必須發送任何消息到每個實時服務器 – repole

0

更改了答案,因爲答覆表明「主」和「實時」服務器是已建立負載平衡的羣集,而不是單個主機。

中心的可擴展性問題似乎是:

我的一般工作流程是當事情觸發了實時信息的需要主服務器上時,主服務器發送消息到實時服務器(通過消息隊列),實時服務器將其分發給任何相關的連接。

強調「有關」一詞。假設您有10個「主」服務器和50個「實時」服務器,並且主服務器#5上發生了一個事件:哪個WebSocket將被視爲與此事件相關?

最糟糕的情況是任何「主」服務器上的任何事件都需要傳播到所有websocket。這是O(N^2)的複雜性,這被視爲嚴重的可擴展性損害。

如果您可以將相關的連接分組爲不與羣集大小或總數nr一起增長的羣組,則只能防止O(N^2)複雜度。的連接。分組需要狀態存儲器來存儲連接所屬的組。

請記住,有3種方式來存儲狀態:

  1. 全局內存(memcached的/ Redis的/ DB,...)
  2. 粘路由(負載平衡器配置)
  3. 客戶端內存(餅乾,瀏覽器本地存儲,鏈接/重定向URL)

其中,選項3被視爲最可擴展的選項,因爲它省略了中央狀態存儲。

爲了將消息從「主」傳遞到「實時」服務器,根據定義,該流量應該遠小於流向客戶端的流量。還有高效的框架來推動pub/sub流量。

+0

我不是說「主「服務器就好像只有一個。其目的是將多個主服務器放在負載平衡器後面,並將多個實時服務器放在負載平衡器後面。 耦合實時服務器和主服務器可能會起作用,但它似乎仍然不完美,因爲一個人更可能需要處理更大的負載,因此將它們耦合起來會是浪費。但或許這樣做比起將消息分發到每個實時服務器,或者不得不做記錄來知道客戶端連接到哪個服務器要浪費得多。 – repole

1

您所描述的問題是在SignalR中使用的常見「消息背板」,也與消息體系結構中的「扇出消息交換」有關。當有背板或扇出時,每條消息都被轉發到每個消息節點服務器,因此客戶端可以連接到任何服務器並獲取消息。當你必須同時支持長輪詢和websocket時,這種方法是合理的。但是,正如您注意到的那樣,這是浪費流量和資源。

您需要使用具有智能路由的消息基礎結構,如RabbitMQ。看看主題和標題交換:https://www.rabbitmq.com/tutorials/amqp-concepts.html

How Topic Exchanges Route Messages

RabbitMQ for Windows: Exchange Types

有噸不同的排隊框架。選擇一個你喜歡的,但確保你可以有更多的交換模式,而不僅僅是直接或扇出;)最後,WebSocket只是和端點連接到消息基礎設施。所以,如果你想進行擴展,把它歸結爲後端你:)