Redis消息队列与客户端编程
文章目录
消息队列
消息队列:把要传输的数据放在队列中,从而实现应用之间的数据交换
常用功能:可以实现多个应用系统之间的解耦,异步,削峰/限流等
常用的消息队列应用:Kafka,RabbitMQ,Redis

消息队列分为两种
生产者/消费者模式:Producer/Consumer
发布者/订阅者模式:Publisher/Subscriber
生产者/消费者模式
生产者消费者模式下,多个消费者同时监听一个频道(redis用队列实现),但是生产者产生的一个消息只能被最先抢到消息的一个消费者消费一次,队列中的消息由可以多个生产者写入,也可以有不同的消费者取出进行消费处理,此模式应用广泛


思来想去,只有 List 和 Streams 两种数据类型,可以实现消息队列的这些需求,当然,Redis 还提供了发布、订阅(pub/sub) 模式。
List 实现消息队列
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
所以常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理。
挑几个弹入、弹出的命令就可以组合出很多姿势
LPUSH、RPOP 左进右出
RPUSH、LPOP 右进左出

案例:
bash
# 生产者生成消息
[root@localhost ~]# redis-cli
127.0.0.1:6379> LPUSH haizeiwang jishu1
(integer) 1
127.0.0.1:6379> LPUSH haizeiwang jishu2
(integer) 2
127.0.0.1:6379> LPUSH haizeiwang jishu3
(integer) 3
127.0.0.1:6379> LPUSH haizeiwang jishu4
(integer) 4
127.0.0.1:6379> LPUSH haizeiwang jishu5
(integer) 5
# 获取所有消息
127.0.0.1:6379> LRANGE haizeiwang 0-1
1) "jishu5"
2) "jishu4"
3) "jishu3"
4) "jishu2"
5) "jishu1"
# 消费者消费消息
127.0.0.1:6379> RPOP haizeiwang #基于实现消息队列的先进先出原则,从管道的右侧
消费
"jishu1"
127.0.0.1:6379> RPOP haizeiwang
"jishu2"
127.0.0.1:6379> RPOP haizeiwang
"jishu3"
127.0.0.1:6379> RPOP haizeiwang
"jishu4"
127.0.0.1:6379> RPOP haizeiwang
"jishu5"
127.0.0.1:6379> RPOP haizeiwang
(nil)
# 验证队列消息消费全部消费完成
127.0.0.1:6379> LRANGE haizeiwang 0-1
(empty list or set)
即时消费问题
通过 LPUSH,RPOP 这样的方式,会存在一个性能风险点,就是消费者如果想要及时的处理数据,就要在程序中写个类似 while(true) 这样的逻辑,不停的去调用 RPOP 或 LPOP 命令,这就会给消费者程序带来些不必要的性能损失。
所以,Redis 还提供了 BLPOP、BRPOP 这种阻塞式读取的命令(带 B-Bloking的都是阻塞式),客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据。这种方式就节省了不必要的 CPU 开销。
LPUSH、BRPOP 左进右阻塞出
RPUSH、BLPOP 右进左阻塞出
bash
# 生产者生成消息
127.0.0.1:6379> LPUSH haizeiwang jishu1 jishu2 jishu3 jishu4 jishu5
(integer) 5
# 获取所有消息
127.0.0.1:6379> LRANGE haizeiwang 0-1
1) "jishu5"
2) "jishu4"
3) "jishu3"
4) "jishu2"
5) "jishu1"
# 消费者消费消息
127.0.0.1:6379> BRPOP haizeiwang 10
1) "haizeiwang"
2) "jishu1"
127.0.0.1:6379> BRPOP haizeiwang 10
1) "haizeiwang"
2) "jishu2"
127.0.0.1:6379> BRPOP haizeiwang 10
1) "haizeiwang"
2) "jishu3"
127.0.0.1:6379> BRPOP haizeiwang 10
1) "haizeiwang"
2) "jishu4"
127.0.0.1:6379> BRPOP haizeiwang 10
1) "haizeiwang"
2) "jishu5"
# 消费的时候已经没有消息了,10秒内再开一个窗口使用命令LPUSH haizeiwang jishu6产生新消息
127.0.0.1:6379> BRPOP haizeiwang 10#如果将超时时间设置为 0 时,即可无限等待,直
到弹出消息
1) "haizeiwang"
2) "jishu6"
(2.73s)
127.0.0.1:6379>
发布者/订阅者模式
在发布者订阅者Publisher/Subscriber模式下,发布者Publisher将消息发布到指定的频道channel,事先监听此channel的一个或多个订阅者Subscriber都会收到相同的消息。即一个消息可以由多个订阅者获取到,对于社交应用中的群聊、群发、群公告等场景适用于此模式

