前言

最近公司里遇到一个问题,在集群中一些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。

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

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

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

  2. springBoot+websocket集群系列知识

    WebSocket简介和spring boot集成简单消息代理 Spring Boot 集成 websocket,使用RabbitMQ做为消息代理 Spring Websocket实现向指定的用户发送 ...

  3. Spring+quartz集群解决多服务器部署定时器重复执行的问题

    一.问题描述 Spring自带的Task虽然能很好使用定时任务,只需要做些简单的配置就可以了.不过如果部署在多台服务器上的时候,这样定时任务会在每台服务器都会执行,造成重复执行. 二.解决方案 Spr ...

  4. Websocket集群解决方案

    最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息. 所谓的全双工表示客户端和服务端都能向对方发送消息.不使用 ...

  5. Redis Cluster高可用集群在线迁移操作记录【转】

    之前介绍了redis cluster的结构及高可用集群部署过程,今天这里简单说下redis集群的迁移.由于之前的redis cluster集群环境部署的服务器性能有限,需要迁移到高配置的服务器上.考虑 ...

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

    Redis集群搭建与简单使用 安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都 ...

  7. ubuntu ceph集群安装以及简单使用

    ubuntu ceph安装以及使用 1.安装环境 本文主要根据官方文档使用ubuntu14.04安装ceph集群,并且简单熟悉其基本操作.整个集群包括一个admin节点(admin node,主机名为 ...

  8. 手把手教你在 TKE 集群中实现简单的蓝绿发布和灰度发布

    概述 如何在腾讯云 Kubernetes 集群实现蓝绿发布和灰度发布?通常要向集群额外部署其它开源工具来实现,比如 Nginx Ingress,Traefik 等,或者让业务上 Service Mes ...

  9. Spring 4.3.2+quartz2.2.3单机、集群+websocket集群实现文本或图片推送、接收及显示

    相关环境 Nginx,Spring4.x当前(要选择4.0+),tomcat8.x,Quartz 2.x集群 测试面页:http://sms.reyo.cn/socket.html 测试面页是文本和图 ...

随机推荐

  1. mysql修改表操作

    一: 修改表信息 1.修改表名 alter table test_a rename to sys_app; 2.修改表注释 alter table sys_application comment '系 ...

  2. 基于Django-Cookie的CBV和FBV的用户验证装饰器

    FBV模式 def cookie(func):       def deco(request,*args,**kwargs):             u = request.get_signed_c ...

  3. MongoDB 查询整理

    查询所有sql:  select * from table_namemongodb:   db.getCollection('期刊论文').find({}) 如上图所示,获取期刊论文collectio ...

  4. Halcon编程-基于形状特征的模板匹配

    halcon软件最高效的一个方面在于模板匹配,号称可以快速进行柔性模板匹配,能够非常方便的用于缺陷检测.目标定位.下面以一个简单的例子说明基于形状特征的模板匹配.      为了在右图中,定位图中的三 ...

  5. 【洛谷】【洛谷月赛】4月月赛Round 1/2

    洛谷月赛“月”来“月”丧了,一月更比一月丧,做得我十分不“月”…… 4月的两轮月赛,都只会T1,就写一下吧,等待后续更新…… 先看看Round1的T1: [R1T1] 网址:点我 [题意简述] 给定一 ...

  6. java map遍历并删除特定值

    删除map中包含password和username的键值对 若是在map中直接删除,会指针错误 Iterator<Map.Entry<String,Object>> it = ...

  7. 转载-SVN常用命令

    SVN(Subversion)是一个自由.开源的项目源代码版本控制工具.目前,绝大多数开源软件和企业代码管理,都使用SVN作为代码版本管理软件. Subversion将文件存放在中心版本库里,这个版本 ...

  8. Django-自动HTML转义

    一.自动HTML转义 从模板生成HTML时,总会有变量包含影响最终HTML的字符风险,例如,考虑这个模板的片段: Hello, {{ name }} 起初,这是一种显示用户名的无害方式,但考虑用户输入 ...

  9. React-Native 之 常用组件Image使用

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...

  10. 正则表达式基础->

    描述:(grep) 正则表达式是一种字符模式,用于在查找过程中匹配指定的字符.在大多数程序里,正则表达式都被置于两个正斜杠之间,它匹配被查找的行中任何位置出现的相同模式 基础正则表达式 正则表达式 描 ...