背景

有时候,在微服务时代,我们需要对全部的机器节点进行通知。在常规情况下,一个请求经过负载均衡只有一个机器可以收到。那么,如何能让全部的机器都收到同样的请求呢?需要借助消息队列的监听机制,让每个节点都监听一个队列,让消息发送到所有的队列中。

rabbit MQ的fanout交换机可以实现这种功能。

那么,如果想用redis去实现这个功能,有没有什么好的选择呢?毕竟仅仅为了一个全部节点的推送,就引入另外一个中间件,不是一个很经济选择。

那么Redis的Stream结构就是一个可以选择的了。

实现

对于Redis的Stream结构,诞生之初就是为了用作消息队列的。具体用法如下:

  • 发送消息
public void sendConfigMessage() {
MapRecord<String, String, String> entries = StreamRecords.mapBacked(Collections.singletonMap("msg", "plsGet")).withStreamKey(RedisConfig.stream);
// 将消息添加至消息队列中
redisTemplate.opsForStream().add(entries);
}
  • 建立监听
    @Bean
public Subscription subscription(RedisConnectionFactory factory) {
Set<String> keys = redisTemplate.keys(streamPattern);
if (keys != null && keys.size() != 0) {
keys = keys.stream().filter(key -> !key.equals(stream)).collect(Collectors.toSet());
if (keys.size() != 0) {
redisTemplate.delete(keys);
}
} group = UUID.randomUUID().toString();
if (Boolean.FALSE.equals(redisTemplate.hasKey(stream))) {
StringRecord stringRecord = StreamRecords.string(Collections.singletonMap("msg", "init")).withStreamKey(RedisConfig.stream);
redisTemplate.opsForStream().add(stringRecord);
} redisTemplate.opsForStream().createGroup(stream, group);
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String, String, String>> options = StreamMessageListenerContainer
.StreamMessageListenerContainerOptions
.builder()
.pollTimeout(Duration.ofSeconds(1))
.build();
StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer = StreamMessageListenerContainer.create(factory, options);
Subscription subscription = listenerContainer.receiveAutoAck(Consumer.from(group, "consumer1"), StreamOffset.create(configStream, ReadOffset.lastConsumed()), configStreamListener);
listenerContainer.start();
return subscription;
}

对于每一台机器,都让它关联唯一的消费组,而这个功能关联唯一的stream key。Redis的stream机制在于,每一条给stream key发送的消息都会推送给所有的消费组,这样所有的机器都会收到这条消息。

一些问题

Redis的连接和MQ还是有一些区别。当Redis连接超时之后,之前建立的监听就不能用了,因为之前的长连接断开了。

一个解决档案就是手动维持一个Netty的心跳机制,不停轮训判断当前的订阅是否还处于活跃状态。一旦不处于活跃状态就要重新建立长连接:

    @Autowired
Subscription subscription; @Autowired
RedisConnectionFactory factory; @Autowired
StreamListener streamListener; @Autowired
RedisTemplate<String, Object> redisTemplate; //当Redis连接超时,自动重置stream队列。否则监听失效
@Bean
public ClientResources clientResources(){ NettyCustomizer nettyCustomizer = new NettyCustomizer() { @Override
public void afterChannelInitialized(Channel channel) {
channel.pipeline().addLast(
new IdleStateHandler(0, 0, 10)); channel.pipeline().addLast(new ChannelDuplexHandler() {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (subscription != null && !subscription.isActive()) {
synchronized ("resetStreamLock") {
if (!subscription.isActive()) {
StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, MapRecord<String, String, String>> options = StreamMessageListenerContainer
.StreamMessageListenerContainerOptions
.builder()
.pollTimeout(Duration.ofSeconds(1))
.build();
StreamMessageListenerContainer<String, MapRecord<String, String, String>> listenerContainer0 = StreamMessageListenerContainer.create(factory, options);
Subscription subscription0 = listenerContainer0.receiveAutoAck(Consumer.from(RedisConfig.group, "consumer1"), StreamOffset.create(RedisConfig.stream, ReadOffset.lastConsumed()), streamListener);
listenerContainer0.start();
subscription = subscription0;
log.info("reset getStream!");
}
}
}
if (evt instanceof IdleStateEvent) {
ctx.disconnect();
}
}
});
} @Override
public void afterBootstrapInitialized(Bootstrap bootstrap) { } }; return ClientResources.builder().nettyCustomizer(nettyCustomizer ).build();
}

