1. 后端主动推送
主动推送时随机选择一台服务器A发起推送,如果用户甲是和服务器B建立连接的,那么服务器A发出的推送就到不了前端。
- 解决方案
-
Nginx配置负载均衡,后台微服务主动推送时不做负载分发,而是所有的服务器都推送
2. 前端心跳轮询
由于前端和后端是长连接,由于前端隔一分钟会发送一次请求,来确认长连接有没有断,断了的话会进行重连,如果请求被分发到了另一台服务器上的话,这样消息就会发送失败,前台就不能确定是请求分发的问题还是真的是长连接断了。
- 解决方案
-
Nginx固定IP路由
3. 代码示例
-
Nginx配置
web.confupstream ms-websocket { server 192.168.1.1:8091; server 192.168.1.2:8091; ip_hash; } location = /notification/socket { proxy_pass http://ms-websocket; proxy_redirect off; proxy_set_header Host $server_name:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; add_header X-Frame-Options "SAMEORIGIN"; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_connect_timeout 60; proxy_send_timeout 60; proxy_read_timeout 60; access_log off; }
-
java代码
pom.xml<dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> </dependency>
producer.java@Component("webSocketKafkaProducer") @Slf4j public class WebSocketKafkaProducer { @Autowired private KafkaTemplate<String, Object> kafkaTemplate; public void sendMessage(String content) { log.debug("发送消息:{}",content); kafkaTemplate.send("websocket_push", content); } }
cosumer.java@Component @Slf4j public class WebSocketKafkaConsumer { @Autowired private SimpMessageSendingOperations messagingTemplate; @KafkaListener( topics = {"websocket_push"} , groupId = "${spring.cloud.client.ip-address}.${server.port}" //websocket每个实例使用不同的group-id,防止漏掉非当前实例的连接用户 ) public void websocket(String content){ log.debug("监听到消息:{}", content); //具体发送websocket String destination = "/websocket/listener" + "/" +"username"; log.info("向监听地址为[{}]发送消息:{}", destination, content); this.messagingTemplate.convertAndSend(destination, content); } }