Redis 网络层

首先我们来了解串行、并发与并行的区别;

一个队列对应一个处理器是串行;

多个队列对应一个处理器是并发(交叉执行);

多个队列对应多个处理器是并行;

如有n个队列和n个处理器,但他们是交换执行的,虽然也是一对一,但因为处理器与队列的对应关系不断切换,所以也属于是并发(多个并发)

线程池 redis队列 redis队列支持多线程处理吗_redis


了解完串行、并发与并行之后,再来看Redis;

Redis是单线程reactor模型;

对于所有连接的数据处理,Redis并发执行;

对于单条连接的数据处理,Redis串行执行;

线程池 redis队列 redis队列支持多线程处理吗_redis_02

Redis 事务

MULTI 开启事务,事务执行过程中,单个命令是入队操作,直到调用EXEC才会一起执行

MULTI

开启事务
相当于mysql中的begin/start transaction

EXEC

提交事务
相当于mysql中的commit

DISCARD

取消事务
相当于mysql的rollback

WATCH

检测key的变化,若在事务执行中,key变动则取消事务;
在事务开启前调用,由乐观锁实现(cas);若被取消则事务返回nil;

分析

redis自带的事务命令,是队列控制的。每次执行完一条命令,就是入队。只有在提交(exec)事务后,统一按顺序进行执行。出现错误后redis不会自动回滚,DISCARD是一个手动的回滚命令。

Lua 脚本

Lua脚本来实现原子性。
Redis中加载了一个lua虚拟机,用来执行Redis lua脚本,redis lua脚本的执行是原子性的,当某个脚本正在执行的时候,不会有其他的命令或者脚本被执行。lua脚本当中有命令的会直接修改数据状态。
注意:如果项目中使用了lua脚本,不需要上述的事务命令

使用步骤:

1、SCRIPT LOAD script

 script即lua脚本,这么做是将lua脚本放到redis服务器中,返回的是一个sha1校验码。

2、EVALSHA sha1 numkeys key [key …] arg [arg …]

 用evalsha调用对应的lua脚本。

线程池 redis队列 redis队列支持多线程处理吗_redis_03


lua应用

1: 项目启动时,建立redis连接并验证后,先加载所有项目中使用的lua脚本(script load);
2: 项目中若需要热更新,通过redis-cli script flush;然后可以通过订阅发布功能通知所有服
务器重新加载lua脚本;
3:若项目中lua脚本发生阻塞,可通过script kill暂停当前阻塞脚本的执行;

ACID特性分析

A 原子性

 事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败;
 redis自带的事务命令不支持回滚;即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。若使用lua脚本可以对错误的返回值进行分析,然后我们手动做回滚操作;

C 一致性

 事务使数据库从一个一致性状态到另外一个一致性状态;
 这里的一致性是指预期的一致性而不是异常后的一致性;所以redis也不满足;这个争议很大:redis 能确保事务执行前后的数据的完整约束;但是并不满足传统意义上的一致性;比如转账功能,一个扣钱一个加钱;可能出现扣钱执行错误(服务器宕机),加钱执行正确,那么最终还是会加钱成功;系统凭空多了钱;

I 隔离性

事务的操作不被其他用户操作所打断;redis 是单线程执行,天然具备隔离性;

D 持久性

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

Redis 发布/订阅

为了支持消息的多播机制,redis 引入了发布订阅模块;
但消息不一定可达,要确保消息可达,可以使用分布式消息队列的方式。

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

应用

发布订阅功能一般要区别命令连接重新开启一个连接;因为命令连接严格遵循请求回应模式;而pubsub能收到redis主动推送的内容;所以实际项目中如果支持pubsub的话,需要另开一条连接用于处理发布订阅;

线程池 redis队列 redis队列支持多线程处理吗_数据库_04

缺点

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