第十九章:事务
事务的实现:
1. 事务开始。MULTI命令将客户端从非事务状态转为事务状态。
2. 命令入队。除了EXEC、DISCARD、WATCH、MULTI,将命令放入一个先进先出的队列里,返回QUEUED回复。
3. 事务执行。有EXEC命令提交事务,并让服务器执行。
typedef struct redisClient {
multiState mstate; // 事务状态
...
}
typedef struct multiState {
multiCmd *commands; // 事务队列
int count; // 已入队命令数
}
typedef struct multiCmd {
robj **argv; // 参数
int argc; // 参数数量
struct redisCommand *cmd; // 命令指针
}
事务执行期间,服务器是阻塞的,执行完毕后才会响应其他客户端的请求。
WATCH命令:一个乐观锁,可在执行EXEC命令之前,监视数据库键。如果执行EXEC命令时发现有些键被修改了,则拒绝执行事务。
当执行对数据库进行修改的命令后,都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查。如果有客户端在监视这个键,那么会打开客户端的REDIS_DIRTY_CAS标识,标识该客户端的事务安全性已破坏。
typedef struct redisDb {
dict *watched_keys; // 键是一个数据库键,值是一个链表,包括所有监视这个数据库键的客户端
...
}
事务的ACID性质:
- Atomicity 原子性。保证原子性。其与传统关系型数据库事务的区别在于,不支持事务回滚机制。即,如果事务队列中某个命令在执行期间出错,事务也会继续执行。
- Consistency 一致性。无论运行在哪种持久化模式下(空、RDB、AOF),都能保证宕机后的一致性。
- Isolation 隔离性。Redis以单线程方式执行事务,并且都是串行执行的,保证隔离型。
- Durability 耐久性。仅当Redis使用AOF持久化模式且appendfsync为always时(总会在执行完命令后将数据保存到硬盘),具有耐久性。值得一提的是,如果开启了no-appendfsync-on-rewrite,那么在执行BGSAVE命令或BGREWRITEAOF命令期间会暂停AOF文件的同步,也不能保证耐久性。无论什么持久化模式,在事务最后加一个SAVE命令可以保证耐久性,但效率太低,不推荐使用。
第二十章:Lua脚本
待学习。
第二十一章:排序
SORT命令可以对列表、集合、有序集合进行排序,底层使用快速排序算法。
SORT命令默认被排序键为数字值,ALPHA选项使其认为被排序键为字符串值。BY选项使其用权重进行排序。GET选项可使其返回特定结果。STORE选项将排序结果保存到指定键里。
除了GET命令,其他选项命令可以乱序。
SORT<key> ALPHA DESC BY <by-pattern> LIMIT <offset> <count> GET <get-pattern> STORE <sotre_key>
typedef struct _redisSortObject {
robj *obj; // 被排序键的值
union {
double score; // 排序数字值时使用
robj *cmpobj; // 排序带有BY选项的字符串值时使用
}
}
第二十二章:二进制位数组
待学习。
第二十三章:慢查询日志
该功能用于记录执行时间超过指定时长的命令请求,用户可通过日志来监视、优化查询。
slowlog-log-slower-than:执行时间超过多少微秒,会被记录。
slowlog-max-len:服务器最多保存多少条慢查询日志。
struct redisServer {
long long slowlog_entry_id; // 下一条慢查询日志的id
list *slowlog; // 所有慢查询日志的链表,每个结点为slowlogEntry
long long slowlog_log_slower_than; // 配置项
unsigned long slowlog_max_len; // 配置项
...
}
typedef struct slowlogEntry {
long long id; // id
time_t time; // 命令开始执行的时间,格式为UNIX时间戳
long long duration; // 命令消耗的时间,单位为微秒
robj **argv; // 命令与命令参数
int argc; // 命令与命令参数的数量
}
第二十四章:监视器
通过MONITOR命令,客户端可以将自己变为一个监视器,实时接收并打印出服务器当前处理的命令信息。
当一个客户端向服务器发送命令时,服务器除了会处理命令外,还会将命令的信息发送至所有监视器。
// MONITOR命令的实现
def MONITOR():
client.flags |= REDIS_MONITOR // 打开监视器标识
server.monitors.append(client) // 将客户端添加到服务器状态的监视器列表末尾
send_reply("OK") // 向客户端返回OK
// 向监视器发送命令的实现
def replicationFeedMonitors(client, monitors, dbid, argv, argc):
msg = create_message(client, dbid, argv, argc) // 创建消息
for monitor in monitors: // 遍历所有监视器
send_message(monitor, msg) // 发送消息给监视器