redis缓存命令处理实现原理

Redis服务器负责与多个客户端建立连接,处理客户端请求,保存各个数据库状态。使用由I/O多路复用技术实现的事件处理器,Redis服务器采用单线程单进程处理客户端命令请求。Redis通过redisServer结构体来记录服务端的各种状态。

命令请求执行过程

1、客户端发送命令请求,客户端将命令请求转换成协议格式。

2、服务端读取命令请求,将命令请求缓存在客户端输入缓冲区中,对输入缓冲区中的命令进行分析把参数和参数个数分别保存到客户端状态的argv属性和argc属性中,然后调用命令执行器执行指定的命令。

3、命令执行器根据argv[0]参数在命令表中查找参数所指定的命令,并将找到的命令保存到客户端状态cmd属性中

4、执行预备操作:

检查客户端cmd指针是否指向NULL,如果是返回一个错误;

根据客户端cmd属性指向的redisCommand结构的arity属性,检查命令请求所给定的参数个数是否正确,如果参数个数不正确返回错误;

检查客户端是否通过了身份验证,未通过身份验证的客户端只能执行AUTH命令,如果未通过身份验证的客户端执行了除AUTH之外的其它命令,返回错误;

如果服务器打开了maxmemory开关功能,那么在执行命令前,先检查服务器的内存占用情况,并在有需要时进行内存回收,从而使得接下来的命令能够顺利执行;

如果服务器上一次执行BGSAVE命令时出错,并且服务器打开了stop-writes-on-bgsave-error功能,而且服务器将要执行的是一个写命令,那么服务器将拒绝执行这个命令,并向客户端返回一个错误;

当客户端当前正在用SUBSCRIBE命令订阅频道,或者正在用PSUBSCRIBE命令订阅模式,那么服务器只会执行 客户端发来的SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE四个命令,其它命令都会被拒绝;

如果服务器正在进行数据载入,那么客户端发送的命令必须带有1标识(比如INFO、SHUTDOWN、PUBLISH) 才会被服务器执行,其它命令都会被服务器拒绝;

如果服务器因为执行Lua脚本而超时并进入阻塞状态,那么服务器只会执行客户端发来的SHUTDOWN nosave命令和SCRIPT KILL命令,其它命令都会被服务器拒绝;

如果客户端正在执行事务,那么服务器只会执行客户端发来的EXEC、DISCARD、MULTI、WATCH四个命令,其它命令都会被放进事务队列中;

如果服务器打开了监视器功能,那么服务器会将要执行的命令和参数等信息发送给监视器。

当完成了以上预备操作之后,服务器就可以开始真正执行命令了。

5、调用命令的实现函数,redisCommand中有个proc属性,它是一个函数指针,通过调用它来执行最终的命令实现。

6、执行后续工作:

如果服务器开启了慢日志查询日志功能,那么慢查询日志模块会检查是否需要为刚刚执行完的命令请求添加一条新的慢查询日志;

根据执行命令所耗费的时长,更新被执行命令的redisCommand结构的milliseconds属性,并它的calls计数器值增1;

如果服务器开启了AOF持久化功能,那么AOF持久化模块会将刚刚执行的命令请求写入到AOF缓冲区里面;

如果有其它从服务器正在复制当前服务器,那么服务器将刚刚执行的命令传播给所有从服务器;

7、将命令回复发送给客户端,命令实现函数会将命令回复保存到客户端的输出缓冲区里面,并为客户端的套接字关联命令回复处理器,当客户端套接字变为可写状态时,服务器将会执行命令回复处理器,将保存在客户端缓冲区中的命令回复发送个客户端。当命令发送完毕后,回复处理器清空客户端输出缓冲区。

serverCron函数

服务器每个100毫秒执行一次serverCron函数,通常情况下,该函数是redis服务器唯一的定时任务,它的主要职责如下:

1、更新服务器时间缓存,redisServer中有unixtime和mstime两个属性,由于100毫秒才调用一次,所以这两个属性保存的时间都是不精确的,如果要获取精确的系统时间,必须执行系统调用获取。

