Golang的优雅重启
更新(2015年4月):Florian von Bock已将本文中描述的内容转换为一个名为endless的优秀Go包 。
如果您有Golang HTTP服务,可能需要重新启动它以升级二进制文件或更改某些配置。如果你(像我一样)因为网络服务器处理它而优雅地重新启动是理所当然的,你可能会发现这个配方非常方便,因为使用Golang你需要自己动手。
实际上这里有两个问题需要解决。首先是正常重启的UNIX方面,即进程可以在不关闭侦听套接字的情况下自行重启的机制。第二个问题是确保所有正在进行的请求正确完成或超时。
重新启动而不关闭套接字
- fork一个继承侦听套接字的新进程。
- 子进程初始化并开始接受套接字上的连接。
- 紧接着,孩子向父母发送信号,导致父母停止接受连接并终止。
分叉一个新的过程
使用Golang lib分支进程的方法不止一种,但对于这种特殊情况, exec.Command是可行的方法。这是因为此函数返回的Cmd结构具有此ExtraFiles成员,该成员指定要由新进程继承的打开文件(除了stdin / err / out)。
这是这样的:
1 |
|
在上面的代码中netListener是一个指向net.Listener的指针, 用于监听HTTP请求。path如果要升级,变量应该包含新可执行文件的路径(可能与当前运行的路径相同)。
上面代码中的一个重点是netListener.File() 返回 文件描述符的 dup(2)。重复的文件描述符不会设置FD_CLOEXEC标志,这会导致文件在子节点中关闭(不是我们想要的)。
您可能会遇到通过命令行参数将继承的文件描述符编号传递给子项的示例,但ExtraFiles实现的方式 使其不必要。文档指出“如果非零,则条目i变为文件描述符3 + i。”这意味着在上面的代码片段中,子代中的继承文件描述符将始终为3,因此不需要明确地传递它。
最后,args数组包含一个-graceful选项:你的程序需要某种方式通知孩子这是一个正常重启的一部分,孩子应该重新使用套接字而不是尝试打开一个新套接字。另一种方法可能是通过环境变量。
子初始化
这是程序启动序列的一部分
1 |
|
信号父母停止
此时我们已准备好接受请求,但就在我们这样做之前,我们需要告诉我们的父母停止接受请求并退出,这可能是这样的:
1 |
|
正在进行的请求完成/超时
为此,我们需要使用sync.WaitGroup跟踪打开的连接 。我们需要在每个接受的连接上递增等待组,并在每个连接关闭时递减它。
1 |
|
乍一看,Golang标准的http包不提供任何钩子来对Accept()或Close()采取行动,但这就是界面魔法拯救的地方。(非常感谢Jeff R. Allen 对这篇文章的评价)。
下面是一个侦听器示例,它在每个Accept()上递增一个等待组。首先,我们“子类” net.Listener(你会明白我们为什么需要stop和stopped以下):
1 |
|
接下来,我们“覆盖”Accept方法。(gracefulConn暂时没关系,稍后会介绍)。
1 |
|
我们还需要一个“构造函数”:
1 |
|
上面的函数启动goroutine的原因是因为它不能在我们Accept()上面完成,因为它会阻塞 gl.Listener.Accept()。goroutine将通过关闭文件描述符来解锁它。
我们的Close()方法只是发送一个nil停止通道,以便上面的goroutine完成其余的工作。
1 |
|
最后,这个小方便方法从中提取文件描述符net.TCPListener。
1 |
|
当然,我们还需要一个net.Conn减少等待组的变体 Close():
1 |
|
要开始使用上面优雅的Listener版本,我们只需要将server.Serve(l)行更改为:
1 |
|
还有一件事。您应该避免挂断客户端无意关闭的连接(或不是本周)。最好按如下方式创建服务器:
1 |
|
Golang的优雅重启的更多相关文章
- [译]Golang中的优雅重启
原文 Graceful Restart in Golang 作者 grisha 声明:本文目的仅仅作为个人mark,所以在翻译的过程中参杂了自己的思想甚至改变了部分内容,其中有下划线的文字为译者添加. ...
- Golang开发支持平滑升级(优雅重启)的HTTP服务
Golang开发支持平滑升级(优雅重启)的HTTP服务 - tabalt的博客 http://tabalt.net/blog/graceful-http-server-for-golang/ http ...
- Apache 优雅重启 Xampp开机自启 - 【环境变量】用DOS命令在任意目录下启动服务
D:\xampp\apache\bin\httpd.exe" -k runservice Apache 优雅重启 :httpd -k graceful Xampp开机自启动 参考文献:ht ...
- Spring Boot 1.X和2.X优雅重启实战
纯洁的微笑 今天 项目在重新发布的过程中,如果有的请求时间比较长,还没执行完成,此时重启的话就会导致请求中断,影响业务功能,优雅重启可以保证在停止的时候,不接收外部的新的请求,等待未完成的请求执行完成 ...
- apache2 重启、停止、优雅重启、优雅停止
停止或者重新启动Apache有两种发送信号的方法 第一种方法: 直接使用linux的kill命令向运行中的进程发送信号.你也许你会注意到你的系统里运行着很多httpd进程.但你不应该直接对它们中的任何 ...
- golang 服务平滑重启小结
背景 golang 程序平滑重启框架 supervisor 出现 defunct 原因 使用 master/worker 模式 背景 在业务快速增长中,前期只是验证模式是否可行,初期忽略程序发布重启带 ...
- Golang服务器热重启、热升级、热更新(safe and graceful hot-restart/reload http server)详解
服务端代码经常需要升级,对于线上系统的升级常用的做法是,通过前端的负载均衡(如nginx)来保证升级时至少有一个服务可用,依次(灰度)升级. 而另一种更方便的方法是在应用上做热重启,直接更新源码.配置 ...
- Golang学习--平滑重启
在上一篇博客介绍TOML配置的时候,讲到了通过信号通知重载配置.我们在这一篇中介绍下如何的平滑重启server. 与重载配置相同的是我们也需要通过信号来通知server重启,但关键在于平滑重启,如果只 ...
- iota: Golang 中优雅的常量
阅读约 11 分钟 注:该文作者是 Katrina Owen,原文地址是 iota: Elegant Constants in Golang 有些概念有名字,并且有时候我们关注这些名字,甚至(特别)是 ...
随机推荐
- JDK源码之ArrayList
序言 ArrayList底层通过数组实现. ArrayList即动态数组,实现了动态的添加和减少元素 需要注意的是,容量拓展,是创建一个新的数组,然后将旧数组上的数组copy到新数组,这是一个很大的消 ...
- 【十二】jvm 性能调优工具之 jhat (JVM Heap Analysis Tool)
jhat也是jdk内置的工具之一.主要是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言. jhat 非常耗费cpu和内存,所以一般不使 ...
- 什么是CRUD
CRUD是指在做计算处理时的增加(Create).读取查询(Retrieve).更新(Update)和删除(Delete)几个单词的首字母简写.主要被用在描述软件系统中数据库或者持久层的基本操作功能.
- 三十一、Linux 进程与信号——SIGCHLD 信号、kill和raise函数以及alarm函数
31.1 SIGCHLD 信号 子进程状态发生变化(子进程结束)产生该信号,父进程需要使用 wait 调用来等待子进程结束并回收它. 避免僵尸进程 #include <stdio.h> # ...
- Docker 空间大小设置 - 十
一.容器启动 默认存储大小: 1.一种在启动项 docker.service 中配置. 2.在启动项配置调用的 docker-storage 配置文件中配置: 二.Docker 容器默认启动文件: / ...
- Vue项目在表单中限制输入数字
<template> <div> <input v-model="userPhone" autofocus type="text" ...
- 配置mongo
Windows 平台安装 MongoDB MongoDB 下载 MongoDB 提供了可用于 32 位和 64 位系统的预编译二进制包,你可以从MongoDB官网下载安装,MongoDB 预编译二进制 ...
- java 弹出选择目录框(选择文件夹),获取选择的文件夹路径
java 弹出选择目录框(选择文件夹),获取选择的文件夹路径 java 弹出选择目录框(选择文件夹),获取选择的文件夹路径:int result = 0;File file = null;String ...
- AMD/CMD/CommonJs到底是什么?它们有什么区别?
知识点1:AMD/CMD/CommonJs是JS模块化开发的标准,目前对应的实现是RequireJs/SeaJs/nodeJs. 知识点2:CommonJs主要针对服务端,AMD/CMD主要针对浏 ...
- JAVA进阶1
间歇性混吃等死,持续性踌躇满志系列-------------第1天 1.冒泡排序法 import java.util.Arrays; public class SumNum{ public stati ...