Redis事务与异步方式

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis事务与异步方式

redis pipeline

redis pipeline 是一个redis-cli提供的机制,而不是redis-server提供的;

目的:节约网络传输时间;

Redis通过网络传输请求通常由同步和异步两种方式:

同步:发一条请求,等待回复,再发一条请求,等待回复……

异步:一次性发送N条请求,然后等待回复。

前者能保证发送和回复的顺序性,后者则能保证高效率地发送。

redis pipeline属于异步网络传输。

Redis的发布-订阅模式

举例:当有三个服务器连接了一个redis,当有一条新的message进入了redis,这三个服务器都想能马上了解怎么办呢?

根据redis的监听-发布者订阅模式,需要这么操作:

  1. 建立一个channel。
  2. 三个服务器都去监听这个channel。
  3. 如果有一条新的message想迅速地被三个服务器知道,那么它往这这个channel发布message。
  4. 当然,message也能是其中一个server发布的,通过监听-发布者模式也能让三个server都迅速获message。

相关代码:

# 订阅频道
subscribe 频道
# 取消订阅频道
unsubscribe 频道
# 发布具体频道或模式频道的内容
publish 频道 内容
# 客户端收到具体频道内容
message 具体频道 内容

(右上角是发布者,其余是监听者。)

# 订阅模式频道
psubscribe 频道
# 取消订阅模式频道
punsubscribe 频道
# 发布具体频道或模式频道的内容
publish 频道 内容
# 客户端收到模式频道内容
pmessage 模式频道 具体频道 内容

一个redis-cli可以与数据库建立多条连接。

发布订阅功能一般要给同一个redis-cli开两个连接,一个负责监听,一个负责日常发命令;因为命令连接严格遵循请求回应模式;而 pubsub 能收到 redis 主动推送的内容。

所以实际项目中如果支持 pubsub 的话,需要另开一条连接用于处理发布订阅。

注意:发布订阅的生产者传递过来一个消息,redis 会直接找到相应的消费者并传递过去;假如没有消费者,消息直接丢弃;假如开始有2个消费者,一个消费者突然挂掉了,另外一个消费者依然能收到消息,但是如果刚挂掉的消费者重新连上后,在断开连接期间的消息对于该消费者来说彻底丢失了;另外,redis 停机重启,public和 subscribe 的消息是不会持久化的,所有的消息被直接丢弃;

所以我们只能在要求不确保消息到达的时候使用pub/sub模式。如果想确保消息一定能到达,需要使用其他模式,比如kafka,stream。

Redis事务

如果redis-server几乎同时收到了来在redis-cliA的3条操作指令,收到了redis-cliB的5条操作指令。因为redis-server处理命令的时候是单线程的,一次只能执行一条命令(具备原子性),有可能把A的3条命令和B的5条命令穿插着处理。如果有要求A和B的命令不能分割处理,要么先处理完A的再处理B的,要么先处理完B的再处理A的该怎么办呢?

这时候需要把A的命令和B的命令再发送前打包成【事务】。

事务:用户定义一系列数据库操作,这些操作视为一个完整的 逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。如果只有一个redis-cli连接redis-server,那么不用考虑事务。

Rredis事务的操作命令(了解即可,实务几乎不用):

MULTI:开启事务

EXEC:提交事务

DISCARD:取消事务

WATCH:检测 key

逻辑图:

如果MULTI之前先WATCH了某个key,这个key在EXEC之前发生了值变化,那么EXEC会清空事件队列。如果MULTI和EXEC中间pop了DISCARD命令,那么EXEC会清空事件队列。

然而,我们一般使用lua脚本来执行redis事务。

Redis-cli发送一串lua脚本给redis-server,然后redis-server用内置的lua虚拟机执行接收到的lua脚本。

# 测试使用
EVAL script numkeys key [key ...] arg [arg ...]
# 线上使用
EVALSHA sha1 numkeys key [key ...] arg [arg ...]

key [key ...]是一个数字,表示script里用到的redis key的数量,arg [arg ...]则表示redis key的名字。

Sha怎么产生?用SCRIPT命令把命令注册到redis-server中

该方法有两个优点:1、用短短的字符串代替复杂脚本。2、只需要编译注册一次,能节省资源。

redis事务的ACID特性分析

redis满足A与I,不满足C与D。

