Redis核心实战:消息队列与Feed流全解析

一、Redis同步秒杀

同步秒杀就是用户请求经 Nginx 到 Tomcat,再按查优惠券、判库存等步骤和 MySQL 交互。

缺点:

  1. 高并发时 Tomcat 压力大,容易扛不住;
  2. 和数据库交互频繁,数据库也容易被打垮,而且整个过程是同步的,用户得一直等着,体验不太好。

二、Redis异步秒杀

1、基于阻塞队列的异步秒杀

1.1 基本流程

用户请求经 Nginx 到 Redis 校验,信息存阻塞队列,Tomcat 异步处理。阻塞队列实现异步秒杀,能削峰填谷,缓冲高并发请求,让系统更稳定;还能异步处理,提升响应速度和用户体验,而且能解耦系统组件,方便维护扩展~

案例:优惠券秒杀的流程
需求:
① 新增秒杀优惠券的同时,将优惠券信息保存到 Redis 中
② 基于 Lua 脚本,判断秒杀库存、一人一单,决定用户是否抢购成功
③ 如果抢购成功,将优惠券 id 和用户 id 封装后存入阻塞队列
④ 开启线程任务,不断从阻塞队列中获取信息,实现异步下单功能

先执行 Lua 脚本,判断库存和用户下单情况,符合条件就扣库存、记录用户,结果为 0 就把信息存阻塞队列异步下单,靠 Redis 高效处理和异步队列,提升秒杀性能与体验~

1.2 小结

秒杀业务优化思路:
① 用 Redis 判断库存余量、一人一单,完成抢单。

② 下单业务放阻塞队列,独立线程异步下单。

基于阻塞队列的异步秒杀问题:

    •    内存限制问题

    •    数据安全问题

2、Redis消息队列实现异步秒杀

2.1 什么是消息队列

消息队列(Message Queue):字面意思就是存放消息的队列。最简单的消息队列模型包括 3 个角色:

  1.     消息队列:存储和管理消息,也被称为消息代理(Message Broker)
  2.    生产者:发送消息到消息队列
  3.    消费者:从消息队列获取消息并处理消息

    流程:生产者判断秒杀时间和库存、校验一人一单后,发优惠券 id 等消息到队列,消费者接收消息完成下单。

Redis 提供了三种不同的方式来实现消息队列:

 •    list 结构:基于 List 结构模拟消息队列

 •    PubSub:基本的点对点消息模型

 •    Stream:比较完善的消息队列模型

三、 Redis实现消息队列的三种方式

1、list 结构

1.1 基于 List 结构模拟消息队列:

Redis的list数据结构是一个双向链表,很容易模拟出队列效果。

队列是入口和出口不在一边,因此我们可以利用:LPUSH结合RPOP、或者RPUSH结合LPOP来实现。

不过要注意的是,当队列中没有消息时RPOP或LPOP操作会返回null,并不像JVM的阻塞队列那样会阻塞并等待消息。因此这里应该使用BRPOP或者BLPOP来实现阻塞效果。

1.2 小结

基于List的消息队列有哪些优缺点?

优点:

• 利用Redis存储,不受限于JVM内存上限

• 基于Redis的持久化机制,数据安全性有保证

• 可以满足消息有序性

缺点:

• 无法避免消息丢失

• 只支持单消费者

2、PubSub:基本的点对点消息模型

2.1 基于PubSub的消息队列

PubSub(发布订阅)是Redis2.0版本引入的消息传递模型。顾名思义,消费者可以订阅一个或多

个channel,生产者向对应channel发送消息后,所有订阅者都能收到相关消息。

■ SUBSCRIBE channel [channel]:订阅一个或多个频道

■ PUBLISH channel msg:向一个频道发送消息

■ PSUBSCRIBE pattern[pattern]:订阅与pattern格式匹配的所有频道

2.2 小结

基于PubSub的消息队列有哪些优缺点?

优点:

• 采用发布订阅模型,支持多生产、多消费

缺点:

• 不支持数据持久化

• 无法避免消息丢失

• 消息堆积有上限,超出时数据丢失

3、Stream:比较完善的消息队列模型

3.1 基于Stream的消息队列

Stream 是 Redis 5.0 引入的一种新数据类型,可以实现一个功能非常完善的消息队列。

发送消息的命令:

例如:

3.2 基于Stream的消息队列——XREAD

读取消息的方式之一:XREAD

XREAD阻塞方式,读取最新的消息:

在业务开发中,我们可以循环的调用XREAD阻塞方式来查询最新消息,从而实现持续监听队列的效果,伪代码如下:

while(true){
// 尝试读取队列中的消息,最多阻塞2秒
Object msg = redis.execute("XREAD COUNT 1 BLOCK 2000 STREAMS users $");
if(msg == null){
continue;
}
// 处理消息
handleMessage(msg);
}

注意:当我们指定起始ID为$时,代表读取最新的消息,如果我们处理一条消息的过程中,又有超过1条以上的消息到达队列,则下次获取时也只能获取到最新的一条,会出现漏读消息的问题。

