集群环境WebSocket数据推送功能改造(基于Redis消息订阅与发布)

主要问题
集群模式下,WebSocket Session共享问题,例如有A,B两台服务器,与客户端建立WebSocket连接的是A服务器,但是处理和结果推送是在B服务器上执行的,因为B服务器上没有保存与客户端WebSocket连接的Session, 这就导致了数据是无法推送到客户端的。

设计方案
1.第一种是nginx基于ip_hash的会话保持,nginx可以基于客户端ip进行负载均衡,在upstream里设置ip_hash,这样可以基于同一个C类地址段中的同一个客户端,选择同一个服务器,除非服务器宕机才会替换
2.WebSocket连接Session是无法序列化的,只能保存在本地服务器中,因此服务端在推送消息的时候就需要找到保存对应Session的服务器,然后通过Session将数据推送到前端。利用中间件特性例如Redis的消息订阅发布机制。

实现思路
后端服务启动时订阅Redis的topic,当服务器推送数据时,先将消息推送到Redis对应的topic上,然后所有订阅这个topic的服务器都能接收到要推送的消息,如果本地WebSocket上存在要发送的Session会话,则将消息发送出去

后端设计架构图
在这里插入图片描述
以下代码经过测试
1.使用Jedis客户端
引入依赖

<!--websocket-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

Redis配置信息

#redis配置文件
# Redis服务器地址
spring.redis.host=10.100.159.157
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=50
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=1000
# 连接超时时间(毫秒)
spring.redis.timeout=2000

Jedis客户端

/**
 * @Description
 * @Author yjf44568
 * @Date 2021/7/22 11:07
 */
@Configuration
public class RedisConfig {
   
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.jedis.pool.max-wait}")
    private int maxWaitMillis;

    @Bean
    public JedisPool jedisPoolFactory() {
   
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setMaxTotal(maxActive);
        return new JedisPool(jedisPoolConfig, host, port, timeout);
    }
}

WebSocket配置

/**
 * 配置类的作用是要注入ServerEndpointExporter,这个备案会自动注册使用@ServerEndPoint注解声明的Websocket endpoint
 * 如果是使用独立的servlet容器,而不是使用springboot的内主容器,不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
 * @Description
 * @Author yjf44568
 * @Date 2021/7/30 14:53
 */
@Configuration
public class WebSocketConfig {
   
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
   
        return new ServerEndpointExporter();
    }
}

WebSocket连接与消息处理

package com.perf.ws;

import com.google.gson.JsonObject;
import 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值