A原子性;redis事务是一个不可分割的工作单位,事务中的操作要么全部执行,要么事前检测出事务中有错误的、不可执行的部分全部不执行;redis事务的原子性体现在此处。但是redis 不支持回滚;如果redis事务事前没检测出错误,事务正常执行,然而事务队列中的某个命令在执行期间出现了错误(比如有可能是因为内存不足的原因),整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止,这时候就会没有严格的原子性了,会出现一部分命令成功,一部分命令执行失败的情况,需要我们人工回滚。

I 隔离性;各个事务之间互不影响;redis 是单线程执行,天然具备隔离性;

C 一致性;redis 不能确保事务执行前后的数据的完整约束,也就是说数据状态(数据的取值或内容)会有事务内部操作只成功了部分,导致事务结束之后,数值的变化和事前预期不一致的情况。而且并不满足业务功能上的一致性(一致性的满足要么数据全部成功,要么出现失败然后全部回滚);比如转账功能,一个扣钱一个加钱;可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功;系统凭空多了钱;

D持久性;redis 只有在 aof 持久化策略的时候,并且需要在 redis.conf 中appendfsync=always 才具备持久性;实际项 目中几乎不会使用 aof 持久化策略;

Redis异步连接

同步连接:等待redis返回了命令执行后的报文再继续发送下一条命令。

异步连接:不等待redis返回命令执行后的报文,照样继续发送后续的报文。

异步连接的速度远高于同步连接的速度,甚至达到了数十倍,缺点是可能会造成业务逻辑的割裂。

如何实现异步连接了?

1、另起线程。

2、使用reactor模型。可以使用开源框架,hiredis(hi,redis)制作客户端。

3、使用proactor模型。

本文介绍一下使用基于hiredis建立能与redis通信reactor服务器的逻辑。

技术拆解:

1、与redis建立连接

       a、创建socket,设置fd为非阻塞。

       b、connet。

       c、fd注册到epoll当中,绑定写事件。

       d、如果连接建立成功,写事件会进行响应,然后注销写事件,注册读事件。

2、向redis发送数据

       a、int n = write(fd,buf,size),根据redis协议加密数据包;如果n<size,说明对应的发送缓冲区已满。

       b、注册写事件,如果写事件触发,继续发送数据,如果全部发送,注销写事件。通常来说客户端不需要通过epoll发现写事件,就能直接发送数据。但是异步发送数据速度非常快,可能会因为缓冲区的限制造成无法发送数据,这时候需要用epoll检测写事件的触发然后再行发送。

       c、注册读事件。

3、读取redis 的返回

       a、读事件触发

       b、根据redis协议分割数据包

其中最关键的是,我们大多是时候不希望自己解析redis协议,那么就需要需要做的是把hiredis的适配器的关键接口实现。

若需要相关的demo可私信联系。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
缓存 NoSQL Redis
Redis 事务
10月更文挑战第18天
26 1
|
3月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
4月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
21天前
|
设计模式 NoSQL Go
Redis 实现高效任务队列:异步队列与延迟队列详解
本文介绍了如何使用 Redis 实现异步队列和延迟队列。通过 Go 语言的 `github.com/go-redis/redis` 客户端,详细讲解了 Redis 客户端的初始化、异步队列的实现和测试、以及延迟队列的实现和测试。文章从基础连接开始,逐步构建了完整的队列系统,帮助读者更好地理解和应用这些概念,提升系统的响应速度和性能。
38 6
|
2月前
|
SQL 分布式计算 NoSQL
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
25 2
|
2月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
281 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
|
4月前
|
NoSQL 关系型数据库 Redis
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
这篇文章深入探讨了Redis事务的概念、命令使用、错误处理机制以及乐观锁和悲观锁的应用,并通过WATCH/UNWATCH命令展示了事务中的锁机制。
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
|
3月前
|
监控 NoSQL 关系型数据库
9)Redis 居然也有事务
9)Redis 居然也有事务
34 0
|
5月前
|
监控 NoSQL Redis
Redis事务和Redis管道
Redis事务和Redis管道
62 0
|
5月前
|
安全 NoSQL Java
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R
网络安全-----Redis12的Java客户端----客户端对比12,Jedis介绍,使用简单安全性不足,lettuce(官方默认)是基于Netty,支持同步,异步和响应式,并且线程是安全的,支持R