KeyDB 客户端处理
本文档从网络层的角度,提供有关 KeyDB 如何处理客户端的信息:包括连接、超时、缓冲区以及其他类似主题。
#
客户端连接是如何被接受的KeyDB 在配置的监听 TCP 端口上以及(如果启用)在 Unix 套接字上接受客户端连接。当一个新的客户端连接被接受时,会执行以下操作:
- 客户端套接字被设置为非阻塞状态,因为 KeyDB 使用多路复用和非阻塞 I/O。
- 设置
TCP_NODELAY
选项以确保我们的连接中没有延迟。 - 创建一个*可读*文件事件,以便 KeyDB 能够在套接字上有新数据可读时立即收集客户端查询。
客户端初始化后,KeyDB 会检查是否已达到可同时处理的客户端数量上限(此上限通过 maxclients
配置指令进行配置)。
如果由于已达到最大客户端数而无法接受当前客户端,KeyDB 会尝试向客户端发送一个错误以告知其此情况,并立即关闭连接。即使 KeyDB 立即关闭连接,错误消息也能到达客户端,因为新的套接字输出缓冲区通常足够大,可以容纳该错误,所以内核将处理错误的传输。
#
客户端以何种顺序被服务顺序由客户端套接字文件描述符编号和内核报告事件的顺序共同决定,因此该顺序应被视为不确定的。
然而,KeyDB 在服务客户端时会做以下两件事:
- 每当客户端套接字有新内容可读时,它只执行一次
read()
系统调用,以确保当我们有多个客户端连接,且少数几个是非常活跃、高频率发送查询的客户端时,其他客户端不会受到影响,也不会经历糟糕的延迟。 - 但是,一旦从一个客户端读取到新数据,当前缓冲区中包含的所有查询都会被顺序处理。这提高了局部性,并且不需要再次迭代来查看是否有需要处理时间的客户端。
#
最大客户端数量过去,可同时处理的最大客户端数量有一个硬编码的限制。后来,这个限制变为动态的:默认设置为 10000 个客户端,除非在 keydb.conf 中由 maxclients
指令另行指定。
然而,KeyDB 会与内核核对我们能够打开的最大文件描述符数量(检查的是*软限制*)。如果该限制小于我们希望处理的最大客户端数量加上 32(这是 KeyDB 为内部使用保留的文件描述符数量),那么 KeyDB 会修改最大客户端数量,以匹配在当前操作系统限制下我们*真正能够处理*的客户端数量。
当配置的最大客户端数量无法满足时,启动时会记录该情况,如下例所示:
当 KeyDB 配置为处理特定数量的客户端时,最好确保操作系统的每个进程最大文件描述符数量的限制也相应设置。
在 Linux 下,这些限制可以在当前会话中设置,也可以通过以下命令作为系统范围的设置:
- ulimit -Sn 100000 # 仅当硬限制足够大时才有效。
- sysctl -w fs.file-max=100000
#
输出缓冲区限制KeyDB 需要为每个客户端处理一个可变长度的输出缓冲区,因为一个命令可能产生大量需要传输给客户端的数据。
然而,可能会出现客户端发送更多命令产生更多输出的速度,快于 KeyDB 将现有输出发送给客户端的速度。对于发布/订阅(Pub/Sub)客户端来说尤其如此,如果客户端无法足够快地处理新消息。
这两种情况都会导致客户端输出缓冲区增长并消耗越来越多的内存。因此,默认情况下,KeyDB 为不同类型的客户端设置了输出缓冲区大小的限制。当达到限制时,客户端连接将被关闭,并在 KeyDB 日志文件中记录该事件。
KeyDB 使用两种限制:
- 硬限制是一个固定的限制,一旦达到,KeyDB 会尽快关闭客户端连接。
- 软限制则是一个与时间相关的限制,例如,每 10 秒 32 MB 的软限制意味着,如果客户端的输出缓冲区持续 10 秒大于 32 MB,连接将被关闭。
不同类型的客户端有不同的默认限制:
- 普通客户端的默认限制为 0,即没有限制,因为大多数普通客户端使用阻塞实现,发送一个命令后等待回复被完全读取再发送下一个命令,所以在普通客户端的情况下,关闭连接通常是不可取的。
- 发布/订阅(Pub/Sub)客户端默认硬限制为 32 MB,软限制为每 60 秒 8 MB。
- 副本(Replicas)默认硬限制为 256 MB,软限制为每 60 秒 64 MB。
可以使用 CONFIG SET
命令在运行时更改限制,或者通过 KeyDB 配置文件 keydb.conf
进行永久更改。有关如何设置限制的更多信息,请参阅 KeyDB 发行版中的示例 keydb.conf
文件。
#
查询缓冲区硬限制每个客户端还受到查询缓冲区限制的约束。这是一个不可配置的硬限制,当客户端查询缓冲区(即我们用来累积客户端命令的缓冲区)达到 1 GB 时,将关闭连接。这实际上只是一个极端的限制,以防止在客户端或服务器软件出现错误时导致服务器崩溃。
#
客户端超时默认情况下,较新版本的 KeyDB 不会因为客户端空闲数秒而关闭连接:连接将永远保持打开。
但是,如果您不喜欢这种行为,可以配置一个超时时间,这样如果客户端空闲超过指定的秒数,客户端连接将被关闭。
您可以通过 keydb.conf
或简单地使用 CONFIG SET timeout <value>
来配置此限制。
请注意,超时仅适用于普通客户端,**不适用于发布/订阅(Pub/Sub)客户端**,因为发布/订阅连接是*推送式*连接,所以客户端空闲是正常现象。
即使默认情况下连接不受超时限制,但在两种情况下设置超时是有意义的:
- 任务关键型应用,其中客户端软件的错误可能导致 KeyDB 服务器被空闲连接饱和,从而导致服务中断。
- 作为一种调试机制,以便在客户端软件的错误导致服务器被空闲连接饱和,使其无法与服务器交互时,能够连接到服务器。
超时不应被认为是十分精确的:KeyDB 避免设置定时器事件或运行 O(N) 算法来检查空闲客户端,因此检查是定期增量执行的。这意味着,虽然超时设置为 10 秒,但如果同时连接了许多客户端,客户端连接可能会在例如 12 秒后才被关闭。
#
CLIENT 命令KeyDB 的 client 命令允许检查每个已连接客户端的状态、终止特定客户端、为连接设置名称。如果您大规模使用 KeyDB,这是一个非常强大的调试工具。
CLIENT LIST
用于获取已连接客户端及其状态的列表:
在上面的示例会话中,有两个客户端连接到 KeyDB 服务器。一些最有趣字段的含义如下:
- addr:客户端地址,即客户端用于连接 KeyDB 服务器的 IP 和远程端口号。
- fd:客户端套接字文件描述符编号。
- name:由
CLIENT SETNAME
设置的客户端名称。 - age:连接存在的秒数。
- idle:连接空闲的秒数。
- flags:客户端类型(N 表示普通客户端,请查看完整的标志列表)。
- omem:客户端用于输出缓冲区的内存量。
- cmd:最后执行的命令。
请参阅 CLIENT LIST 文档以获取完整的字段列表及其含义。
一旦有了客户端列表,您就可以使用 CLIENT KILL
命令,并以客户端地址作为参数,轻松地关闭与客户端的连接。
CLIENT SETNAME
和 CLIENT GETNAME
命令可用于设置和获取连接名称。从 KeyDB 4.0 开始,客户端名称会显示在 SLOWLOG
输出中,这使得识别导致延迟问题的客户端变得更加简单。
#
TCP keepaliveKeyDB 默认启用了 TCP keepalive(SO_KEEPALIVE
套接字选项),并设置为约 300 秒。此选项有助于检测死亡的对等方(即那些看起来已连接但无法访问的客户端)。此外,如果客户端和服务器之间存在需要看到一些流量才能保持连接开放的网络设备,该选项将防止意外的连接关闭事件。