读书笔记-《Redis设计与实现》-第四部分:独立功能的实现

第十九章:事务

事务的实现

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以单线程方式执行事务,并且都是串行执行的,保证隔离型。

扫描二维码关注公众号,回复: 8930744 查看本文章

- 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)                  // 发送消息给监视器
发布了25 篇原创文章 · 获赞 12 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_25498677/article/details/87027329
今日推荐