案例:
bash
# 订阅者订阅频道
#窗口A:
[root@localhost ~]# redis-cli
127.0.0.1:6379> SUBSCRIBE douluodalu #订阅者事先订阅指定的频道,之后
发布的消息才能收到
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "douluodalu"
3) (integer) 1
#窗口B:
127.0.0.1:6379> SUBSCRIBE douluodalu haizeiwang #订阅多个频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "douluodalu"
3) (integer) 1
1) "subscribe"
2) "haizeiwang"
3) (integer) 2
# 发布者发布消息
#窗口C:
127.0.0.1:6379> PUBLISH douluodalu fuhuoba,wodeairen
(integer) 2#订阅者个数2个
127.0.0.1:6379> PUBLISH haizeiwang 5danglufei
(integer) 1
# 各个订阅者都能收到消息
#窗口A:
[root@localhost ~]# redis-cli
127.0.0.1:6379> SUBSCRIBE douluodalu
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "douluodalu"
3) (integer) 1
1) "message"
2) "douluodalu"
3) "fuhuoba,wodeairen"
#窗口B
[root@localhost ~]# redis-cli
127.0.0.1:6379> SUBSCRIBE douluodalu haizeiwang
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "douluodalu"
3) (integer) 1
1) "subscribe"
2) "haizeiwang"
3) (integer) 2
1) "message"
2) "douluodalu"
3) "fuhuoba,wodeairen"
1) "message"
2) "haizeiwang"
3) "5danglufei"
# 订阅所有频道
127.0.0.1:6379> PSUBSCRIBE *
# 订阅匹配的频道
127.0.0.1:6379> PSUBSCRIBE douluo*
shell脚本访问Redis
脚本内容:write_redis.sh
#!/bin/bash
bash
# Redis 连接参数(可根据需要修改)
REDIS_HOST="127.0.0.1"
REDIS_PORT=6379
REDIS_DB=0
# 写入100个键值对
for i in {0..99}; do
KEY="key:$i"
VALUE="$i"
redis-cli -h"$REDIS_HOST"-p"$REDIS_PORT"-n"$REDIS_DB" SET "$KEY"
"$VALUE"
done
echo"已成功写入100条数据到 Redis。"
给脚本添加执行权限:
root@localhost \~# chmod +x write_redis.sh
运行脚本
root@localhost \~# ./write_redis.sh
bash
OK
......
OK
已成功写入100条数据到 Redis。
[root@localhost ~]#
#验证结果
127.0.0.1:6379> info keyspace
# Keyspace
db0:keys=100,expires=0,avg_ttl=0
127.0.0.1:6379> keys key:*
💡可选增强功能:
带密码认证:如果 Redis 设置了密码,加上-a your_password (注意安全性)或使用--
bash
askpass 。
批量管道操作(更快):如需更高性能,可使用redis-cli --pipe批量导入(适合大量数
据)。
图形工具连接Redis
Redis Desktop Manager又名RDM,它是一款用于Windows,Linux和MacOS的快速开源Redis数据库管理应用程序,能够为用户提供一系列功能选择以及操作设定,以便于用户直接对需要管理的Redis数据库进行建设性操作,以树形的方式来罗列出密匙以及CRUD密钥,可节约用户的很多宝贵时间,此工具支持识别shell命令,管理员能够根据自己的需要添加shel,以此让程序系统执行对应的命令操作;它为用户提供中文显示界面,同时还提供了通俗易懂的用户界面,无论是新手用户还可以经验十足的用户都可以非常轻松的上手。
Github地址:
https://github.com/qishibo/AnotherRedisDesktopManager



需要提前在redis服务器上配置redis密码,和关闭防火墙,更改bind地址root@localhost \~# systemctl stop firewalld
root@localhost \~# vim /etc/redis.conf
bash
69 bind 0.0.0.0
[root@localhost ~]# systemctl restart redis
127.0.0.1:6379> CONFIG SET requirepass 123456
OK


程序连接Redis
Redis支持多种开发语言访问
https://redis.io/docs/latest/develop/clients/

基本语句(python)
python提供了多种开发库,都可以支持连接访问Redis
下面选择使用redis-py库连接redis
bash
# redis-py 使用手册
https://redis.io/docs/latest/develop/clients/redis-py/
pycharm连接redis
bash
pip install redis
import redis
r = redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
print(r)
解释:
bash
import redis
导入redis模块,这是 Python 操作 Redis 的官方客户端库(需提前安装:pip install
bash
redis )。
r = redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
创建一个 Redis 客户端对象r ,用于与远程 Redis 服务器通信:
host: Redis 服务器 IP 地址(这里是局域网中的192.168.108.172 )
port: Redis 默认端口6379
password: 认证密码'123456' (说明 Redis 配置了requirepass 123456 )
db: 使用第0号数据库(Redis 默认有 16 个逻辑数据库,编号 0~15)
print®
打印 Redis 客户端对象的描述信息,这只是对象的内部表示,用于调试,确认连接配置是否正确。


