spring websocket集群问题的简单记录

[TOC]

前言

最近公司里遇到一个问题,在集群中一些websocket的消息丢失了。
产生问题的原理很简单,发送消息的服务和接收者连接的服务不是同一个服务。

解决方案

用中间件(mq, redis etc.)来在服务之间进行通信。

不直接发送websocket消息,而是将消息放在mq或者redis的list中。
并在redis中维护连接信息,服务根据连接信息来判断自己是否需要处理消息,或者将消息发给接收者连接的服务。

代码示例

我们的项目中使用的是Spring WebSocket,并且使用了STOMP协议,可以去官网查看文档。

代码示例只做维护连接信息的代码示例,其他部分就不放上来了。

维护连接信息的代码示例

想要在维护STOMP协议的连接信息,可以查看文档的这一部分Listening To ApplicationContext Events and Intercepting Messages

这里的连接信息只要是能够标识出不同的服务就OK。

一下是监听了订阅事件的Listener的部分代码:

package cn.fjhdtp.websocket.interceptor;

import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

public class LoginInfoInterceptor extends HttpSessionHandshakeInterceptor {

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
            WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
            //握手前,往attributes中增加所需信息

        Object loginBean = ...;//获取登录的用户信息(或其他信息)
        attributes.put(WebSocketConstant.WEBSOKET_LOGINBEAN,loginBean);

        return super.beforeHandshake(request, response, wsHandler, attributes);
    }
}
package cn.fjhdtp.listener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;

import java.util.Map;

@Component
public class SessionSubscribeEventListener implements ApplicationListener<SessionSubscribeEvent> {

    @Autowired
    @Qualifier("serversideMessageTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private IMessageHandler messageHandler;

    @Override
    public void onApplicationEvent(SessionSubscribeEvent event) {
            //获取订阅的destination
          String destination = (String) event.getMessage().getHeaders().get("simpDestination");
            //获取登录信息
            Object loginBean = ((Map) event.getMessage().getHeaders().get("simpSessionAttributes")).get(WebSocketConstant.WEBSOKET_LOGINBEAN);
            //TODO 向redis中增加连接信息
    }
}
package cn.fjhdtp.message.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

import java.util.Map;

@Component
public class SessionDisconnectEventListener implements ApplicationListener<SessionDisconnectEvent> {

    @Override
    public void onApplicationEvent(SessionDisconnectEvent event) {
        // stomp连接断开,清除连接信息
        //从attributes中获取登录信息(或其他信息)
        Object loginBean = ((Map) event.getMessage().getHeaders().get("simpSessionAttributes")).get(WebSocketConstant.WEBSOKET_LOGINBEAN);

        //从redis中移除连接信息
    }
}

当然,有些情况下可能不会正常的触发断开连接的事件(在was下就不会有这个事件),因此还会需要HeartBeat。

原文地址:https://www.cnblogs.com/FJH1994/p/8998900.html

时间: 2024-11-26 08:59:13

spring websocket集群问题的简单记录的相关文章

Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群

Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 2016年7月7日 09:06:09 星期四 http://fanshuya

Redis集群搭建与简单使用【转】

Redis集群搭建与简单使用 安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 oracle linux 6.6 ,一台(IP:192.168.31.245),一台(IP:192.168.31.210) . 安装过程 1. 下载并解压 cd /root/software wget http://download.redis.io/releases/redis-3.2.4.t

spring quartz 集群配置

Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它来为执行一个作业而创建简单的或复杂的调度. 在项目中有大量的后台任务需要调度执行,如构建索引.统计报表.周期同步数据等等,要求任务调度系统具备高可用性.负载均衡特性,使用Quartz 会很方便. 下文是spring和quartz进行整合,同时支持集群部署.quartz集群的支持是通过数据库进行任务调度的感知. 1.使用的版本情况:spring

springboot websocket集群(stomp协议)连接时候传递参数

最近在公司项目中接到个需求.就是后台跟前端浏览器要保持长连接,后台主动往前台推数据. 网上查了下,websocket stomp协议处理这个很简单.尤其是跟springboot 集成. 但是由于开始是单机玩的,很顺利. 但是后面部署到生产搞集群的话,就会出问题了. 假如集群两个节点,浏览器A与节点A建立连接,A节点发的消息浏览器A节点肯定能收到.但是B节点由于没有跟浏览器A建立连接.B节点发的消息浏览器就收不到了. 网上也查了好多,但是没有一个说的很清楚的,也很多都是理论层面的. 还有很多思路都

Redis集群搭建与简单使用

转载 介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 CentOS6.5 (IP:192.168.31.245),一台 CentOS7(IP:192.168.31.210) . 安装过程 1. 下载并解压 cd /root/software wget http://download.redis.io/releases/redis-3.2.4.ta

【转】Redis集群搭建与简单使用

介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 CentOS6.5 (IP:192.168.31.245),一台 CentOS7(IP:192.168.31.210) . 安装过程 1. 下载并解压 cd /root/software wget http://download.redis.io/releases/redis-3.2.4.tar.g

(转)Redis集群搭建与简单使用(最少需要 6个节点)

介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 CentOS6.5 (IP:192.168.31.245),一台 CentOS7(IP:192.168.31.210) . 安装过程 1. 下载并解压 cd /root/software wget http://download.redis.io/releases/redis-3.2.4.tar.g

Hadoop学习之路(四)Hadoop集群搭建和简单应用

概念了解 主从结构:在一个集群中,会有部分节点充当主服务器的角色,其他服务器都是从服务器的角色,当前这种架构模式叫做主从结构. 主从结构分类: 1.一主多从 2.多主多从 Hadoop中的HDFS和YARN都是主从结构,主从结构中的主节点和从节点有多重概念方式: 1.主节点 从节点 2.master slave 3.管理者 工作者 4.leader follower Hadoop集群中各个角色的名称: 服务 主节点 从节点 HDFS NameNode DataNode YARN Resource

谈谈websocket集群的解决方式

上文我们已经利用websocket实现微信二维码支付的业务. 上述实现在单机环境中实现是没有什么问题的,无非就是客户端连接服务端,首先将连接的websocketsession存在一个map里面,当异步响应的时候, 根据流水号获取map里面对于的websocketSession,给指定的客户端发送消息. 但实际生产环境中,服务器一般是采用集群模式,首先,比方支付来说,接收第三方响应的服务器可能是有多台,然后具体是根据nginx随机路由转发, 假设异步响应的服务器有2台,A和B,而且连接websoc