Redis Stream实现全部节点机器推送消息的更多相关文章

  1. wp推送消息笔记

    最近想给应用添加推送消息,主要是toast消息,所以就打算去了解一下wp消息推送机制以及实现方法,过程中,查了许多资料,也遇到过一些问题,做完后,自己就做个小笔记,总结一下,好记性不如烂笔头嘛,以后可 ...

  2. 使用极光推送(www.jpush.cn)向安卓手机推送消息【服务端向客户端主送推送】C#语言

    在VisualStudio2010中新建网站JPushAndroid.添加引用json帮助类库Newtonsoft.Json.dll. 在web.config增加appkey和mastersecret ...

  3. HTML5服务器推送消息的各种解决办法

    摘要 在各种BS架构的应用程序中,往往都希望服务端能够主动地向客户端推送各种消息,以达到类似于邮件.消息.待办事项等通知. 往BS架构本身存在的问题就是,服务器一直采用的是一问一答的机制.这就意味着如 ...

  4. python 全栈开发,Day131(向app推送消息,玩具端消息推送)

    先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.4.zip 注意:由于涉及到 ...

  5. Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息)

    推荐阅读:Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)​ 需求分析 我们假设有一个需求,我在后端点击按钮 1,首页弹出 “后端触发了按钮 1”.后端点了 ...

  6. 使用PushSharp给iOS应用推送消息

    PushSharp是一个C#编写的服务端类库,用于推送消息到各种客户端,支持iOS(iPhone/iPad).Android.Windows Phone.Windows 8.Amazo.Blackbe ...

  7. android不需要Socket的跨进程推送消息AIDL!

    上篇介绍了跨进程实时通讯http://www.cnblogs.com/xiaoxiaing/p/5818161.html 但是他有个缺点就是服务端无法推送消息给客户端,今天这篇文章主要说的就是服务器推 ...

  8. 用JPUSH极光推送实现服务端向安装了APP应用的手机推送消息(C#服务端接口)

    这次公司要我们做一个功能,就是当用户成功注册以后,他登录以后要收到消息,当然这个消息是安装了我们的手机APP应用的手机咯. 极光推送的网站的网址是:https://www.jpush.cn/ 极光推送 ...

  9. iOS点击推送消息跳到应用指定页面

    现在的推送用的越来越频繁,几乎每个应用都开始用到了.其实又有几个用户会去看推送消息呢?没办法,产品经理最大啊,只是苦了我们这一帮程序员啊!闲话少说,进入正题.兄弟我用的是极光推送,自然是以极光推送为例 ...

  10. signalr推送消息

    参考:Tutorial: Getting Started with SignalR 2 and MVC 5 环境:vs2013,webapi2,entity framework6.0 实现效果:当用户 ...

随机推荐

  1. shell语法4-printf命令、test命令和判断符号[]、逻辑运算符&&和||

    一.printf命令 printf命令用于格式化输出,类似于C/C++中的printf函数. 默认不会在字符串末尾添加换行符!!! 例如: printf "%10d.\n" 123 ...

  2. 软件工程日报三——创建一个简单app和SDK的介绍

    昨天讲安卓studio和gradle等软件和环境都配置成功,今天开始创建第一个app. 一.打开Android studio,创建一个新文件,点击File,选择New Project里面的Empty ...

  3. 【vcpkg】使用vcpkg安装库

    https://blog.csdn.net/cjmqas/article/details/79282847 使用vcpkg 查看vcpkg支持的开源库列表 执行命令 .\vcpkg.exe searc ...

  4. css 卡片hover效果

    .card { height: 430px; width: 100%; background:#ffffff; border:1px solid #eaeefb; border-radius:5px; ...

  5. vue3.0 dialog无法弹出的问题

    最近用elementui做了点东西,一直感觉挺好的,但是嫖的别人的框架是vue3.0,这次的dialog就弹不出来了. 经过多方查证,发现vue3.0的element为了适配移动端升级为element ...

  6. 使用IntelliJ创建第一个简单的Springboot项目

    使用Intellij创建Springboot项目 使用IntelliJ创建Springboot项目是非常方便的,创建过程中,我们可以自由的选择要启用的springboot生态里的各种框架.插件.本文只 ...

  7. 【Java学习Day11】变量种类及命名规范

    变量 变量是什么:就是可以变化的量 Java是一种强类型语言,每个变量都必须声明其类型 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=valu ...

  8. 【Java学习Day02】基本的Dos命令

    基本的Dos命令学习 打开CMD的方式 Windows+S,输入cmd打开命令控制台 鼠标右键单击windows图标,再单击windows终端(管理员)即可以管理员的身份打开PowerShell/CM ...

  9. 关闭win10“快速启动”功能

    windows正常运行时间的统计问题 windows任务管理器中,在性能选项卡中可以查看系统的运行时间(开机时间) 正常情况下,如果电脑关机,那么再次开机后,该时间会被重置 但是,如果电脑处于上面所说 ...

  10. 关于ecplipse中的中文都成乱码的问题

    这个问题之前也搞死我了,差不多搞了两个下午才搞好 唉,说多了都是泪 时间过的有点久,不是很记得了,不过我这个问题是装fx包之前发生的,后来我是改了jdk版本的所以可能会有些不同 首先,中文会变成乱码主 ...