2、更新LRU时钟,redisServer中的lruclock属性保存了服务器的LRU时钟,它也是个服务器时间缓存,当服务器要计算一个数据库键的空转时间时,通过服务器的lruclock减redisObject的lru属性获取。serverCron默认以每10秒一次的频率更新lruclock,所以它也是一个估算值。

3、更新服务器每秒执行命令数。

4、更新服务器内存峰值,记录在redisServer的stat_peak_memory属性中。

5、处理SIGTERM信号,在启动服务器时,Redis会为服务器进程的SIGTERM信号关联处理器sigtermHandler函数,这个信号处理器负责在服务器接到SIGTERM信号时,打开服务器状态的shutdown_asap标识,每次serverCron函数运行时,程序会对服务器状态的shutdown_asap属性进行检查,并根据属性的值决定是否关闭服务器,在关闭服务器前服务器会进行RDB持久化操作,这就是服务器拦截SIGTERM信号的原因。

6、管理客户端资源,serverCron函数每次执行都会调用clientsCron函数, clientsCron函数会对一定数量的客户端进行一下两个检查:

如果客户端与服务器之间连接已经超时(很长时间没有互动),那么程序释放这个客户端,关闭连接。

如果客户端在上一次执行命令请求之后,输入缓冲区的大小超过了一定的长度,那么程序会释放客户端当前的输入缓冲区,并重新创建一个默认大小的输入缓冲区,从而防止客户端的输入缓冲区耗费了过多的内存

7、管理数据库资源,调用databaseCron函数,对服务器中的一部分数据库进行检查,删除其中的过期键,并在有需要时对字典进行收缩操作。

8、执行被延迟的BGREWRITEAOF,服务器在执行BGSAVE期间,如果客户端向服务器请求了BGREWRITEAOF命令,那么服务器会将BGREWRITEAOF命令延迟到BGSAVE执行完毕之后执行,通过redisServer中的aof_rewrite_scheduled记录(值为1表示有BGREWRITEAOF命令被延迟了)。

9、检查持久化操作的运行状态,服务器通过redisServer的rdb_child_pid和aof_child_pid属性记录执行BGSAVE和BGREWRITEAOF命令的子进程id,这个两个属性也可用于检查当前是否有BGSAVE或BGREWRITEAOF命令正在执行,每次serverCron执行时都会检查者两个属性的值,只要有一个值不为-1,程序就会执行一次wait3函数,检查子进程是否有信号发来服务器:

如果有信号达到,表示新的RDB文件已经生成或者AOF文件重写已经完毕,服务器需要进行相应的后续操作,比如用新的RDB文件替换现有的RDB文件,或者用重写后的AOF文件替换现有的AOF文件

如果没有信号到达,那么表示持久化操作未完成,不做动作。

如果rdb_child_pid和aof_child_pid两个属性的值都为-1,那么表示服务器没有在进行持久化操作,这种情况下,程序执行三个检查:

查看是否有BGREWRITEAOF被延迟,如果有,执行一次新的BGREWRITEAOF。

查看自动保存条件是否满足,如果满足并且服务器没有执行其他持久化操作,那么服务器开始一次新的BGSAVE。

检查AOF重写条件是否满足,如果满足并且服务器没有执行其他的持久化操作,执行一次新的BGREWRITEAOF命令。

10、将AOF缓冲区中的内容写入AOF文件,如果开启了AOF持久化功能,并且AOF缓冲区还有待写入的数据,那么serverCron会调用相关的函数将AOF缓冲区中的内容写入到AOF文件中

11、关闭异步客户端,服务器会关闭那些输出缓冲区超出限制的客户端。

12、增加cronloops计数器的值,这个值记录了serverCron函数被执行了多少次,这个属性会用来“每执行N次serverCron函数就执行一次指定代码”的功能。

image.png

根据key路由到具体的redis实例上,查询返回

[redis 命令的调用过程]

(https://www.cnblogs.com/bush2582/p/9326745.html)

Redis 命令参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容