服务如何实现优雅重启

前言

平滑重启主要考虑两点:

  • 如何做到不中断接收新请求

  • 老的请求不能被中断

 

实现思路

主要思路就是要解决新老进程切换过程中listener文件描述符和现有连接描述符的迁移,之前有一篇文章讲了如何通过unixSocket来传递文件描述符,这里也会用到这个技术, 具体的迁移流程如下:

 

1、老进程在启动时,启动tcp listen监听,就是开启对外服务的端口,如果有请求过来,开启一个协程处理这个请求。

2、老进程启动一个unix Socket监听,通过switch.sock和新进程进行通信,一旦由请求过来,就把自己的listener文件描述符发给新进程,然后通过发送信号触发迁移流程,同时等待一段时间关闭自己的listener,进程退出。

3、新进程在启动前,会尝试连接旧进程的switch.sock,如果通信成功,就知道它需要开始接收旧的listener 和 connection了,此时会分别启动listen.sock监听和conn.sock监听,来获取旧进程的listener信息和conn信息。如果收到了listener信息,则会用这个listener启动服务。

4、接步骤1,协程在处理请求的过程中,如果收到了迁移信号,则会判断是否将现有的客户端连接发给新进程,如果连接里还有可读的数据,则需要迁移。

 

到此整个迁移流程就完毕了。

 

测试

代码在 https://gitee.com/zqwlai/proxy,服务端在处理TCP请求时,是以“#”为分隔符来处理的,会返回“进程标志 reply:截断部分#”。如果客户端没有发送“#”,则连接会一直保持(阻塞),这样可以模拟TCP的长连接,方便连接迁移的测试。

 

先启动服务:

go run main.go -l :8081 -p hello  #-p表示进程标识符

 

 

客户端采用telnet的方式与服务端通信

 

 

可以看到当发送“123#456”时,会返回“hello reply:123#”,同时查看连接状态:

$ netstat -an |grep 8081
tcp        0      0 127.0.0.1:38514         127.0.0.1:8081          ESTABLISHED
tcp6       0      0 :::8081                 :::*                    LISTEN     
tcp6       0      0 127.0.0.1:8081          127.0.0.1:38514         ESTABLISHED

 

 

然后再次启动服务端(也可以用fork子进程的方式来实现,需要代码做下改动):

go run main.go -l :8081 -p BBB


再次发送一个“#”,可以看到结果能被正确返回

 

 

 

posted @   独揽风月  阅读(254)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示