《Redis设计与实现》读书笔记(十九) ——Redis客户端创建关闭及客户端总结
(原创内容,转载请注明来源,谢谢)
一、客户端的创建于关闭
1、普通客户端连接
普通的客户端,通过connect命令连接上服务器后,会被redis将客户端的状态结构体加入到redisServer的链表属性clients的末尾。
下图表示c1比c2先连上的redis服务器 。
2、普通客户端关闭
客户端关闭有下述情况:
1)客户端进程退出,或被kill,或成为client kill的目标。
2)客户端发送不符合协议格式的请求,或客户端发送命令超出默认的1GB大小的请求,或服务器回复给客户端的内容超过输出缓冲区规定大小的内容。
3)用户设置空转时限而客户端达到此时限(该条件有例外,如客户端是主服务器、从服务器、客户端被阻塞、客户端正在发布订阅,就算超过时限也不会被关闭)。
服务器通过两种方式来先知客户端输出缓冲区的大小:
1)硬性限制
规定一个值,输出缓冲区超过这个值,立刻关闭该客户端。
2)软性限制
当超过这个值,但是还没超过硬性限制,会写入上述提及redis客户端结构体中obuf_soft_limit_reached_time属性,作为超过软性限制开始的时间,之后服务器会持续监控此客户端,如果超出规定的软性限制的时间,则关闭客户端;如果软性限制时间之前,客户端输出缓冲区内容减小到软性限制之前,则不关闭客户端,并且将obuf_soft_limit_reached_time的值清零。
使用client-output-buffer-limit可以为普通客户端、从服务器客户端、执行发布订阅客户端,设置硬性限制和软性限制。
格式是client-output-buffer-limit<class> <hard limit> <soft limit> <soft seconds>
其中class表示客户端的类型,包括normal、slave、pubsub。hard和soft的limit是设置大小,例如256mb、16mb等,如果是0的话表示不限制大小。
3、lua伪客户端
lua伪客户端不是存放在redisServer的clients链表中,而是单独有一个redisClient类型的属性lua_client,用于存放redis的lua伪客户端。该客户端创建后,不会关闭,直到服务器关闭才会关闭。
4、AOF伪客户端
服务器载入aof文件时,会创建aof伪客户端,并且载入完毕后关闭该客户端。
四、总结
1、redis服务器采用clients链表,保存客户端的信息,链表里面每个元素都是一个redisClient结构体。新连接的客户端会加到链表的最后。
2、redisClient中,flag属性记录客户端当前的状态,主要是区分客户端是否主从、发布订阅、阻塞非阻塞、强制AOF等。
3、客户端命令会被记录到redisClient的querybuf中,采用sds进行保存;记录完成后,redis会分析内容,并把参数存到argv数组,参数个数存到argc,其中argv[0]是命令,后续的是参数;分析完毕后,redis会查找保存在服务器中的命令表,通过argv[0]找到与其对应的redisCommand结构,并用指针cmd指向该结构。
3、redis服务器执行完命令后,会将内容存到输出缓冲区。redis给每个客户端都设置了固定大小缓冲区和可变大小缓冲区两种,固定大小缓冲区默认记录16KB的信息,通常用于记录短的回复,存于数组中,并另用一个字段记录当前使用的字节数。如果输出结果超过16KB,或者原先在固定大小中随着执行期超过了16KB,redis都将把结果存到可变大小缓冲区,该缓冲区根据实际大小,把每个结果存在一个字符串对象中,总的用一个链表串起来。
4、客户端中还会记录连接上服务器的时间、空转时间、超出软性限制大小的时间。
5、当主动或被迫关闭客户端、发送请求不符合格式、空转超时且不符合特殊条件(主、从、阻塞、发布订阅)、超出输出缓冲区硬性限制、输出缓冲区超出软性限制且超出规定时间等,都会造成客户端被关闭。其中硬性限制和软性限制以及软性限制的时间,都可以配置。
6、redis会创建一个伪客户端,专门用于处理Lua脚本,其存放在单独的一个属性中,不和普通客户端存在数组。且创建后,会保存在redis的整个生命周期,直到服务器关闭。
7、AOF伪客户端,是在载入aof的时候创建,载入完毕就关闭。
——written by linhxx 2017.09.08