非常感谢依乐祝发表文章《.NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐》,对csredis作了一次完整的诠释。

前言

提到消息队列,最熟悉无疑是 rabbitmq,它基本是业界标准的解决方案。本文详细介绍 redis 多种实现轻订阅方法,作者认为非常有趣并加以总结,希望对有需要的朋友学习 redis 功能有一定的带入作用。

方法一:SUBSCRIBE + PUBLISH

//程序1:使用代码实现订阅端
var sub = RedisHelper.Subscribe(("chan1", msg => Console.WriteLine(msg.Body)));
//sub.Disponse(); //停止订阅 //程序2:使用代码实现发布端
RedisHelper.Publish("chan1", "111");

优势:支持多端订阅、简单、性能高;

缺点:数据会丢失;

参考资料:http://doc.redisfans.com/pub_sub/subscribe.html

方法二:BLPOP + LPUSH(争抢)

//程序1:使用代码实现订阅端
while (running) {
try {
var msg = RedisHelper.BLPop(5, "list1");
if (string.IsNullOrEmpty(msg) == false) {
Console.WriteLine(msg);
}
} catch (Exception ex) {
Console.WriteLine(ex.Message);
}
} //程序2:使用代码实现发布端
RedisHelper.LPush("list1", "111");

优势:数据不会丢失、简单、性能高;

缺点:不支持多端(存在资源争抢);

总结:为了解决方法一的痛点,我们实现了本方法,并且很漂亮的制造了一个新问题(不支持多端订阅)。

学习使用 BLPOP

BLPOP key [key ...] timeout

BLPOP 是列表的阻塞式(blocking)弹出原语。

它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。

当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。

非阻塞行为

当 BLPOP 被调用时,如果给定 key 内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者。

当存在多个给定 key 时, BLPOP 按给定 key 参数排列的先后顺序,依次检查各个列表。

假设现在有 job 、 command 和 request 三个列表,其中 job 不存在, command 和 request 都持有非空列表。考虑以下命令:

BLPOP job command request 0

BLPOP 保证返回的元素来自 command ,因为它是按”查找 job -> 查找 command -> 查找 request “这样的顺序,第一个找到的非空列表。

redis> DEL job command request           # 确保key都被删除
(integer) 0 redis> LPUSH command "update system..." # 为command列表增加一个值
(integer) 1 redis> LPUSH request "visit page" # 为request列表增加一个值
(integer) 1 redis> BLPOP job command request 0 # job 列表为空,被跳过,紧接着 command 列表的第一个元素被弹出。
1) "command" # 弹出元素所属的列表
2) "update system..." # 弹出元素所属的值

阻塞行为

如果所有给定 key 都不存在或包含空列表,那么 BLPOP 命令将阻塞连接,直到等待超时,或有另一个客户端对给定 key 的任意一个执行 LPUSH 或 RPUSH 命令为止。

超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。

redis> EXISTS job                # 确保两个 key 都不存在
(integer) 0
redis> EXISTS command
(integer) 0 redis> BLPOP job command 300 # 因为key一开始不存在,所以操作会被阻塞,直到另一客户端对 job 或者 command 列表进行 PUSH 操作。
1) "job" # 这里被 push 的是 job
2) "do my home work" # 被弹出的值
(26.26s) # 等待的秒数 redis> BLPOP job command 5 # 等待超时的情况
(nil)
(5.66s) # 等待的秒数

更多学习资料:http://doc.redisfans.com/list/blpop.html

方法三:BLPOP + LPUSH(非争抢)

本方法根据方法二演变而来,设计图如下:

如何实现三端订阅,都可收到消息,三端分别为 sub3, sub4, sub5:

1、sub3, sub4, sub5 使用【方法二】订阅 listkey:list1_sub3,list1_sub4,list1_sub5;

2、总订阅端订阅 listkey:list1,总订阅端收到消息后,执行 lpush list1_sub1 msg, lpush list1_sub2 msg, lpush list1_sub3 msg;

总订阅端订阅原始消息,随后将消息分发给其他订阅端,从而解决【方法二】不支持多端同时订阅的缺点。

最终实现的逻辑为:多端先争抢 list1 消息,抢到者再向其他端转发消息。

测试代码

nuget Install-Package CSRedisCore

var rds = new CSRedis.CSRedisClient("127.0.0.1:6379,password=,poolsize=50,ssl=false,writeBuffer=10240");

//sub1, sub2 争抢订阅(只可一端收到消息)
var sub1 = rds.SubscribeList("list1", msg => Console.WriteLine($"sub1 -> list1 : {msg}"));
var sub2 = rds.SubscribeList("list1", msg => Console.WriteLine($"sub2 -> list1 : {msg}")); //sub3, sub4, sub5 非争抢订阅(多端都可收到消息)
var sub3 = rds.SubscribeListBroadcast("list2", "sub3", msg => Console.WriteLine($"sub3 -> list2 : {msg}"));
var sub4 = rds.SubscribeListBroadcast("list2", "sub4", msg => Console.WriteLine($"sub4 -> list2 : {msg}"));
var sub5 = rds.SubscribeListBroadcast("list2", "sub5", msg => Console.WriteLine($"sub5 -> list2 : {msg}")); //sub6 是redis自带的普通订阅
var sub6 = rds.Subscribe(("chan1", msg => Console.WriteLine(msg.Body))); Console.ReadKey();
sub1.Dispose();
sub2.Dispose();
sub3.Dispose();
sub4.Dispose();
sub5.Dispose();
sub6.Dispose(); rds.Dispose();
return;

