本文通过rocketMq源码说明netty中常见channelOption的含义和用法
先看服务端
SO_BACKLOG:用于指定服务端连接队列长度,当服务器连接处理线程全忙时,已完成三次握手的请求会被临时存放在连接队列中等待被accept,队列满后会拒绝新收到的连接请求
如不设置,该值默认为200左右,对于连接数不太多的场景,默认值就够了,像常见RPC框架的服务端(如dubbo)就没有设置,RocketMq需要支持更高频的连接请求,所以使用了推荐值1024
SO_REUSEADDR:TCP四次挥手的最后阶段,主动发起关闭的一端会处于TIME_WAIT状态,该状态下的socket所用端口无法被复用(默认时间2MSL=4分钟);
在服务端客户端架构中,通常是服务端主动发起连接关闭,在大量连接的场景中,无论是频繁关闭连接和新建连接,还是服务端重启,都需要端口资源,4分钟太长了,不能忍。
SO_REUSEADDR=true就是通知内核,如果端口忙,但socket状态是TIME_WAIT,可以立即重用端口;因为端口资源限制,该配置算是服务端必备的了
SO_KEEPALIVE:TCP有内置的连接保活机制,保活并不是把挂掉的连接整活,而是及时发现并释放无效连接资源,只留下活跃的连接
由于netty提供的IdleStateHandler可以非常方便、灵活的实现心跳维持和会话管理,所以一般不用TCP自带的KEEP_ALIVE,这里就设置为false了
TCP_NODELAY:TCP/IP协议中针对TCP默认开启了Nagle算法,会对包的发送进行限制,至少满足下面任意一个条件才可以发出
1.写缓冲区的字节数超过指定阈值 2.之前发出的所有包都已收到ack
其好处是减少网络开销和发送接收两端的压力,坏处就是存在发送延时,对于延时敏感型、数据传输量比较小的应用,应该选择关闭Nagle算法,关闭方式为设置TCP_NODELAY=true
SO_SNDBUF与SO_RCVBUF:每个socket都有一个receive缓冲区和send缓冲区,在调用socket的read send时,其实仅仅是操作缓冲区
read仅仅从receive缓冲区拿数据,拿不到就阻塞等待对端数据从网络过来。send仅仅将数据放入send缓冲区,缓冲区满了就等待
对于TCP协议来说,由于有滑动窗口控制,如果接收端read缓冲区已满,还未来的及处理,则会在回复发送端的ack中缩小窗口值,提示发送端降低发送速度,甚至暂时不发,缓解自身的压力
所以说缓冲区的大小影响的是两端发送接收的速度和压力,没有一个标准的参考值,实际生产时应该由测试结果决定,通常情况下,默认的值就够了,也就是不需要设置
服务端参数小结,可以看到,服务端在设置option时,有两类方法
一类是option(),作用的对象是服务端监听端口的socket(我们称之为父socket)
一类是childOption,作用的对象是与客户端连接的socket(我们称之为子socket)
哪些参数该设置在父socket哪些设置在子socket上,我没找到一个满意的说法,我自己的推测是子socket只用于数据传输,与数据发送接收有关的option应该设置在子socket上;如果你看到标准答案,记得告诉我一声...
再看客户端
除了CONNECT_TIMEOUT_MILLS,其他参数在服务端中都已经介绍过,CONNECT_TIMEOUT_MILLS顾名思义,连接超时时间,超过该时间还没连上服务端,则抛出timeout异常,也算是客户端的标配了
由于客户端只与服务端建立少量的连接,所以不需要设置SO_REUSEADDR