Redis 分布式事务实现
开始本文之前,我们先来看什么是分布式事务。分布式事务是什么?
题外话
如需转载文章,请保留文章出处(blog.csdn.net/knight_zhou)。因为我的很多文章一般是会进行更新的。也避免百度搜出来一大推相似的文章,却找不到原创博主。
本文主题
我们要实现分布式事务,而我们目前已经有的中间件是Reis和Kafka,因为Kafka不支持分布式事务。所以我们想借助Redis去实现。而实现的思路是使用
Redis键通知功能 notify-keyspace-events 去实现的。
分布式事务是什么?
开始本文之前,我们先来看什么是分布式事务。在讲分布式事务之前,我们先来看看什么是程序的本地事务。因为我们的业务技术栈主要是Java微服务,并且采用的都是Spring Boot的微服务。我们知道Spring Boot 微服务里面有个注解是 @EnableTransactionManagement ,其实这个就是本地事务。因为不同的微服务去维护各自的事务。但是这样就不是分布式事务了。
而分布式事务就不同,比如有5个微服务。要么5个微服务的一类操作要么全部执行成功要么全部失败。所以对于整个业务的微服务来讲,这就是分布式事务了,所以这也就需要分布式事务去实现了。
Redis怎么去实现分布式事务?
解题思路分析:
比如我们有5个微服务,每个微服务做完这一类操作之后就更新一下Redis的字符串key。(这就有点类似我们去哪里游玩,比如我们去黄山玩,有些人就喜欢打卡,然后提上自己的名字, xxx 到此一游,表示你已经来过这里)当然这个字符串的key是一个固定前缀开头的。当某一个微服务,长时间比如1个小时都没有更新key的话,那么就认定这个微服务超时,也就是失败了。
所以我们需要对Redis的特定的key进行监听,比如我们设置Redis的key的超时时间是2个小时,也就是5个微服务同时执行完这一类操作的时间是2个小时,我们只需要Redis告诉我,key失效的时候能通知我就行了。
当然这个时候你会想,为什么要等Redis主动通知我了?我自己不能去轮询Redis去看是否已经失效了吗?当然这种方式是可以,但是这种方式就比较傻,而且很耗机器性能。所以就像websocket一样,主动推送才是最科学的方式。
聪明的你可能有会这样提出,既然微服务不想去设置轮询,那么不是可以这样做: 首先我们程序设置了Redis的key的失效时间,失效时间程序是知道的,比如假定我们的失效时间是5分钟,那么我们5分钟之后就查就可以了,并且每个微服务做完这一类操作
之后就会更新Redis的key,那么程序只需要在之前我们设定的时间去查一次就可以了,去查那个key的值是不是等于最后一个微服务修改的值就可以了。
关于Redis的事件通知
要实现Redis key的失效事件通知,我们可以使用 notify-keyspace-events 去实现。我们先看看这个配置有哪些参数,具体是什么含义。我们先来看看官方文档:
官方文档: Redis keyspace notifications | Redis
中文翻译文档: 键空间通知(keyspace notification) — Redis 命令参考
IMPORTANT Keyspace notifications is a feature available since 2.8.0
键空间通知功能是 2.8.0以来的一个特性
默认情况下,keyspace事件通知是禁用的,因为这个功能虽然不太合理,但会消耗一些CPU能量。通知可以使用 redis.conf 的 notify-keyspace-events 或通过配置进行启用。
字符 |
发送的通知 |
---|---|
|
键空间通知,所有通知以 |
|
键事件通知,所有通知以 |
|
|
|
字符串命令的通知 |
|
列表命令的通知 |
|
集合命令的通知 |
|
哈希命令的通知 |
|
有序集合命令的通知 |
|
过期事件:每当有过期键被删除时发送 |
|
驱逐(evict)事件:每当有键因为 |
m | 键丢失事件: 访问不存在的键时生成的事件 |
|
参数 |
输入的参数中至少要有一个 K
或者 E
, 否则的话, 不管其余的参数是什么, 都不会有任何通知被分发。
如:
- notify-keyspace-events "Ex" 表示对过期事件进行通知发送;
键空间通知和键事件通知有什么区别了?
- 键空间通知:“某个键执行了什么命令”的通知称为键空间通知(key-space notification)
- 键事件通知:键事件通知(key-event notification)关注的是“某个命令被什么键执行了”。
过期事件测试
首先我们先开启过期事件通知,命令如下:
[www@me03-common ~]$ redis-cli -p 6305
127.0.0.1:6305> auth xx
OK
127.0.0.1:6305> config get notify-keyspace-events
1) "notify-keyspace-events"
2) ""
127.0.0.1:6305> config set notify-keyspace-events Ex
OK
127.0.0.1:6305> config get notify-keyspace-events
1) "notify-keyspace-events"
2) "xE"
127.0.0.1:6305>
然后我们再开一个客户端 B 进行订阅如下:
[www@me03-common ~]$ redis-cli -p 6305
127.0.0.1:6305> auth zxx
OK
127.0.0.1:6305>
然后我们执行set一个key 并设置失效事件为10s试一试。
127.0.0.1:6305> setex name 10 tom
OK
127.0.0.1:6305>
然后客户端B 进行检查如下:
127.0.0.1:6305> subscribe __keyevent@0__:expired
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "__keyevent@0__:expired"
3) (integer) 1
1) "message"
2) "__keyevent@0__:expired"
3) "name"
到此成功得到了事件通知。
Python代码实现
首先定义一个RedisHelper类,连接Redis,定义相应的频道,定义发布(publish)及订阅(subscribe)方法。文件名为: RedisHelper.py
import redis
# 定义监听的事件
key_channel = "__keyevent@0__:expired"
class RedisHelper(object):
def __init__(self):
self.__conn = redis.Redis(host='yy.cn',port=6305,password="zhoulong")#连接Redis
self.channel = '__keyevent@0__:expired' #定义名称
def publish(self,msg): #定义发布方法
self.__conn.publish(self.channel,msg)
return True
def subscribe(self):#定义订阅方法
pub = self.__conn.pubsub()
pub.subscribe(self.channel)
pub.parse_response()
return pub
新增订阅的文件 diingyue.py:
from RedisHelper import RedisHelper
obj = RedisHelper()
redis_sub = obj.subscribe() # 调用订阅方法
while True:
msg = redis_sub.parse_response()
print(msg)
测试结果如下:
127.0.0.1:6305> setex name 10 tom
OK
127.0.0.1:6305>
查看Python代码的返回:
更多推荐
所有评论(0)