story

在项目中的数据库链接使用socket链接,原来socket链接默认的buffer只有1460byte,从db读取大背包数据时候就会变得很慢,主要原因在buffer设置很小时候,socket进程会收到多个info消息,多次处理消耗时间。
后面把buffer从原来的1460设置到65535({recbuf 65535})后,db读取7m的数据由原来的6.2s提升到0.22s左右。

recbuf sndbuf buffer 之间关系

概念

  • recbuf 系统层面的接收区缓存
  • sndbuf 系统层面的发送缓冲区
  • buffer erlang虚拟机层面的接收缓冲区,有高速的内存分配器,默认1460

测试三者设置后的现象

系统环境

CentOS Linux release 7.8.2003 (Core)
OTP22

系统默认设置:

1
2
3
4
[root@localhost sbin]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 6291456
[root@localhost sbin]# cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304

默认的三者数值
1
2
3
4
5
6
Eshell V10.5  (abort with ^G)
1>
1> {ok, S} = gen_tcp:connect("www.baidu.com", 80, [{active,false}]).
{ok,#Port<0.6>}
2> inet:getopts(S, [recbuf,sndbuf,buffer]).
{ok,[{recbuf,369280},{sndbuf,87040},{buffer,1460}]}
单独设置recbuf

recbuf自动x2(可能考虑到封包的大小),buffer自动设置为目标值

1
2
3
4
5
Eshell V10.5  (abort with ^G)
1> {ok, S} = gen_tcp:connect("www.baidu.com", 80, [{recbuf, 2000},{active,false}]).
{ok,#Port<0.6>}
2> inet:getopts(S, [recbuf,sndbuf,buffer]).
{ok,[{recbuf,4000},{sndbuf,87040},{buffer,2000}]}

单独设置sndbuf

自动x2

1
2
3
4
3> {ok, S1} = gen_tcp:connect("www.baidu.com", 80, [{sndbuf, 4096},{active,false}]).
{ok,#Port<0.7>}
4> inet:getopts(S1, [recbuf,sndbuf,buffer]).
{ok,[{recbuf,369280},{sndbuf,8192},{buffer,1460}]}

单独设置buffer

只生效buffer部分

1
2
3
4
5> {ok, S2} = gen_tcp:connect("www.baidu.com", 80, [{buffer, 4096},{active,false}]).
{ok,#Port<0.8>}
6> inet:getopts(S2, [recbuf,sndbuf,buffer]).
{ok,[{recbuf,369280},{sndbuf,87040},{buffer,4096}]}

三者之间更详细的说明以及源码解读可参考:
gen_tcp接收缓冲区易混淆概念纠正