trpc.group/trpc-go/trpc-go@v1.0.3/docs/user_guide/graceful_restart.zh_CN.md (about)

     1  [English](graceful_restart.md) | 中文
     2  
     3  # 前言
     4  
     5  tRPC-Go 框架支持服务优雅重启(热重启),在重启期间,不中断老进程已建立的连接、保证已接受的请求正确处理(包括消费者服务),同时新进程允许建立新的连接并处理连接请求。
     6  
     7  # 原理
     8  
     9  tRPC-Go 实现热重启的原理大致总结如下:
    10  - 服务启动的时候监听信号 SIGUSR2 作为热重启信号(可自定义);
    11  - 服务进程在启动的时候,会将启动的每个 servertransport 的 listenfd 记录下来;
    12  - 当服务进程接收到 SIGUSR2 信号之后,开始执行热重启逻辑;
    13  - 服务进程通过 ForkExec 来创建一个进程副本(不同于 fork),并通过 ProcAttr 传递 listenfd 给子进程,同时通过环境变量来告知子进程当前是热重启模式,也通过环境变量来传递 listenfd 的起始值以及数量;
    14  - 子进程正常启动,在实例化 servertransport 的时候稍有特殊,会检查当前是否是热重启模式,如果是则继承父进程 listenfd 并重建 listener,反之则走正常启动逻辑;
    15  - 子进程启动之后,立马提供正常服务,父进程得知子进程创建成功之后,择一合适时机退出,如 shutdown tcpconn read、停止 consumer 消费消息、service 上请求都已经正常处理之后再退出;
    16  
    17  # 实现代码
    18  
    19  参考 `server/serve_unix.go` 中涉及 `DefaultServerGracefulSIG` 变量处理的部分
    20  
    21  # 使用示例
    22  
    23  ## 热重启触发方法
    24  
    25  当启动 server 后,首先使用 `ps -ef | grep server_name` 来获取进程的 pid 信息,然后通过 kill 命令向该进程发送 USR2 信号:
    26  
    27  ```bash
    28  $ kill -SIGUSR2 pid
    29  ```
    30  
    31  上述命令即可完成进程的热重启操作
    32  
    33  ## 使用自定义 signal
    34  
    35  热重启信号默认为 SIGUSR2,用户可以在 `s.Serve` 之前修改这个默认值,比如:
    36  
    37  ```go
    38  import "trpc.group/trpc-go/trpc-go/server"
    39  
    40  func main() {
    41      server.DefaultServerGracefulSIG = syscall.SIGUSR1
    42  }
    43  ```
    44  
    45  ## 注册 shutdown hooks
    46  
    47  用户可以注册进程结束后需要执行的 hook,以保证资源的及时清理,用法如下:
    48  
    49  ```go
    50  import (
    51    trpc "trpc.group/trpc-go/trpc-go"
    52      "trpc.group/trpc-go/trpc-go/server"
    53  )
    54  
    55  func main() {
    56      s := trpc.NewServer()
    57      s.RegisterOnShutdown(func() { /* Your logic. */ })
    58      // ...
    59  }
    60  ```
    61  
    62  假如插件需要在进程结束时进行资源清理操作,可以额外实现 `plugin.Closer` interface,提供 `Close` 方法,这个方法在进程结束时会被框架内部自动调用(调用的顺序为插件 Setup 的逆序):
    63  
    64  ```go
    65  type closablePlugin struct{}
    66  
    67  // Type 和 Setup 是 plugin 需要实现的基本方法
    68  func (p *closablePlugin) Type() string {...}
    69  func (p *closablePlugin) Setup(name string, dec Decoder) error {...}
    70  
    71  // 插件可以选择额外实现一个 Close 方法,用于进程结束后的资源自动清理
    72  func (p *closablePlugin) Close() error {...}
    73  ```