3.2.1 小结

STREAM类型消息队列的XREAD命令特点:

• 消息可回溯

• 一个消息可以被多个消费者读取

• 可以阻塞读取

• 支持持久化

3.3 基于Stream的消息队列-消费者组

创建消费者组:

XGROUP CREATE  key groupName ID [MKSTREAM]

• key:队列名称
• groupName:消费者组名称
• ID:起始ID标示,$代表队列中最后一个消息,0则代表队列中第一个消息
• MKSTREAM:队列不存在时自动创建队列

其它常见命令:

# 删除指定的消费者组

XGROUP DESTORY key groupName

# 给指定的消费者组添加消费者

XGROUP CREATECONSUMER key groupname consumername

# 删除消费者组中的指定消费者

XGROUP DELCONSUMER key groupname consumername

从消费者组读取消息:

XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS 
key [key ...] ID [ID ...]
  • group:消费组名称
  • consumer:消费者名称,如果消费者不存在,会自动创建一个消费者
  • count:本次查询的最大数量
  • BLOCK milliseconds:当没有消息时最长等待时间
  • NOACK:无需手动 ACK,获取到消息后自动确认
  • STREAMS key:指定队列名称
  • ID:获取消息的起始 ID:

           • ">":从下一个未消费的消息开始

           • 其它:根据指定 id 从 pending-list 中获取已消费但未确认的消息,例如 0,是从 pending-                list 中的第一个消息开始

XREADGROUP命令特点
  1.  消息可回溯
  2. 可以多消费者争抢消息,加快消费速度
  3. 可以阻塞读取
  4. 没有消息漏读的风险
  5. 有消息确认机制,保证消息至少被消费一次

4、Redis消息队列总结

List PubSub Stream 
消息持久化支持不支持支持
阻塞读取支持支持支持
消息堆积处理受限于内存空间,可以利用多消费者加快处理受限于消费者缓冲区受限于队列长度,可以利用消费者组提高消费速度,减少堆积
消息确认机制不支持不支持支持
消息回溯不支持不支持支持

四、Redis加持下的Feed流

Feed 流作为当下信息推送的主流形式,能让用户快速获取关注内容。而 Redis 凭借其高效的数据存储与处理能力,为 Feed 流的高效运行保驾护航。比如在数据存储上,Redis 的多种数据结构能适配 Feed 流不同场景需求;在内容推送时,Redis 的消息队列机制让信息流转更顺畅。下面我们来看看 Feed 流常见模式及 Redis 在其中的关键作用~

Feed流产品有两种常见模式:

    •    Timeline:不做内容筛选,简单的按照内容发布时间排序,常用于好友或关注。例如朋友圈,Redis 可利用列表(List)结构按时间存储内容,快速构建 Timeline 流~

                 优点:信息全面,不会有缺失。并且实现也相对简单

                 缺点:信息噪音较多,用户不一定感兴趣,内容获取效率低

    •    智能排序:利用智能算法屏蔽掉违规的、用户不感兴趣的内容。推送用户感兴趣信息来吸引用户,Redis 能利用它高效读取存储用户兴趣数据,辅助算法更精准推送~

                 优点:投喂用户感兴趣信息,用户粘度很高,容易沉迷

                  缺点:如果算法不精准,可能起到反作用

下面的例子是基于关注的好友来做Feed流,因此采用Timeline模式,该模式的实现方案有三种:
① 拉模式
② 推模式
③ 推拉结合

  • 拉模式(读扩散)时,Redis 可快速聚合用户关注对象发件箱内容;
  • 推模式(写扩散)下,Redis 消息队列能高效把内容推给粉丝收件箱;
  • 推拉结合模式,Redis 能结合两者优势,让大 V 内容及时推、普通内容按需拉,平衡效率与存储~

下面来看看这几种模式的解析及优缺点~

1、拉模式

拉模式:也叫读扩散,就是用户主动去拉取关注对象发的内容,系统实时聚合这些内容形成 Feed 流~像图里,张三、李四、王五发内容存发件箱,赵六关注他们,主动从发件箱读取内容到自己收件箱,这就是拉模式~它实现简单,但用户拉取时系统运算压力可能大些~

2、推模式

推模式:Feed 流推模式(写扩散),就是用户发布内容时,系统马上把内容推到所有粉丝的收件箱,粉丝看 Feed 直接读自己收件箱就行~像图里张三、李四发内容,粉丝 1、2、3 的收件箱就有对应的消息,读取很方便~不过这种模式如果粉丝多,存储压力会大些~

3、推拉结合模式

推拉结合模式:也叫读写混合。就是结合推、拉两种模式的优点~像大 V 发内容用推模式,直接推给粉丝收件箱,普通人内容粉丝按需拉取~这样既保证大 V 内容及时触达,又减轻存储压力,让 Feed 流又快又省资源~

4、三种模式总结

拉模式推模式推拉结合
写比例
读比例
用户读取延迟
实现难度复杂简单很复杂
使用场景很少使用用户量少,没有大V过千万的用户量,有大V

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值