测试功能时,发布端可以使用 redis-cli 工具。

结语

redis 功能何其多且相当好玩有趣 ,大家应尽可能多带着兴趣爱好去学习它。

若文中有不好的地方,请提出批评与改正方法,谢谢观赏。

本文使用到 CSRedisCore 的开源地址:https://github.com/2881099/csredis

【由浅至深】redis 实现发布订阅的几种方式的更多相关文章

  1. [翻译] C# 8.0 新特性 Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南) 【由浅至深】redis 实现发布订阅的几种方式 .NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

    [翻译] C# 8.0 新特性 2018-11-13 17:04 by Rwing, 1179 阅读, 24 评论, 收藏, 编辑 原文: Building C# 8.0[译注:原文主标题如此,但内容 ...

  2. redis的发布订阅模式

    概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer {     /* Pubsub */     // 字典,键为频道, ...

  3. StackExchange.Redis 使用-发布订阅 (二)

    使用Redis的发布订阅功能 redis另一个常见的用途是发布订阅功能 . 它非常的简单 ,当连接失败时 ConnectionMultiplexer 会自动重新进行订阅 . ISubscriber s ...

  4. .net core 使用Redis的发布订阅

    Redis是一个性能非常强劲的内存数据库,它一般是作为缓存来使用,但是他不仅仅可以用来作为缓存,比如著名的分布式框架dubbo就可以用Redis来做服务注册中心.接下来介绍一下.net core 使用 ...

  5. redis的发布订阅模式pubsub

    前言 redis支持发布订阅模式,在这个实现中,发送者(发送信息的客户端)不是将信息直接发送给特定的接收者(接收信息的客户端),而是将信息发送给频道(channel),然后由频道将信息转发给所有对这个 ...

  6. java实现 redis的发布订阅(简单易懂)

    redis的应用场景实在太多了,现在介绍一下它的几大特性之一   发布订阅(pub/sub). 特性介绍: 什么是redis的发布订阅(pub/sub)?   Pub/Sub功能(means Publ ...

  7. spring boot 使用redis进行发布订阅

    异步消息的方式有很多,这篇博客介绍如何使用redis进行发布订阅, 完成这个示例只需要三个文件 1.redis消息监听配置 @Configuration public class RedisListe ...

  8. 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能

    springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...

  9. redis的发布订阅、持久化存储、redis的主从复制

    redis的发布订阅 1. 创建redis配置文件 vim /opt/redis_conf/reids-6379.conf mkdir /data/6379 redis-server  redis-6 ...

随机推荐

  1. 烂泥:jira7.2安装、中文及破解

    . jira的主要配置文件,存放在/opt/atlassian/jira/conf/server.xml文件中,如下: vim /opt/atlassian/jira/conf/server.xml ...

  2. Linux课程实践四:ELF文件格式分析

    一.ELF文件格式概述 1. ELF文件 ELF:Executable and Linking Format,是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东 ...

  3. 代码验证浏览器是否支持html audio 和video

    <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...

  4. 如何实现桌面App图标可以动态显示消息数(类似手机上的QQ图标)?

    手机上的APP , 像QQ和微信等都可以在图标上动态显示消息数(最大99) , 那么你有没有想过这些效果是如何实现的?桌面上开发的传统应用程序能否也实现类似的功能? 1 思路 桌面快捷方式的图标本质上 ...

  5. phaser运用中,dota战术板

    首发:个人博客,更新&纠错&回复 还是没想好用phaser做个啥小游戏好,以每年春节打dota的这两伙人为基础是肯定的,但游戏具体咋做还没头绪. 暂时试着做了个卡通版dota地图,可以 ...

  6. Linux下查看文件属性

    1.ls ls -a 查看所有文件,就是包含隐藏文件 ls -l 查看详细的属性,包括文件类型(d表示目录,-表示普通文件,l表示链接文件),文件的权限(所有者权限,所属组权限,其他人权限),所有者, ...

  7. SQL日期操作及只获取日期的方法

    datepart()函数的使用                          * datepart()函数可以方便的取到时期中的各个部分*如日期:2006-07--02 18:15:36.513* ...

  8. 配置主机路由表(route)(两)

    我们谈到了路由在互联网为基础的时间问题,必须有一个路径之间的两个主机可通信 TCP/IP 合约,否则就不能是有线啊! 一般来说.只要有一个网络接口,的接口将产生的路由.例如,在哥斯达黎加的内部主机鸟有 ...

  9. 聊一聊FE面试那些事

    聊一聊FE面试那些事 最近公司由于业务的扩展.技术的延伸需要招一批有能力的小伙伴加入,而我有幸担任"技术面试官"的角色前前后后面试了不下50多位候选人,如同见证了50多位前端开发者 ...

  10. Andrew Ng机器学习课程笔记--week3(逻辑回归&amp;正则化参数)

    Logistic Regression 一.内容概要 Classification and Representation Classification Hypothesis Representatio ...