我們知道在單節點應用中我們只需要將websocketsession存儲在ConcurrentHashMap中就OK,每次發送通知都從map中根據用戶ID獲取對應的websocket的session進行消息通知。
針對分布式系統,很多人第一時間想到的是websocket的session共享,這是大多數的第一反應。很遺憾的是,websocketsession不支持序列化操作,所以也就不能夠存在redis等緩存中。
那么我們還有什么其他的解決方案呢?
我先大致說一下我的項目架構,springcloud項目,沒有做前后端分離,所有請求都是經過web服務進行轉發。
好了,下面就來說說我是怎么解決的吧。
如圖,我是利用了redis的訂閱發布機制實現信息共享的,web負責維護websocketsession,並監聽redis
通道中的消息,將消息發送給對應的在線用戶。業務服務都統一通過接口服務將消息發布到redis,這樣子就不
需要每個服務都去做配置了。做到服務間職能清晰。
redis配置如下:
@Configuration public class RedisConfig { /** * redis消息監聽器容器 * 可以添加多個監聽不同話題的redis監聽器,只需要把消息監聽器和相應的消息訂閱處理器綁定,該消息監聽器 * 通過反射技術調用消息訂閱處理器的相關方法進行一些業務處理 * @param connectionFactory * @param listenerAdapter * @return */ @Bean //相當於xml中的bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); //訂閱了一個叫chat 的通道 container.addMessageListener(listenerAdapter, new PatternTopic(RedisTopicConstants.INNER_TOPIC_NAME)); //這個container 可以添加多個 messageListener return container; } /** * 消息監聽器適配器,綁定消息處理器,利用反射技術調用消息處理器的業務方法 * @param receiver * @return */ @Bean MessageListenerAdapter listenerAdapter(MessageReceiver receiver) { //這個地方 是給messageListenerAdapter 傳入一個消息接受的處理器,利用反射的方法調用“receiveMessage” //也有好幾個重載方法,這邊默認調用處理器的方法 叫handleMessage 可以自己到源碼里面看 return new MessageListenerAdapter(receiver, RedisTopicConstants.TOPIC_RECEIVER_HANDLE_METHOD_NAME); } }
websocket相關配置請參考:
本人采用的是jdk自帶的,在javax.websocket包下。
當然針對各個項目情況還有多種解決辦法,這里就不在一一贅述,具體情況具體分析。