当前位置:网站首页>Redis實現消息隊列的4種方案
Redis實現消息隊列的4種方案
2022-06-12 01:40:00 【柔情柴少】
redis實現消息隊列的集中方案:
1、基於List的LPUSH和BRPOP實現
2、PUB/SUB,訂閱/發布模式
3、基於Sorted-Set的實現
4、基於Stream類型的實現
1、基於list列錶的lpush和brpop實現消息隊列
生產者,模擬30個商品id,存入list列錶
<?php
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis->select(0);
$goodsId = 30;
$key = "sec_kill:active:active_1";
// 循環添加商品
for ($i=1;$i<=$goodsId;$i++){
$redis->rPush($key,$i);
}消費者,把商品id從list列錶取出來,模擬用戶id,一 一對應30對,存入hash,剩下2970用戶秒殺失敗,存一個數量,並且把失敗用戶的編號存入列錶list
<?php
// 假裝是用戶的唯一標識
$uuid = md5(uniqid('user').time());
// 創建鏈接redis對象
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$redis->select(0);
$goodsKey = "sec_kill:active:active_1";
$orderKey = "sec_kill:active:order_1";
$failUserNum = "sec_kill:active:fail_user_num";
$failUser = "sec_kill:active:fail_user";
if ($goodsId = $redis->lPop($goodsKey)){
// 秒殺成功
// 把幸運用戶存在集合中
$redis->hSet($orderKey,$goodsId,$uuid);
echo "下單成功".PHP_EOL;
}else{
// 秒殺失敗 將失敗用戶計數
$redis->incr($failUserNum);
$redis->rPush($failUser,$uuid);
echo "下單失敗".PHP_EOL;
}按理說,應該有監聽者watcher,監聽watcher的list,是否還有商品沒有消費,如果過期沒消費,則應該存入生產列錶,再次循環消費(博客觀看者,這一段可以不用看,作者寫給自己的,因為和上下文不對應,可能把你看迷糊)
2、redis發布/訂閱(PUB/SUB)實現消息隊列
(1)首先,介紹2組概念
channel:頻道,管道,信道,它就是一個通道,所有訂閱了該頻道的客戶端,都可以收到該頻道發出的消息
pattern:模式,或者說,多個頻道的集合,(有點類似正則的感覺),訂閱了該模式,所有能匹配到的頻道所發出的消息,該客戶端都能收到
(2)channel和pattern底層實現原理
當一個客戶端執行subscribe命令,訂閱某個或某些頻道的時候,這個客戶端於被訂閱頻道之間就建立起了一種訂閱關系。
Redis將所有頻道的訂閱關系都保存在服務器狀態的pubsub_channels字典裏面,這個字典的鍵是被訂閱的頻道,而鍵的值則是一個鏈錶,鏈錶裏面記錄了所有訂閱這個頻道的客戶端,底層C語言實現原理:
struct redisServer {
// ...
// 保存所有頻道的訂閱關系
dict *pubsub_channels;
// ...
};根據頻道是否已有其他訂閱者,關聯操作分為兩種情况執行:
1、如果頻道已有其他訂閱者,那麼它在pubsub_channels字典中必然有相應的訂閱者鏈錶,程序唯一要做的就是將客戶端添加到訂閱者鏈錶的末尾
2、如果頻道還沒有任何訂閱者,那麼它必然不存在與pubsub_channels字典,程序首先要在pubsub_channels字典中為頻道創建一個鍵,並將這個鍵的值設置為空鏈錶,然後再將客戶端添加到鏈錶,成為鏈錶的第一個元素
subscribe命令的實現可以用以下偽代碼來描述:
def subscribe(*all_input_channels):
# 遍曆輸入的所有頻道
for channel in all_input_channels:
# 如果 channel 不存在於 pubsub_channels 字典(沒有任何訂閱者)
# 那麼在字典中添加 channel 鍵,並設置它的值為空鏈錶
if channel not in server.pubsub_channels:
server.pubsub_channels[channel] = []
# 將訂閱者添加到頻道所對應的鏈錶的末尾
server.pubsub_channels[channel].append(client)
聲明:這一部分借鑒了《RabbitMQ兔老大》,本文秉著友好交流學習的目的做一下個人總結,不做任何商用,原文連接:https://blog.csdn.net/hebtu666/article/details/114827837
unsubscribe命令和subscribe命令行為正好相反,當一個客戶端退訂某個或者某些頻道時,服務器將從pubsub_channels中解除客戶端於被退訂頻道之間的關聯:
1、程序會根據被退訂頻道的名字, 在
pubsub_channels字典中找到頻道對應的訂閱者鏈錶, 然後從訂閱者鏈錶中删除退訂客戶端的信息2、如果删除退訂客戶端之後, 頻道的訂閱者鏈錶變成了空鏈錶, 那麼說明這個頻道已經沒有任何訂閱者了, 程序將從
pubsub_channels字典中删除頻道對應的鍵
unsubscribe命令的實現可以用以下偽代碼來描述:
def unsubscribe(*all_input_channels):
# 遍曆要退訂的所有頻道
for channel in all_input_channels:
# 在訂閱者鏈錶中删除退訂的客戶端
server.pubsub_channels[channel].remove(client)
# 如果頻道已經沒有任何訂閱者了(訂閱者鏈錶為空)
# 那麼將頻道從字典中删除
if len(server.pubsub_channels[channel]) == 0:
server.pubsub_channels.remove(channel)模式部分:
服務器將所有模式的訂閱者關系存在了pubsub_Patterns屬性裏
struct redisServer {
// 保存所有頻道的訂閱關系
list *pubsub_patterns;
};pubsub_Patterns屬性是一個鏈錶,每個結點是被訂閱的模式,節點內記錄了模式,節點內的client屬性記錄了訂閱模式的客戶端
typedef struct pubsubPattern{
//訂閱模式的客戶端
redisClient *client;
//被訂閱的模式
robj *pattern;
}pubsubPattern;每當客戶端執行PSUBSCRIBE這個命令來訂閱某個或某些模式時,服務器會對每個被訂閱的模式執行下面的操作:
1)新建一個pubsubPattern結構,設置好兩個屬性
2)將新節點加到pubsub_patterns尾部
偽代碼實現:
def osubscribe(*all_input_patterns):
#遍曆所有輸入的模式
#記錄被訂閱的模式和對應的客戶端
pubsubPattern=create()
pubsubPattern.client=client
pubsubPattern.pattern=pattern
#插入鏈錶末尾
server.pub_patterns.append(pubsubPattern)模式退訂命令PUNSUBSCRIBE是PSUBSCRIBE的反操作
服務器將找到並删除那些被退訂的模式
def osubscribe(*all_input_patterns):
#遍曆所有退訂的模式
for pattern in all_input_patterns:
#遍曆每一個節點
for pubsubPattern in server.pubsub_patterns:
#如果客戶端和模式都相同
if client==pubsubPattern.client:
if pattern==pubsubPattern.pattern:
#删除
server.pub_patterns.remove(pubsubPattern)發送消息:
當一個客戶端執行PUBLISH<channel> <message>命令將消息發送給頻道時,服務器需要:
1)把消息發送給所有本頻道的訂閱者
具體做法就是去pubsub_channels字典找到本頻道的鏈錶,也就是訂閱名單,然後發消息
2)將消息發給,包含本頻道的所有模式中的所有訂閱者
具體做法就是去pubsub_patterns查找包含本頻道的模式,並且把消息發送給訂閱它們的客戶端。
查看訂閱信息:
redis2.8新增三個命令,用來查看頻道和模式的相關信息。
PUBLISH CHANNELS[pattern]用於返回服務器當前被訂閱的頻道,pattern可寫可不寫,不寫就查看所有,否則查看與pattern匹配的對應頻道
這個子命令是通過遍曆pubsub_channels字典實現的。
PUBLISH NUMSUB[CHANNEL-1 CHANNEL-2.....]返回這些頻道的訂閱者數量
這個子命令是通過遍曆pubsub_channels字典,查看對應鏈錶長度實現的。
PUBLISH NUMPAT返回被訂閱模式數量
這個子命令是通過返回pubsub_patterns的長度實現的。
總而言之,PUBSUB 命令的三個子命令都是通過讀取 pubsub_channels 字典和 pubsub_patterns 鏈錶中的信息來實現的。
個人實操:
四個客戶端 A、B、C、D,A客戶端訂閱了頻道 news.it D客戶端訂閱了頻道news.et BC客戶端訂閱了模式 news.[ie]t,此處中括號內,ie兩個字母部分先後順序
A命令:subscribe news.it
B命令:psubscribe news.[ie]t
C命令:psubscribe news.[ie]t
D命令:subscribe news.et
當我們發布消息時:publish news.it 'She is not boy!' 請看效果圖:

