为什么会选择这套方案

目前websocket的方案对比

  1. 使用springboot自带的websocket方案

    • 优点: 和springboot集成,接入简单
    • 缺点: 性能不高
  2. 使用netty作为websocket server

    • 优点:性能高,编码灵活性高
    • 缺点:很多基础的东西需要自己写
  3. Vertx websocket

    • 优点:底层是netty,保证了性能,函数式编程十分的方便,这也是没有选用netty-socketio的原因

    • 缺点:使用的人数较少,需要自己踩坑

分布式Websocket服务的问题

  1. 负载均衡问题

  2. 广播问题(websocket链接分布在各个服务器上,广播的时候需要找到对应的链接)

解决方案

负载均衡

负载均衡问题主要通过spring cloud gateway来解决的,因为本身spring cloud gateway里面自带了负载均衡方案

配置如下:

1
2
3
4
5
6
7
8
spring:
cloud:
gateway:
routes:
- id: route-id
uri: lb:ws://service-id
predicates:
- Path=/ws/**

所以要解决负载均衡问题,我们要想办法把vertx服务注册springcloud 注册中心中,所以需要把vertx websocket服务集成到springboot中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Component
public class PushServiceStartUp implements InitializingBean {

private final VertxServerProperties vertxServerProperties;

private final Vertx vertx;

private final Router router;

private final WebsocketHandler websocketHandler;

public PushServiceStartUp(VertxServerProperties vertxServerProperties, Vertx vertx, Router router, WebsocketHandler websocketHandler) {
this.vertxServerProperties = vertxServerProperties;
this.vertx = vertx;
this.router = router;
this.websocketHandler = websocketHandler;
}

@Override
public void afterPropertiesSet() throws Exception {
new Thread(() -> {

HttpServer server = vertx.createHttpServer();
server.requestHandler(router)
.webSocketHandler(websocketHandler::handler)
.listen(vertxServerProperties.getPort());
}
).start();
}

}

完成上面的集成之后,默认的能注册到springcloud注册中心的只能是springboot web服务,不能注册vertx服务,为了解决这个问题,我在github上spring cloud gateway项目下提问了之后问题,开发人员给了相关的解决方案,但是都偏复杂,直到我在spring cloud zookeeper中发现了这样一个配置

1
2
3
4
5
spring:
cloud:
zookeeper:
discovery:
instance-port: xxxx

Spring cloud zookeeper registry客户端支持修改默认注册到zookeeper上服务的端口,把这个端口改成vertx web的端口,就可以实现负载均衡了。

优点:和网络上其他的一些负载均衡的方案相比,该方案主要是不需要做比较大的代码改动,主要靠配置就可以完成负载均衡,而且还能和springcloud体系完美兼容。