前言

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

    1022. Poor contestant Prob Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description As everyb ...

  2. 在EF6.0中打印数据库操作日志

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. Eltwise层解析

    Concat层虽然利用到了上下文的语义信息,但仅仅是将其拼接起来,之所以能起到效果,在于它在不增加算法复杂度的情形下增加了channel数目.那有没有直接关联上下文的语义信息呢?答案是Eltwise层 ...

  4. HDU 1181 变形课 (深搜)

    题目连接 Problem Description 呃......变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形 ...

  5. Linux基础-awk使用

    打印uid在30~40范围内的用户名:awk -F: '$3>=30&&$3<040{print $1}' passwd 打印第5-10行的行号和用户名:awk -F: ' ...

  6. Intent 对象在 Android 开发中的应用

    转自(http://www.ibm.com/developerworks/cn/opensource/os-cn-android-intent/) Android 是一个开放性移动开发平台,运行在该平 ...

  7. DRM学习总结(1)--- DRM框架介绍

    一.DRM 简介 In computing, the Direct Rendering Manager (DRM), a subsystem of the Linux kernel, interfac ...

  8. Linux下C程序的反汇编【转】

    转自:http://blog.csdn.net/u011192270/article/details/50224267 前言:本文主要介绍几种反汇编的方法. gcc gcc的完整编译过程大致为:预处理 ...

  9. linux中断申请之request_threaded_irq 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=21977330&id=3755609 在linux里,中断处理分 ...

  10. mysql备份的 三种方式【转】

    备份的本质就是将数据集另存一个副本,但是原数据会不停的发生变化,所以利用备份只能回复到数据变化之前的数据.那变化之后的呢?所以制定一个好的备份策略很重要. 一.备份的目的 做灾难恢复:对损坏的数据进行 ...