當我們發布訂閱消息時:publish news.et 'He is not girls! And this boy is very cute!'

注:從左到右,從上到下,一次分別為客戶端 ABCD 可見模式類似正則,匹配到多少頻道,當這些頻道發消息時,訂閱該頻道的客戶端,以及訂閱相關模式的客戶端,都會收到消息
下面:通過PHP代碼,盡可能去實現消息隊列
今天沒寫完,請翻看本博主,下一篇redis講解,明日寫完
边栏推荐
- On the night of the joint commissioning, I beat up my colleagues
- 大一下期:学习总结
- Article 6: Design of multi-functional intelligent trunk following control system | undergraduate graduation design - [Key Technology - positioning technology related data (UWB WiFi Bluetooth)]
- 一文get,最容易碰上的接口自动化测试问题汇总
- 2022年金属非金属矿山(小型露天采石场)安全管理人员考试模拟100题及模拟考试
- Design practice of rongyun Im on electron platform
- Ce soir - là, j'ai battu mon collègue...
- 【项目实训】微信公众号模板消息推送
- 螺旋矩阵(技巧)
- 马尔可夫网络 与 条件随机场
猜你喜欢

Defect detection, introduction to Halcon case.

pip运行报错:Fatal error in launcher: Unable to create process using

Don't write about the full screen explosion, try the decorator mode, this is the elegant way!!

