关键词预热
- 未处理完的请求终端,破坏数据一致性
- 新服务启动期间,请求无法进来导致服务一段时间不可用
解决方案
- 生产环境应用层通过四层或者七层负载均衡,通过流量调度来实现平滑重启【待更新】
- 通过Kubernetes实现对Go服务进行扩容、更新、回滚、平滑重启【待更新】
- 进程间通信来解决热更新【下文介绍】
生产环境集群一般的做法是 ApiGateway + CD, 发布的时候自动摘除机器,等待程序处理完现有请求再做发布处理,也可以借助SLB或者LVS手动切换流量
实现原理
- 原(父)进程fork一个子进程,同时让子进程继承父进程监听的所有socket
- 子进程初始化后开始接收新的请求
- 父进程停止接收新的请求,处理完当下请求后,等服务空闲,平滑退出
服务升级/更新时不关闭现有连结,不会出现拒绝访问的情况,对用户友好/用户无感知
进程间通信来解决热更新两种方式
- 设置套接字,将多个socket绑定在同一个监听端口,复制套接字【学习中】
- 用父子进程fork-exec继承文件描述符的特性,在父子进程之间维护传递监听socket。在升级/重启的过程中,父进程将监听socket继承给子进程,使得整个过程没有监听 socket 被关闭,从而不产生拒绝服务的问题。【本文demo使用方式】
实现方式
常见的开源实现graceful和endless。
graceful:https://github.com/facebookgo/grace
Golang >= 1.8可以使用 http.Server 的 Shutdown 方法实现
##代码实现
endless方式实现,lesof + 端口 查看启动的进程
kill -1 +端口 发送请求是查看请求被fork子进程收
1 | endless.DefaultReadTimeOut = setting.ReadTimeout |
http.Serve 实现demo,kill -1 +端口 同时发送请求,请求没有中断
1 | go func() { |
unix基础(补充)
进程间通信场景
- 数据传输
- 共享数据
- 通知事件
- 资源共享
- 进程控制
进程之间通信方式
- 管道
- 信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段
- 消息队列
- 信号:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生【本文demo采用的方式】
- 共享内存
- 套接字
信号说明
脚本输入:++kill -l++

常用信号列表