如何在进程间转移Unix domain socket所有权实现gRPC服务无缝升级
核心结论
Unix domain socket(以下简称UDS)完全支持无缝转移套接字、不中断现有连接的操作,完全可以满足你gRPC服务无缝升级的需求。
实现原理
Unix系统下所有套接字(包括TCP/UDP和UDS)的本质都是内核维护的文件描述符,只要能把监听状态的UDS文件描述符从旧进程B转移到新进程B',就可以实现无缝接管,不会丢失已有连接。
两种常用实现方案
- 方案1:父进程fork派生新进程
旧进程B作为父进程fork出子进程B',fork操作会自动将父进程持有的UDS监听套接字继承给子进程,之后父子进程可以同时监听同一个UDS路径。你可以给旧进程B发信号让它停止接收新请求,等旧进程的现有gRPC调用全部处理完成后正常退出,所有新请求就会自动由新进程B'承接,全程不会出现连接拒绝的情况。
这种方案实现最简单,不需要额外依赖,适合自己写服务启停逻辑的场景。 - 方案2:通过Unix域套接字传递文件描述符
你可以在新旧进程之间建立一个临时的UDS通信通道,调用sendmsg系统调用把旧进程B持有的UDS监听套接字作为控制消息发送给B',B'用recvmsg接收后就能拿到这个套接字的完整操作权限,之后就可以和上面的逻辑一样,让旧进程优雅退出即可。
这种方案适合新旧进程没有父子派生关系的场景。
gRPC场景的注意事项
- 你需要确保gRPC服务端开启优雅停机逻辑:收到停机信号后不再接收新连接,等待所有正在处理的RPC调用完成后再退出进程,避免正在进行的请求被中断。
- 不需要修改客户端进程A的任何逻辑,客户端感知不到服务端的替换过程。
- 如果你已经在使用Envoy/HAProxy做代理,也可以直接让代理监听UDS路径,后端配置为B和B'的实例,待B'启动正常后把B从后端池摘除,等B的现有连接全部释放后再下线B,同样可以实现无缝切换,逻辑和TCP代理完全一致。
内容的提问来源于stack exchange,提问作者h1990
相关产品推荐
相关产品推荐

