rinetd 在生产环境要谨慎使用
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
起因:
购买了阿里云的redis节点,但是默认阿里云不提供公网IP,所以我在一台阿里云的机器启动了rinetd,做端口的转发服务,开始一切正常,一段时间以后,随着并发力度加大。我们发现redis连不上了,提示Connection reset by peer
排查
1. 排查Redis
为什么会这样,首先我怀疑,是否redis有问题
首先我查看了redis的负载情况,使用INFO 命令
# Clients
connected_clients:192
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:16
# Stats
total_connections_received:1131
total_commands_processed:7225865
instantaneous_ops_per_sec:30
total_net_input_bytes:216949807
total_net_output_bytes:87315792
显然redis的负载并不高
instantaneous_ops_per_sec 要超过2w, 负载才算高
connected_clients还不到200, 默认的设置允许最大连接数是1w
2. 排查阿里云主机
首先这台的机器的连接数并不高
[root@xxx-xx-77 ~]# ss -s
Total: 733 (kernel 751)
TCP: 644 (estab 598, closed 1, orphaned 0, synrecv 0, timewait 1/0), ports 234
Transport Total IP IPv6
* 751 - -
RAW 0 0 0
UDP 1 1 0
TCP 643 636 7
INET 644 637 7
FRAG 0 0 0
但是观察机器的CPU使用率
top - 13:34:57 up 72 days, 21:21, 2 users, load average: 1.03, 1.32, 1.08
Tasks: 264 total, 2 running, 262 sleeping, 0 stopped, 0 zombie
Cpu(s): 3.6%us, 9.9%sy, 0.0%ni, 85.8%id, 0.0%wa, 0.0%hi, 0.8%si, 0.0%st
Mem: 15641200k total, 15093856k used, 547344k free, 246612k buffers
Swap: 4194300k total, 0k used, 4194300k free, 3384744k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
19532 root 20 0 9284 1828 612 R 100.0 0.0 16:18.16 rinetd
6456 root 20 0 96076 10m 1292 S 11.6 0.1 35:13.00 redis-server
13636 rabbitmq 20 0 6029m 255m 3940 S 0.7 1.7 1912:26 beam.smp
16505 root 20 0 935m 79m 9.9m S 0.3 0.5 184:33.40 docker
20069 root 20 0 17208 1380 952 S 0.3 0.0 0:15.24 top
20312 root 20 0 17208 1384 952 R 0.3 0.0 0:00.01 top
1 root 20 0 21408 1636 1312 S 0.0 0.0 0:54.05 init
很明显是rinetd 所占CPU过高,这是一个异常点
[root@bbd-iner-2-77 ~]# ps -mp 19532 -o THREAD,tid
USER %CPU PRI SCNT WCHAN USER SYSTEM TID
root 36.6 - - - - - -
root 36.6 19 - - - - 19532
使用strace 追一下系统调用
strace -p 19532
sendto(1024, "*3\r\n$3\r\nSET\r\n$5\r\n11111\r\n$2\r\n15\r\n", 32, 0, NULL, 0) = 32
select(1025, [4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
... ...
993 997 999 1003 1007 1009 1013 1017])
recvfrom(408, "+OK\r\n", 1024, 0, NULL, NULL) = 5
recvfrom(409, "*3\r\n$3\r\nSET\r\n$5\r\n11111\r\n$2\r\n15\r\n", 1024, 0, NULL, NULL) = 32
recvfrom(411, "*3\r\n$3\r\nSET\r\n$5\r\n11111\r\n$2\r\n15\r\n", 1024, 0, NULL, NULL) = 32
sendto(413, "$2\r\n15\r\n", 8, 0, NULL, 0) = 8
recvfrom(415, "*2\r\n$3\r\nGET\r\n$5\r\n11111\r\n", 1024, 0, NULL, NULL) = 24
recvfrom(423, "*2\r\n$3\r\nGET\r\n$5\r\n11111\r\n", 1024, 0, NULL, NULL) = 24
recvfrom(425, "*2\r\n$3\r\nGET\r\n$5\r\n11111\r\n", 1024, 0, NULL, NULL) = 24
recvfrom(440, "+OK\r\n", 1024, 0, NULL, NULL) = 5
rinetd 没有使用epoll,而是用了select
众所周知, select是基于类似的轮训的机制,反复去查询fd的情况,并且会在内核空间和用户空间拷贝fd集合
在IO比较高的情况下,select相比epoll有更高的CPU消耗,并且select默认最大支持1024个fd
所以rinetd才把CPU打的比较高,导致转发服务异常
解决
直接使用nginx的tcp proxy模块,问题解决,并且CPU使用率也不高
参考资料:
1. select、poll、epoll之间的区别总结[整理]
2. NGINX Load Balancing – TCP and UDP Load Balancer
看到博主使用的wordstar,真巧,我也是这个主题。找问题找了过来,rinetd 2023年都不支持epoll。
倒是有不少fork 15年就支持epoll了。作者添加支持IPv6都用了4年,支持epoll可能猴年马月了。