连接的建立
Redis通过监控TCP端口或Unix套接字接收来自客户端的连接。建立连接后,Redis将执行以下操作:
首先,客户端套接字将被设置为非阻塞模式,因为Redis在网络事件处理中采用了非阻塞复用模式。然后为这个socket设置TCP_NODELAY属性,禁用Nagle算法,创建一个可读的文件事件来监控这个客户端socket的数据传输。客户端连接初始化后,Redis将检查当前的连接数,然后比较配置的maxclients值。如果当前连接数已达到最大客户端数,则意味着无法再接收此连接。Redis会直接向客户端返回一个连接错误,并立即关闭这个连接。
服务器处理序列
如果多个客户端连接到Redis,并且都向Redis发送命令,那么Redis服务器会先处理哪个客户端的请求?其实答案是不确定的,主要跟两个因素有关,一个是客户端套接字对应的数字大小,另一个是kernal上报每个客户端事件的顺序。
Redis按如下方式处理来自客户端的数据:
它对触发事件的socket调用once read,只读取一次(而不是读取这个socket上的消息),为了防止某个客户端连续发送太多命令导致其他客户端的请求长时间无法处理的情况。当然,当这个read调用完成后,无论包含多少个命令,都会一次性按顺序执行。通过这种方式,可以确保公平对待每个客户端命令。关于最大连接数maxclients
在Redis2.4中,最大连接数直接硬编码在代码中,而在2.6版中,该值变得可配置。maxclients的默认值是10000。您也可以在redis.conf中修改该值
当然,这个值只是Redis的一厢情愿的值,Redis还会照顾到系统自己对进程使用的文件描述符数量的限制。Redis将在启动时检查系统的软限制,以查看打开的文件描述符的最大数量。如果系统设置的数量小于最大连接数加32,那么maxclients的设置将不起作用,Redis将根据系统要求设置该值。(加上32是因为Redis在内部最多会使用32个文件描述符,所以可以连接使用的就相当于所有可用的描述符减去32)。
出现这种情况时(设置后maxclients不起作用时),Redis启动过程中会有相应的日志记录。例如,以下命令希望将最大客户端数量设置为100,000,因此Redis需要100,000+32个文件描述符,而系统的最大文件描述符设置为10144,因此Redis只能将maxclients设置为10144–32 = 10112。
$ ./redis-server-max clients 100000[41422]23 Jan 11:28:33.179 #无法将最大文件数限制设置为100032(无效参数),将最大客户端配置设置为10112。
因此,当您想要设置maxclients值时,最好顺便修改您的系统设置。当然,你也可以通过养成阅读日志的好习惯来发现这个问题。
具体设置方式看你个人需求。只能修改这个会话的限制,也可以通过sysctl直接修改系统的默认设置。比如:
ulimit -Sn 100000 #这只在硬限制足够大时才有效
输出缓冲区大小限制
对于Redis的输出(即命令的返回值),其大小往往是不可控的。它可能是一个简单的命令,可以产生巨大的返回数据。另外,也有可能是因为执行的命令太多,生成的返回数据的速率超过了发送给客户端的速率。这时也会出现消息堆积,导致输出缓冲区越来越大,占用内存过多,甚至导致系统崩溃。
所以Redis设置了一些保护机制来避免这种情况。这些机制作用于不同类型的客户端,并具有不同的输出缓冲区大小限制。有两种方法可以限制它们:
一种是大小限制,当某个客户端的缓冲区超过一定大小时,直接关闭客户端连接;另一种是当某个客户端的缓冲区在一段时间内占用过多空时,也直接关闭客户端连接。针对不同客户的策略如下:
对于普通客户端来说,限制为0,即没有限制,因为普通客户端通常采用阻塞消息响应方式,比如发送请求,等待返回,再次发送请求,等待返回。这种模式通常不会导致输出缓冲区的积累和扩大。对于发布/订阅客户端,大小限制为32m。当输出缓冲区超过32m时,连接将被关闭。持久性限制是,当客户端缓冲区大小超过8m达60秒时,连接也将被关闭。对于从属客户端,大小限制是256m,持久性限制是当客户端缓冲区大小超过64m达60秒时关闭连接。以上三个规则是可配置的。可以通过CONFIG SET命令或修改redis.conf文件来配置它。
输入缓冲区大小限制。
Redis严格限制输入缓冲区的大小。当客户端发送的请求大小超过1G时,服务器会直接关闭连接。这种方法可以有效地防止某些客户端或服务器bug导致的输入缓冲区过大的问题。
客户端超时
对于当前版本的Redis,默认情况下,服务器不会关闭长时间闲置的客户端空。但是您可以修改默认配置来设置您想要的超时。比如客户端超过很长时间没有交互,就直接关闭。同样,这也可以通过CONFIG SET命令或修改redis.conf文件来配置。
值得注意的是,超时的设置只对普通客户端有效。对于发布/订阅客户端,长期空空闲状态是正常的。
此外,实际超时可能没有设置的精确,因为Redis不使用计时器或循环遍历来检测客户端超时,而是以渐进的方式进行,一次检查一部分。因此,您可以将超时时间设置为10秒,但实际执行时间是12秒,然后客户端就会关闭。
客户端命令
Redis客户端命令可以实现三个功能:检查连接的状态、终止连接和为连接设置名称。
list命令可以获取所有客户端的当前状态,其用法如下:
redis 127.0.0.1:6379客户端列表addr = 127 . 0 . 0 . 1:52555 FD = 5 name = age = 855 idle = 0 flags = N db = 0 sub = 0 psub = 0 multi =-1 qpuf = 0 qpuf-free = 32768 obl = 0 oll = 0 o mem = 0 events = r cmd = client addr = 127 . 0 . 0 . 1:52787 FD = 6 name
从上面命令的输出可以看出,目前这个Redis有两个客户端连接,每行代表一个连接的各种信息:
Addr:客户端的TCP地址,包括IP和端口fd:客户端连接名称的套接字对应的文件描述符句柄号:连接的名称,默认为空。可以设置年龄:客户端空闲存活的秒数:客户端空空闲的秒数标志:客户端的类型(n表示普通客户端,更多类型见文档查看所有输出的含义。
通过上面的命令获得客户端列表后,可以通过CLIENT KILL命令终止指定的连接。客户端KILL的参数就是上面的addr值。
上面提到的客户端设置名和客户端获取名可以用来设置连接的名称。