背景
項目中經常使用LVS做負載,當一個長連接過段時間不發消息時,LVS之后就不會再轉發這個長連接的TCP數據包。
使用TCP長連接的場景
一種情況:為了節省TCP連接時間,我們選擇建立幾個固定的TCP長連接,然后把所有的消息平均分配的這幾個TCP通道上傳送給對方。
另一種情況:客戶端和服務端之間是一個會話,要隔一段時間發個心跳。
現在出現了第三種情況,我是一個代理程序,要轉發一個會話,讓服務端和客戶端都無感知;而且多個會話可以復用一個通路
(1)我需要在會話建立之前就建立連接;
(2)沒設計代理的心跳接口,我不能自己給后端發心跳;
但代理和后端之間隔着LVS。我不發心跳,LVS就偷偷地把長連接斷開了,而此時代理和后端都一無所知。從連接上看都是ESTABLISHED,一發消息就被RST。
這時我們就用到了TCP自帶的keepalive機制。
配置TCP長連接參數
在Centos7上的嘗試,配置以下內核參數
# cat /etc/sysctl.conf
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_intvl = 20
但是沒見生效;為什么沒生效?因為需要自己在程序里開啟KEEPALIVE標識;(也就是說得讓系統知道你是長連接)
在C++的程序中開啟方法如下:
int keepAlive = 5;
int keepIdle = 5;
int keepInterval = 5;
int keepCount = 3;
if(setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1)
{
printf("setsockopt SO_KEEPALIVE error!");
}
思考問題:那發送間隔等參數的設置,最后以誰為准呢?
答:如果程序中設置了,以程序中的為准。如果只是像上面開啟了標識,沒設置參數。那么就以/etc/sysctl.conf中配置的參數為准。