Basic use of MATLAB

Go language learning summary (7) -- Dachang go programming specification summary

联调这夜,我把同事打了...

Entity class dto to VO is converted through plug-in

"Xilin chain" of Southwest Forestry University passed the functional test of Electronic Standards Institute of the Ministry of industry and information technology | FISCO bcos case

Why should a redis cluster use a reverse proxy? Just read this one

Prism框架初识-模块化介绍
随机推荐
[project training] wechat official account to obtain user openid
Article 3: Design of multifunctional intelligent trunk following control system | undergraduate graduation project - [defense ppt]
Detailed explanation and examples of common parameters of curl
Jmeter接口测试之常用断言
聯調這夜,我把同事打了...
Investment analysis and prospect forecast report of wearable biosensor industry for global and Chinese medical monitoring 2022 ~ 2028
Forecast report on market demand and future prospect of cvtf industry of China's continuously variable transmission oil
In depth description of Weibull distribution (2) meaning of parameters and formulas
Common assertions for JMeter interface testing
How to buy children's serious illness insurance, what to pay attention to and how to choose products
In 2022, the internal promotion of the "MIHA Tour" golden, silver and silver social recruitment started in April and march! Less overtime, good welfare, 200+ posts for you to choose, come and see!
Weekly CTF 第一周:神奇的磁带
New knowledge: monkey improved app crawler
“还是学一门技术更保险!”杭州校区小哥哥转行软件测试,喜提10K+双休!
Advanced data storage
[从零开始学习FPGA编程-20]:快速入门篇 - 操作步骤4-2-Altera Quartus II工具的快速使用(modelSim联合仿真、程序下载到Altera开发板)
[C language] summary of basic knowledge points of pointer
联调这夜,我把同事打了...
UoE UG2 Inf Course Research
实体类DTO转VO通过插件转化