使用redis(pub/sub)模式实现简单MQ功能

1.什么是MQ

消息队列中间件(MQ)是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ,这里我们简单的使用redis来实现MQ的功能.

2.应用场景

以下介绍消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯四个场景。

2.1 异步处理

一般处理方式:

  • 用户注册后,需要发注册邮件和注册短信.将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端,如此共用时150ms。
    在这里插入图片描述
    异步处理方式:
  • 将注册信息写入数据库成功后,其余的操作异步去执行,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端,这样只需要100ms便可实现全部操作。
    在这里插入图片描述

2.2 应用解耦

比如我们的货款抵扣业务场景,用户生成订单发送MQ后立即返回,结算系统去消费该MQ进行用户账户金额的扣款。这样订单系统只需要关注把订单创建成功,最大可能的提高订单量,并且生成订单后立即返回用户。而结算系统重点关心的是账户金额的扣减,保证账户金额最终一致。
在这里插入图片描述

2.3 流量削锋

还是以订单系统和结算系统场景为例,如果订单系统通过RPC框架来调用结算系统,在有高峰促销的情况下生成订单的量会非常大,而且由于生成订单的速度也非常快,这样势必会给结算系统造成系统压力,服务器利用率则会偏高,但在不是高峰的时间点订单量比较小,结算系统的服务器利用率则会偏低。对于结算系统来说就会出现下面这样的高峰波谷现象图。
在这里插入图片描述
那么如果通过MQ的方式,将订单存储到MQ队列中,消费端通过拉取的方式,并且拉去速度有消费端来控制,则就可以控制流量趋于平稳。这样对于结算系统来讲,就达到了削峰填谷的目的。或者说起到了流控的目标

2.4 消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等

  • 点对点通讯:客户端A和客户端B使用同一队列,进行消息通讯。
    在这里插入图片描述
  • 聊天室通讯:客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
    在这里插入图片描述

3.redis(pub/sub)模式实现

3.1 什么是pub/sub

Pub/Sub功能(means Publish, Subscribe)即发布及订阅功能。基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。熟悉设计模式的朋友应该了解这与23种设计模式中的观察者模式极为相似。
同样,Redis的pub/sub是一种消息通信模式,主要的目的是解除消息发布者和消息订阅者之间的耦合,Redis作为一个pub/sub的server,在订阅者和发布者之间起到了消息路由的功能。

3.2 Redis pub/sub的实现

  1. 首先我们先登陆redis-cli,完后订阅我们喜爱的频道(SUBSCRIBE CCTV)
    在这里插入图片描述
  2. 其次我们再打开一个linux终端,再次登陆redis-cli,并发布我们的消息(PUBLISH CCTV 111111命令中必须指定到CCTV频道)
    在这里插入图片描述
  3. 我们发现,之前监听的那个linux窗口有了新的变化,他接收到了来自CCTV频道的信息1111111
    在这里插入图片描述
    自此,我们就实现了redis(pub/sub)的功能,但是我们怎么使用到我们的项目中呢??

3.3 在php中的实现

  1. 首先在我们的php控制器中实现发布的功能
    public function red()
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379, 3600);
        $message = '用法还是不难的';
        $redis->publish('CCTV',$message);
        echo(12121212);
    }
  1. 完后我们在linux终端中,编写我们订阅的sub.php(sub功能只能在php-cli模式下运行)
		ini_set('default_socket_timeout', -1); 
		// 由于redis扩展也是基于php 的socket方式实现,因此该参数值需要设置为-1(不超时)。
        $redis = new \Redis();
        $redis->connect('127.0.01', 6379, 3600);
        $result = $redis->subscribe(['CCTV'], 'callback');
        function callback($instance, $channelName, $message)
        {
            print_r($message);
        }
  1. 最后我们先在linux中运行php su.php的命令,再在网页中访问控制器red()的地址,得到:
    在这里插入图片描述
    最终,我们简单实现了redis的(pub/sub)模式,模拟了MQ的过程
### 三、Redis 实现消息队列(MQ功能的方法 Redis 提供了多种数据结构,其中 `List`、`Pub/Sub` 和 `Stream` 是实现消息队列的核心机制。这些方式可以用于构建轻量级的异步任务处理系统,适用于对性能要求高但不需要复杂消息中间件的场景。 #### 使用 Redis List 实现简单的队列 Redis 的 `List` 结构支持两端操作,可以使用 `LPUSH` 向队列中添加元素,使用 `RPOP` 或 `BRPOP` 消费元素。这种方式适合于点对点的消息模型: ```java // 生产者代码示例(使用 Jedis) Jedis jedis = new Jedis("localhost"); jedis.lpush("myqueue", "message1"); ``` ```java // 消费者代码示例 while (true) { List<String> message = jedis.brpop(0, "myqueue"); System.out.println("Received: " + message.get(1)); } ``` 该方法的优点是实现简单、部署方便,但缺乏持久化和确认机制,在高并发或网络不稳定的情况下可能会出现消息丢失的问题[^1]。 #### 使用 Redis Pub/Sub 实现发布订阅模式 Redis 的 `PUB/SUB` 模型允许客户端订阅一个或多个频道,并在有新消息发布到这些频道时接收通知。这适用于广播式的通信需求: ```java // 订阅者示例 jedis.subscribe(new JedisPubSub() { @Override public void onMessage(String channel, String message) { System.out.println("Received from " + channel + ": " + message); } }, "channel1"); ``` ```java // 发布者示例 jedis.publish("channel1", "Hello Redis"); ``` 虽然 Pub/Sub 支持一对多的通信模式,但它不提供消息持久化功能,如果订阅者在消息发布时未连接,则会丢失消息[^1]。 #### 使用 Redis Stream 实现高级消息队列 从 Redis 5.0 开始引入的 `Stream` 类型是目前最推荐的方式,它支持持久化、消费者组、确认机制等特性,能够满足大多数消息队列的需求: ```java // 添加消息到 Stream jedis.xadd("mystream", StreamEntryID.NONE, Map.of("field1", "value1")); // 读取消息 List<StreamEntry> entries = jedis.xrange("mystream", StreamEntryID.MINIMUM, StreamEntryID.MAXIMUM, 10); for (StreamEntry entry : entries) { System.out.println(entry.getID() + ": " + entry.getFields()); } ``` 通过 `XREADGROUP` 命令可以实现消费者组的读取逻辑,确保每条消息只被一个消费者处理一次。同时,使用 `XACK` 可以手动确认消息是否已成功处理,避免重复消费或消息丢失的情况[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值