c - 连接到 Redis 时,Unix 套接字比 tcp 慢

标签 c sockets unix redis server

我正在开发高性能 Web 服务器,它应该可以处理约 2k 个并发连接和 40k QPS,实现响应时间 < 7ms。

它所做的是查询 Redis 服务器(在同一主机上运行)并将响应返回给客户端。 在测试期间,我观察到使用 TCP STREAM_SOCKET 的实现比使用 unix 套接字连接要好得多。在约 1500 个连接的情况下,TCP 保持约 8 毫秒,而 unix 套接字达到约 50。

服务器是用 C 编写的,它基于常量 Posix 线程池,我使用阻塞连接到 Redis。我的操作系统是 CentOS 6,使用 Jmeter、wrk 和 ab 进行了测试。 对于与 redis 的连接,我使用 hiredis 库,它提供了这两种连接到 Redis 的方式。
据我所知,unix socket 应该至少和 TCP 一样快。

有人知道什么会导致这种行为吗?

最佳答案

Unix 域套接字通常比环回接口(interface)上的 TCP 套接字更快。通常 Unix 域套接字的平均延迟为 2 微秒,而 TCP 套接字为 6 微秒。

如果我使用默认值(无管道)运行 redis-benchmark,我看到每秒 160k 个请求,主要是因为单线程 redis 服务器受 TCP 套接字限制,160k 请求运行平均响应时间为 6 微秒。

Redos 在使用 Unix 域套接字时每秒可实现 320k SET/GET 请求。

但是有一个限制,实际上我们在 Torusware 的产品已经达到了这个限制 Speedus ,一个高性能的 TCP 套接字实现,平均延迟为 200 纳秒(通过 info@torusware.com 向我们发送请求极限性能版本)。我们看到 redis-benchmark 的延迟几乎为零,每秒可处理大约 500k 个请求。因此我们可以说,redis-server 平均每个请求的延迟约为 2 微秒。

如果您想尽快回答并且您的负载低于 redis 服务器的峰值性能,那么避免流水线可能是最好的选择。但是,如果您希望能够处理更高的吞吐量,那么您可以处理请求管道。响应可能需要更长的时间,但您将能够在某些硬件上处理更多请求。

因此,在之前的场景中,使用 32 个请求的管道(在通过套接字发送实际请求之前缓冲 32 个请求),您可以通过环回接口(interface)每秒处理多达 100 万个请求。而在这种场景下,UDS 的 yield 并没有那么高,尤其是因为处理这样​​的流水线是性能瓶颈。事实上,管道为 32 的 1M 请求大约是每秒 31,000 个“实际”请求,我们已经看到 redis-server 每秒能够处理 160,000 个请求。

Unix 域套接字每秒处理大约 110 万和 170 万个 SET/GET 请求。 TCP 环回每秒处理 1M 和 1.5 个 SET/GET 请求。

通过流水线,瓶颈从传输协议(protocol)转移到流水线处理。

这与 redis-benchmark 中提到的信息一致地点。

但是,流水线显着增加了响应时间。因此,在没有流水线的情况下,100% 的操作通常在不到 1 毫秒的时间内运行。当流水线处理 32 个请求时,在高性能服务器中最大响应时间为 4 毫秒,如果 redis-server 在不同的机器或虚拟机中运行,则为数十毫秒。

因此您必须权衡响应时间和最大吞吐量。

关于c - 连接到 Redis 时,Unix 套接字比 tcp 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26934941/

相关文章:

mysql - 是否可以使用 mysqlimport 设置 MySQL session 变量?

char* 与 char(*)[100] 的间接级别不同

c - 使用TCP从服务器下载文件

mysql - 哪些软件可以将mysql套接字文件转发到远程服务器?

java - 检查DataInputStream是否有内容

unix - 如何在不获取 nohup.out 的情况下使用 nohup 命令?

powershell - 根据参数将文件从Unix复制到Windows

C - 从可写字符数组中删除第 i 个字符

android - 我可以在 Android 环境中使用 SQLite 内置函数吗?

我可以同时初始化和使用两个 Lua 缓冲区吗?