分布式下websocket响应实时响应redis方案

本文介绍了一种在分布式环境下,利用redis的发布/订阅模式来实现实时响应的websocket方案。通过后端代码配合nginx配置,确保多服务节点间的WebSocket消息分发,避免了MQ的额外成本。
摘要由CSDN通过智能技术生成

分布式下websocket实时响应redis方案


背景

业务背景是需求要求通过外部接口将数据实时传数到前端展示。
目前能想到的方案有:
1.前端加个定时器请求接口;要求及时响应并且在并发环境下,无疑主动攻击自己的服务器。
2.使用SseEmitter 后端异步推送,一次请求与后端保持长链接,但是只能后端向前端发送消息,是spring mvc自带,轻量级。
3.使用websocket 双工通讯,更加灵活,但相对比SseEmitter 更重。
为了满足项目需求选择了websocket。而分布式环境下,保证websocket能正常接收信息,有使用mq,但是由于项目中没有加入mq,为了节省不必要的开支,使用现有的redis,运用redis的分发/订阅模式实现分布式下websocket的可用性。


一、websock是什么?

websocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器的全双工通讯-允许服务器主动发起信息个客户端,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据。(剩余的概念百度就有,这里不做多赘述)

二、redis的分发/订阅模式

Redis发布订阅(pub/sub)是一种消息通讯模式,发送者(pub)发送消息,订阅者(sub)接收消息。
Redis客户端可以通过广播的方式将消息(message)同时发送给可能存在的多个客户端,并且发送消息的客户端不需要知道接受消息的客户端的具体信息。(发布消息的客户端和接收消息的客户端两者之间没有直接联系)
客户端可以订阅(subscribe)任意数量的频道(channel),每当有新消息被发送到订阅的频道时,信息就会被发送给所有订阅指定频道的客户端。
一个频道可以被多个客户端订阅,一个客户端也可以订阅多个频道。
在这里插入图片描述

三、代码实现

1.后端代码


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.istack.internal.NotNull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint("/ws/{model}/{id}")
@Component
public class WbSocketServer {
   

    private static final long sessionTimeout = 600000;

    private static final Logger log = LoggerFactory.getLogger(WbSocketServer.class);

    /**
     * 当前在线连接数
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 用来存放每个客户端对应的 WebSocketServer 对象
     */
    private static ConcurrentHashMap<Long, WbSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 注入消息redis
     */
    private static RedisCache redisCache;

    @Autowired
    public void setRedisCache(RedisCache redisCache) {
   
        this.redisCache = redisCache;
    }
    /**
     * 接收 id
     */
    private Long id;


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") Long id) {
   
        session.setMaxIdleTimeout(sessionTimeout);
        this.session = session;
        this.id = id;
        if (webSocketMap.containsKey(id)) {
   
            webSocketMap.remove(id);
            webSocketMap.put(id, this);
        } else {
   
            webSocketMap.put(id, this);
            addOnlineCount();
        }
        log.info("编号id:" + id + "连接,当前在线数为:" + getOnlineCount());
        try {
   
            String result ="{\"msg\":\"连接成功!\"}\n";
            sendMessage(result);
        } catch (IOException e) {
   
            log.error("编号id:" + id + ",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
   
        if (webSocketMap.containsKey(id)) {
   
            webSocketMap.remove(id);
            subOnlineCount();
        }
        log.info("编号id:" + id + "退出,当前在线数为:" + 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值