接收 set 操作的返回值
bash
importredis
r=redis.Redis(host='192.168.108.172', port=6379, password='123456', db=0)
print(r)
# 接收 set 操作的返回值
result=r.set('color1', 'red')
print(result) # 输出 True(或 'OK',取决于 redis-py 版本)
注意文件不要为redis,会和redis模块名称冲突
解释:
bash
result = r.set('color1', 'red')
调用set() 方法,向 Redis 中设置一个字符串类型的键值对:
键(key):'color1'
值(value):'red'
这相当于在 Redis CLI 中执行:SET color1 red
print(result)
r.set()的返回值说明:
| redis-py 版本 | r.set(...) 成功时的返回值 |
|---|---|
| 4.0.0 及以上 | True (布尔值)✅(当前主流版本) |
| 3.x 及更早 | b'OK' (字节串) |
自redis-py 4.0起,为了更符合 Python 习惯,成功操作统一返回True ,失败则抛出异常(如连接错误、认证失败等)。

设置和获取值
可以使用set和get方法来存储和检索数据
bash
#存储变量
r.set('color1','red')
#获取变量值
value = r.get('color1')
print(value)

使用字符串操作
redis-py提供了多种字符串操作方法,如incr(增加),decr(减少),append(追加)等。
r.set('int1',10)
bash
#自增
restult=r.incr('int1')
#自减
restult=r.decr('int1')
print(restult)


使用列表操作
Redis的列表是一个简单的字符串列表,可以进行lpush(从左边插入)、rpush(从右边插入)、lpop(从左边弹出)、rpop(从右边弹出)等操作。
bash
#列表
r.lpush('mylist','nihao')
r.lpush('mylist','laogao')
print(r.lrange('mylist',0,-1))
注释:
r.lpush('mylist','nihao')
使用 LPUSH 命令将字符串 'nihao' 从左侧(头部)推入名为 mylist 的列表。如果 mylist 不存在,Redis 会自动创建它。
执行后,mylist 内容为:'nihao'
r.lpush('mylist','laogao')
再次使用 LPUSH,将 'laogao' 插入到列表最左边。
列表是"头进",所以新元素在前。
此时 mylist 内容变为:'laogao', 'nihao'
print(r.lrange('mylist',0,-1))
使用 LRANGE 命令获取列表 mylist 中从索引 0 到 -1(即全部元素)的内容。
在 Redis 中,-1 表示最后一个元素,0 是第一个。
r.lrange(...) 返回的是字节串(bytes)组成的列表(因为 Redis 存储的是二进制安全的字符串)。
💡小知识:Redis 列表是"左进右出"还是"右进左出"?
LPUSH :从左边 插入→新元素在头部
RPUSH :从右边 插入→新元素在尾部
列表索引:0是最左边(最新插入的 LPUSH 元素),-1是最右边(最早插入的)

b'laogao', b'nihao'注意:每个字符串前面有 b'...',表示这是 bytes 类型,不是普通字符串(str)。
使用哈希表操作
Redis的哈希表是一个字符串字段和字符串值之间的映射表,可以进行hset(设置字段)、hget(获取字段)、hgetall(获取所有字段和值)等操作。
bash
#哈希
r.hset('student','name','lisi')
r.hset('student','age','18')
print(r.hget('student','name'))
print(r.hget('student','age'))
print(r.hgetall('student'))
r.hset('student','name','lisi')
在名为'student'的**哈希表(Hash)**中,设置字段(field)'name'的值为'lisi' 。
相当于执行 Redis 命令:HSET student name lisi
r.hset('student','age','18')
在同一个哈希表'student'中,再设置字段'age'的值为'18' 。
注意:Redis 中所有值都是字符串,即使看起来像数字(如'18' ),存储时也是字符串类型。
print(r.hget('student','name'))
获取哈希表'student'中字段'name'的值。
返回值是bytes 类型(因为 redis-py 默认返回字节)。
输出:b'lisi'
print(r.hget('student','age'))
获取'age'字段的值。
输出:b'18'
print(r.hgetall('student'))
获取'student'哈希表中所有字段和值。
返回一个字典(dict),但键和值都是 bytes 类型。
