tcp连接迁移
意义
搜了一下好像并没有文章讲这件事,网上的tcp迁移
貌似讲的都是网关,跟upstream
直连偷偷换连接(偷改四元组,类似负载均衡);;不过我说的可能跟其他人看到标题时候想的也不一样,实际主要说的是热更新tcp长链不断。
mosn
主要也是看了mosn(蚂蚁版本envoy)源码,这块挺有意思的。
实际上我也没有完全看明白它的实现,里面代码封装太多层(抽象,也不好调试)。比方说,conntion
迁移的时候是和reader buffer
的数据一起过去了,如何避免中间时间差的read buffer
;我只是翻懂了大致的思路,然后自己写出来一个(写法上有一些差异)。
热更新
关于热更新:类似nginx或者go http服务的热更新,一般都比较熟知大致流程;
新进程继承listen port(子进程继承),并且接受新的http请求;
旧进程上面已存在的http请求正常运行至结束,旧进程在所有http请求关闭后自动退出;
所以新旧进程短时间可能会同时存在运行。
可以拿nginx和python来做个试验。
第一步:可以看到Nginx监听了80端口,没有任何连接过来
第二步:利用python的requests库发http请求,注意调用session()是为了保持tcp暂时不断
第三步:可以看见tcp已经保持不断,随后nginx -s reload
平滑重启nginx,发现旧进程上面的长链tcp服务器端主动断了
tcp长链不断
新旧进程间如何保证tcp长链不断?
主要利用Linux可以发送 control message 格式,来传递fd(包括listener/tcp conntion 都是可以的)
需要注意一些细节,例如read buffer
传过去的时机;又或者因为现在的tcp
是双工的,所以对于write
的conntion
是不需要重复传输conntion
的,read
的conntion
已经发送过一遍了。
reply
我写了一个极小demo,留作记录
我的程序会指定监听端口,当客户端连接上来的时候,无论发送过来,只有看到'#',就会把字符串截取加上指定的前缀吐出去
举个栗子
// 程序编译、运行
go build -o main
./main -l :8081 -p hello
// 然后就不用看上面服务端的日志,主要看下面客户端返回
// 客户端使用nc连接并发送数据
nc 127.0.0.1 8081
// 发送
123#456#789
// 收到
hello reply : 123#
hello reply : 456#
因为789
后面没有'#'号,所以程序并没有把 789
返回
// 这个时候启动新的进程
./main -p world
//并且把`789`后续的`#`补上发出去,你会发现nc收到了
world reply: 789#
// 最终旧进程平滑关闭
全流程下来 nc 与服务端的连接没有断链(可以任意中途netstat -anp查看连接),tcp保持长链无感
附件
附一份代码的流程图,防止忘了