Home > programming > daemon平滑升级

daemon平滑升级

对于socket server来说,平滑升级对于用户体验是一个很好的加分。这样可以不对用户操作造成任何影响。而平滑升级的最直接最核心的应该就是不在升级的过程中关掉listen端口,也不断掉当前的连接,同时还可以接受新的连接,所有的已被接受的请求必须要完整的执行完毕,不能因为升级步骤而终止.

为了到达以上几点,一般来说可以如下来达到平滑升级的目的。
1. 分区域升级。 首先在总控部分,禁掉某些部分server接受新请求的能力。然后等待这些server的当前请求全部执行完毕以后开始升级这些server上的服务。采用这种方法逐步升级所有的server
2. 采用类似nginx的平滑升级的方法。

第一种方法对于那些直接面对客户端的server是行不通的,因为一旦停掉一会儿,客户端就无法正常连接了。还有就是即便是分布式的后台加上一个proxy, 也可能会因为某些特定的请求很难在短时间内完成而无法升级(例如,一个广播流的频道请求),对于这些特定的就需要在指定的维护窗口时间强行升级服务了。
第二种方法看起来比较的容易接受。google了一下nginx的平滑升级的办法。其主要使用到了如下几点技术:

1. 未设置FD_CLOEXEC 属性的文件描述符在fork以后会被child process继承,一般来说除了listen socket和log以外的fd都会设置这个属性
2. 把需要在child process里面使用的文件描述符通过env或者命令行参数在调用execv的时候传入新的process
3. 在启动child process之前,停止accept新的请求。
4. parent process一直服务到所有的请求执行完毕以后正常退出。
5. child process在收到传入的文件描述符(通常是用于listen的那个socket的fd)以后使用这个fd来做accept操作。

这个方法解决了socket连接的平滑升级,但是对于log的问题,我还不是特别肯定。如果parent process和child process都是用同一个log文件的描述符,那么必然会造成打印出的日志是混乱的。当然如果你的日志写入是严格按照一个信息块的方式写入的话(也就是不是几个字节几个自己的写入),而vfs_write又是对inode加锁的,那么虽然会有parent process和child process的日志混杂在一起,但是每一条日志内容本身应该是有完整信息的。(这个还需要核实)。

在这里有相关的测试代码

 

Written with StackEdit.

Categories: programming Tags:
  1. No comments yet.
  1. No trackbacks yet.