本文档提供了关于 Valkey 如何在网络层处理客户端的信息:包括连接、超时、缓冲区以及其他类似主题。
接受客户端连接
如果启用,Valkey 会在配置的 TCP 端口和 Unix 套接字上接受客户端连接。当接受新的客户端连接时,会执行以下操作:
- 客户端套接字被设置为非阻塞状态,因为 Valkey 使用多路复用和非阻塞 I/O。
- 设置
TCP_NODELAY
选项是为了确保连接没有延迟。 - 创建一个可读文件事件,以便 Valkey 能够在套接字上有新数据可读时立即收集客户端查询。
客户端初始化后,Valkey 会检查是否已达到配置的并发客户端数量限制(使用 maxclients
配置指令进行配置,有关更多信息,请参阅本文档的下一节)。
当 Valkey 因达到最大客户端数量而无法接受新的客户端连接时,它会尝试向客户端发送错误以告知此情况,并立即关闭连接。即使连接立即被 Valkey 关闭,错误消息也会到达客户端,因为新的套接字输出缓冲区通常足够大以包含错误,因此内核将处理错误的传输。
客户端请求以什么顺序服务?
顺序由客户端套接字文件描述符编号和内核报告事件的顺序组合决定,因此应将该顺序视为未指定。
然而,Valkey 在服务客户端时会执行以下两项操作:
- 每次从客户端套接字有新数据可读时,它只执行一次
read()
系统调用。这确保了如果连接了多个客户端,并且少数客户端以高频率发送查询,其他客户端不会受到影响,也不会遇到延迟问题。 - 但是,一旦从客户端读取到新数据,当前缓冲区中包含的所有查询都将按顺序处理。这提高了局部性,并且无需第二次迭代来查看是否有客户端需要处理时间。
最大并发连接客户端数
可以同时处理的最大客户端数量限制可通过 valkey.conf
中的 maxclients
指令进行配置。默认值为 10,000 个客户端。
然而,Valkey 会向内核查询我们能够打开的最大文件描述符数量(检查*软限制*)。如果该限制小于我们想要处理的最大客户端数量加上 32(这是 Valkey 为内部使用保留的文件描述符数量),那么最大客户端数量将更新为在当前操作系统限制下*真正能够处理*的客户端数量。
当 maxclients
设置为一个超出 Valkey 支持范围的数字时,启动时会记录一条消息:
$ ./valkey-server --maxclients 100000
[41422] 23 Jan 11:28:33.179 # Unable to set the max number of files limit to 100032 (Invalid argument), setting the max clients configuration to 10112.
当 Valkey 配置为处理特定数量的客户端时,最好确保操作系统对每个进程的最大文件描述符数量也相应设置。
在 Linux 下,这些限制可以在当前会话中设置,也可以作为系统范围的设置,使用以下命令:
ulimit -Sn 100000 # 仅当硬限制足够大时才有效。
sysctl -w fs.file-max=100000
输出缓冲区限制
Valkey 需要为每个客户端处理可变长度的输出缓冲区,因为一个命令可能会产生大量需要传输给客户端的数据。
然而,客户端可能会以比 Valkey 向客户端发送现有输出更快的速度发送更多命令并产生更多输出。对于 Pub/Sub 客户端来说尤其如此,如果客户端无法足够快地处理新消息。
这两种情况都会导致客户端输出缓冲区不断增长并消耗越来越多的内存。因此,默认情况下,Valkey 会对不同类型的客户端设置输出缓冲区大小限制。当达到限制时,客户端连接将被关闭,并且事件会记录在 Valkey 日志文件中。
Valkey 使用两种类型的限制:
- 硬限制是一个固定限制,一旦达到该限制,Valkey 将尽快关闭客户端连接。
- 软限制则是一个与时间相关的限制,例如,每 10 秒 32 兆字节的软限制意味着如果客户端的输出缓冲区持续超过 32 兆字节达 10 秒,连接就会被关闭。
不同类型的客户端有不同的默认限制:
- 普通客户端的默认限制为 0,这意味着完全没有限制,因为大多数普通客户端使用阻塞实现,发送一个命令并等待回复完全读取后再发送下一个命令,因此在普通客户端的情况下关闭连接总是不受欢迎的。
- Pub/Sub 客户端的默认硬限制为 32 兆字节,软限制为每 60 秒 8 兆字节。
- 副本的默认硬限制为 256 兆字节,软限制为每 60 秒 64 兆字节。
可以使用 CONFIG SET
命令在运行时更改限制,或者使用 Valkey 配置文件 valkey.conf
以永久方式更改。有关如何设置限制的更多信息,请参阅 Valkey 分发包中的 valkey.conf
示例。
查询缓冲区硬限制
每个客户端也受到查询缓冲区限制。这是一个不可配置的硬限制,当客户端查询缓冲区(即我们用于从客户端累积命令的缓冲区)达到 1 GB 时,将关闭连接。它实际上只是一个极端限制,旨在避免在客户端或服务器软件出现错误时导致服务器崩溃。
客户端驱逐
Valkey 旨在处理大量的客户端连接。客户端连接往往会消耗内存,当数量众多时,总内存消耗可能非常高,从而导致数据驱逐或内存不足错误。这些情况可以在一定程度上通过输出缓冲区限制来缓解,但 Valkey 允许我们进行更强大的配置,以限制所有客户端连接使用的总内存。
这种机制被称为客户端驱逐,它本质上是一种安全机制,一旦所有客户端的总内存使用量超过某个阈值,就会断开客户端连接。该机制首先尝试断开使用内存最多的客户端。它会断开最少数量的客户端连接,以使总内存使用量回到 maxmemory-clients
阈值以下。
maxmemory-clients
定义了连接到 Valkey 的所有客户端的最大总内存使用量。聚合考虑了客户端连接使用的所有内存:查询缓冲区、输出缓冲区以及其他中间缓冲区。
请注意,副本和主连接不受客户端驱逐机制的影响。因此,此类连接永远不会被驱逐。
maxmemory-clients
可以永久设置在配置文件(valkey.conf
)中,也可以通过 CONFIG SET
命令设置。此设置可以是 0(表示无限制),以字节为单位的大小(可能带有 mb
/gb
后缀),或者通过使用 %
后缀表示 maxmemory
的百分比(例如,将其设置为 10%
将表示 maxmemory
配置的 10%)。
默认设置为 0,表示客户端驱逐默认关闭。然而,对于任何大型生产部署,强烈建议配置一个非零的 maxmemory-clients
值。例如,5%
是一个很好的起始值。
可以标记特定的客户端连接,使其不被客户端驱逐机制影响。这对于控制路径连接非常有用。例如,如果您有一个应用程序通过 INFO
命令监视服务器并在出现问题时发出警报,您可能希望确保此连接不会被驱逐。您可以使用以下命令(从相关客户端的连接)执行此操作:
CLIENT NO-EVICT
on
您可以使用以下命令恢复:
CLIENT NO-EVICT
off
有关更多信息和示例,请参阅默认 valkey.conf
文件中的 maxmemory-clients
部分。
客户端驱逐功能从 Redis OSS 7.0 开始可用。
客户端超时
默认情况下,Valkey 的最新版本不会在客户端空闲多秒时关闭与客户端的连接:连接将永远保持打开状态。
但是,如果您不喜欢这种行为,可以配置一个超时,这样如果客户端空闲时间超过指定的秒数,客户端连接将被关闭。
您可以通过 valkey.conf
配置此限制,或者直接使用 CONFIG SET timeout
命令。
请注意,超时仅适用于普通客户端,**不适用于 Pub/Sub 客户端**,因为 Pub/Sub 连接是*推模式*连接,因此客户端空闲是正常情况。
即使默认情况下连接不受超时限制,但在以下两种情况下设置超时是有意义的:
- 任务关键型应用程序,其中客户端软件中的错误可能导致 Valkey 服务器被空闲连接饱和,从而造成服务中断。
- 作为一种调试机制,当客户端软件中的错误使服务器被空闲连接饱和,导致无法与服务器交互时,能够连接到服务器。
超时不应被视为非常精确:Valkey 避免设置定时器事件或运行 O(N) 算法来检查空闲客户端,因此检查是逐步进行的。这意味着,即使超时设置为 10 秒,如果同时连接了许多客户端,客户端连接也可能在例如 12 秒后才关闭。
CLIENT
命令
Valkey 的 CLIENT
命令允许您检查每个已连接客户端的状态、终止特定客户端以及命名连接。如果您大规模使用 Valkey,它是一个非常强大的调试工具。
使用 CLIENT LIST
可以获取连接客户端及其状态的列表:
127.0.0.1:6379> client list
addr=127.0.0.1:52555 fd=5 name= age=855 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=client
addr=127.0.0.1:52787 fd=6 name= age=6 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping
在上面的示例中,有两个客户端连接到 Valkey 服务器。让我们看看返回的一些数据代表什么:
- addr:客户端地址,即客户端 IP 及其用于连接 Valkey 服务器的远程端口号。
- fd:客户端套接字文件描述符编号。
- name:通过
CLIENT SETNAME
设置的客户端名称。 - age:连接已存在的秒数。
- idle:连接空闲的秒数。
- flags:客户端类型(N 表示普通客户端,请查看完整的标志列表)。
- omem:客户端输出缓冲区使用的内存量。
- cmd:最后执行的命令。
有关字段的完整列表及其用途,请参阅 CLIENT LIST
文档。
获取客户端列表后,您可以使用 CLIENT KILL
命令关闭客户端连接,并将其客户端地址作为参数。
命令 CLIENT SETNAME
和 CLIENT GETNAME
可用于设置和获取连接名称。从 Redis OSS 4.0 开始,客户端名称会显示在 SLOWLOG
输出中,以帮助识别造成延迟问题的客户端。
TCP keepalive
Valkey 默认启用 TCP keepalive(SO_KEEPALIVE
套接字选项)并设置为大约 300 秒。此选项对于检测死对等体(即使看起来已连接也无法访问的客户端)很有用。此外,如果在客户端和服务器之间存在需要看到某些流量才能保持连接打开的网络设备,此选项将防止意外的连接关闭事件。