Tag Archives: Go

reloader:Go服务热升级支持

以前我在公司写过一个简单的Go热升级支持程序。但是工作时间写的,领导不准开源。后我想另写一个开源版本,但一直没想到解决多端口的问题。后来就慢慢忘却了。 直到最近一次偶然的机会,这个程序被人重新提起。又遇上待业期,正需要写点东西打发时间。突然灵感来了,想到了多端口的解决方案。 于是有了reloader。 思路基本是之前版本的扩展版。一个master进程,多个worker进程,一个worker进程处理一个侦听器。这样可以实现多端口的动态侦听和关闭。我又做了些进程管理的优化,推送到github。 无法否认,我的解决方案存在很多问题,因为偷偷起了多进程。比如程序在所有侦听器和连接都关闭后需要上层逻辑结束,这对于单进程无碍,对于reloader却是可能多了N个垃圾worker进程。这些问题,得等待找到更好的解决方案。

Posted in Uncategorized | Tagged | Leave a comment

实现golang程序热升级

更新:已实现一个开源版本reloader。 简单定义热升级就是:让运行中的服务改为执行新的程序代码逻辑,且不中断服务。 目前现有的开源热升级程序主要有endless,和beego的grace组件。 经过测试,grace在热升级时,会掐掉当前处理中的连接,自然无法接受。endless的问题在于每次热升级都是创建子进程后,原进程就退出了,这点显然不符合守护进程的要求。 于是自己实现个新的。逻辑参考了endless。其实endless和grace也是相互“借鉴”,相互copy了很多代码。我在“借鉴”时,力求逻辑尽可能简单,自己编写全部代码,并后续完善一些关键细节。 首先要解决多个进程监听同一地址+端口。我首先想到的是nginx、node.js的端口复用方案。但golang尚不支持端口复用。好在golang支持文件描述符和listener的互转,和文件描述符的继承。方案为主进程创建listener,取得文件描述符,子进程再继承listener文件描述符。 新进程应该执行新程序的逻辑。要实现这点,就不能用fork,不然新进程还是执行旧的程序逻辑。 支持守护进程。这点是我重新实现热升级的关键。endless和grace的逻辑是,创建子进程,然后原进程退出。我的方案是一个master进程,一个worker进程。每次只升级worker进程。 master进程与worker进程在外部看起来应该是一体的。这里沿袭了erlang任其崩溃的思想,一个退出,另一个跟随。如果worker进程退出码非0,master进程以相同的退出码结束。 还有很重要的一点,退出worker进程,首先关闭listener,一并关闭listener关联的文件描述符,再等待所有连接关闭。 支持自动升级。这个不是很必要,以后再说。 相比endless,我的实现的另一个优势是:只提供listener接口,而不是ListenAndServe函数。也就是该实现不仅支持http/https,同时支持其它基于tcp的应用层协议,比如grpc。

Posted in Uncategorized | Tagged | 5 Comments