golang应用平滑重启

平滑重启:

在当前的软件系统中,在不关闭服务的情况下部署一个新的版本或者是修改一些配置信息已经成为了必备的要求。这里介绍不同的方法去平滑重启应用,同时用些实例去挖掘其中的细节信息。这里通过介绍Teleport来展开,Teleport是为Kubernetes权限控制而设计的,对于不熟悉的可以查看这个链接https://gravitational.com/teleport/SO_REUSERPORT vs Duplicating Sockets:

为了Teleport更加高可用,我们最近花费了一些时间如何去平滑重启Teleport的TLS和SSH的监听者,我们的目标是在不生成一个新的实例的情况下去升级Teleport的包。

两种通用的实现方法在这篇文章中有介绍,https://blog.cloudflare.com/the-sad-state-of-linux-socket-balancing,其方法大概就是这样:

》你可以在使用socket时设置 SO_REUSERPORT ,这样就允许多个进程绑定同一个端口,采用这种方法时每个进程都有一个对应的接收处理队列。

》你也可以复用socket,通过将其传递给子进程的方式来使用,这种方式就是多个进程共用一个接收队列。

对于SO_REUSERPORT有一些负面的影响,一个是我们的工程师以前用过这种方式,这种多个接收队列的方式有时会导致tcp连接的中断。另外 Go不容易去设置SO_REUSERPORT这个参数。

第二种方法由于大部分开发者都比较熟悉其简单的unix fork/exec模型 反而是比较吸引的。这种方式可以把所有的文件描述符都传递给子进程,不过在go中 os/exec包目前是不允许这样的,可能是因为安全问题,只能传递 stdin stdou和stderr给子进程。但是os包有比较底层的包可以传递所有的文件描述符给子进程,而这正是我们要做的。信号控制进程切换:

在讲正式的源码前,先说下这种方式工作的细节信息。

开始一个新的Teleport进程时会创建一个socket listener,其会接收发送给目的端口的所有traffic。我们增加一个信号处理函数来处理 SIGUSR2,这个信号可以使Teleport复制一份lisenter socket然后传递的文件描述符和其环境变量的元数据信息生成一个新的进程。一旦一个新的进程开始,就使用前面传递过来的文件描述符合元素开始改造socket并开始处traffic。

这里应该注意下 socket被复用后,两个socket是循环均衡的处理traffic,具体可以查看下面的图。这意味这Teleport进程每一段时间将接受新的连接。

父进程(PID2))的关闭方式是一样的,只是顺序反过来。一旦一个Teleport进程接收了SIGOUT信号将会开始关闭进程,其流程:先停止接收新连接,然后等待所有连接退出。然后父进程将关闭它自己的listener socket并退出。现在内核只发送traffic给新的进程了。

实例:

我们使用这种方法写了一个小应用。源代码在底部。首先我们来编译然后开始应用:

$ go build restart.go
$ ./restart &
[1] 95147
$ Created listener file descriptor for :8080.
 $ curl http://localhost:8080/hello
Hello from 95147! 

发送USR2信号给原始进程,现在你点击发送http请求时,将会返回两个进程的pid号:```

$ kill -SIGUSR2 95147

user de

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值