WebSocket在现代浏览器中的应用已经算是比较普遍了,在某些业务场景下,要求必须能够在服务器端推送消息至客户端。在没有WebSocket的年代,我们使用过dwr,在那个时候dwr真实一个非常棒的方案。但是在WebSocket兴起之后,我们更愿意使用标准实现来解决问题、
首先交代一下,本篇文章不讲解WebSocket的配置,主要讲的是针对在微服务架构集群模式下解决方案的选择。
微服务架构大家应该都不陌生了,在微服务架构下,服务是分布式的,而且为了保证业务的可用性,每个服务都是以集群的形式存在。在集群模式下,要保证集群的每一个节点的访问得到相同的结果就需要做到数据一致性,如缓存、session等。
微服务集群缓存通常使用分布式缓存redis解决,session一致性也通常会通过redis解决,但是现在更流行的是无状态的Http,即无session化,最常见的解决方案就是OAuth。
WebSocket有所不同,它是与服务端建立一个长连接,在集群模式下,显然不可能把前端与服务集群中的每一个节点建立连接,一个可行的思路是像解决http session的共享一样,通过redis来实现websocket的session共享,但是websocket session的数量是远多于http session的数量的(因为每打开一个页面都会建立一个websocket连接),所以随着用户量的增长,共享的数据量太大,很容易造成瓶颈。
另一个思路是,websocket总归会与集群中某个节点建立连接,那么,只要找到连接所在的节点,就可以向服务端推送消息了,那么要解决的问题就是如何找到一个websocket连接所在的节点。要找到连接在哪个节点上,我们需要一个唯一的标识符用于寻找连接,然而在基于stomp的发布-订阅模式下,一个消息的推送可能是面向若干个连接的,可能分布在集群中的每一个节点上,这样去寻找连接的代价也很高。既然这样,我们不妨换种思路,每一个websocket消息,我们在集群的每个节点上都进行推送,订阅了该消息的连接,不管有一个还是一万个,最终肯定都能收到这个消息。基于这个思路,我们做了一些技术选型:
- RabbitMQ
- Spring Cloud Stream
首先说RabbitMQ,高级消息队列,可以实现消息广播(当然kafka一样可以做到,这里只介绍一种),另一项技术是Spring Cloud Stream,stream是一个用于构建高度可扩展事件驱动型微服务的框架,并且它可以跟RabbitMQ、Kafka以及其他多种消息服务集成,使用了streamÿ