Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >服务器无损升级技术解析

服务器无损升级技术解析

作者头像
用户1215536
发布于 2023-10-16 08:45:28
发布于 2023-10-16 08:45:28
27600
代码可运行
举报
运行总次数:0
代码可运行

声明:本人原创文章,详细内容已发布在我的微信个人技术公众号---网络技术修炼,公众号总结普及网络基础知识,包括基础原理、网络方案、开发经验和问题定位案例等,欢迎关注。

概述

软件工程中持续迭代和更新是必不可少的,在服务端软件更新时,保持服务的连续性是一项关键任务。本文将从技术角度解析服务端软件更新过程如何实现不停止服务的重要功能。

在进行热升级时,进程的代码和数据都是非常重要的。为了实现代码的更新,同时又不丢失有用的数据,需要采取一些措施。有用的数据包括内存中的数据和文件描述符。对于内存中的数据,例如配置信息,可以通过将其落盘到配置文件中来实现保留。这样,在升级过程中,新的进程可以读取配置文件并继续使用之前的配置。而对于文件描述符,可以采用一种叫做UNIX域套接字的机制,在进程之间进行迁移。通过这种方式,新进程可以接管原来进程的文件描述符,从而保持之前打开的文件和网络连接的状态。在某些情况下,项目可能会选择不迁移文件描述符,而是通过让新旧进程共同处理一段时间的请求来逐步过渡。这样,新进程可以逐渐接收和处理新的请求,而老进程则继续处理旧的请求,直到所有请求都由新进程处理完毕。

另外,为了减轻对客户端的影响,还可以采用一些HTTP协议的特性。例如,在HTTP1中可以使用"Connection: Close"头部字段,告知客户端断开连接并重新连接。而在HTTP2中,可以使用Goaway帧来类似地通知客户端断开连接。这样一来,客户端就能够及时与新进程建立新的连接,以继续进行请求和响应的处理。

通过这些措施和优化方法,可以实现热升级过程中代码更新和数据保留的目标,并尽可能减少对系统和客户端的影响。

详解

通过fork + execve实现无损升级

典型项目

nginx

nginx为例解析

交互流程
  • 先不停掉老进程,启动新进程。
  • 老进程继续处理仍然没有处理完的请求,但不再接受新请求。
  • 新进程接受新请求。
  • 老进程处理完所有存量请求,关闭所有连接,退出。
信号支持

官方文档:http://nginx.org/en/docs/control.html

nginx中master进程为管理进程,woker进程为master进程fork出的子进程,是处理网络的进程。

master进程支持的信号

TERM,INT

快速退出

QUIT

优雅退出master+worker进程(worker进程处理完存量请求再退出)

KILL

强子终止进程

HUP

使用新的的配置启动worker进程,并优雅退出老的worker进程

USR1

重新打开日志文件

USR2

升级可执行文件(即启动新的master进程)

WINCH

优雅退出woker进程

worker进程支持的信号:

TERM,INT

快速退出

QUIT

优雅退出(处理完存量请求再退出)

USR1

重新打开日志文件

实验
  • 更新前进程状态查看。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ps -ef | grep nginx
root      82556      1  0 11:58 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     82562  82556  0 11:58 ?        00:00:00 nginx: worker process
nginx     82563  82556  0 11:58 ?        00:00:00 nginx: worker process
nginx     82564  82556  0 11:58 ?        00:00:00 nginx: worker process
nginx     82565  82556  0 11:58 ?        00:00:00 nginx: worker process
nginx     82566  82556  0 11:58 ?        00:00:00 nginx: worker process
nginx     82567  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82569  82556  2 11:58 ?        00:00:03 nginx: worker process
nginx     82570  82556 14 11:58 ?        00:00:24 nginx: worker process

#cat /app/nginx/logs/nginx.pid
82556
可以看出nginx.pid记录的是当前master的进程号。
  • 将旧Nginx二进制换成新Nginx二进制(注意备份旧二进制)。
  • 向master进程发送USR2信号。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
kill -USR2 `cat /app/nginx/logs/nginx.pid`

执行后结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ps -ef | grep nginx
root      82556      1  0 11:58 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     82562  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82563  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82564  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82565  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82566  82556  0 11:58 ?        00:00:01 nginx: worker process
nginx     82567  82556  0 11:58 ?        00:00:02 nginx: worker process
nginx     82569  82556  2 11:58 ?        00:00:06 nginx: worker process
nginx     82570  82556 13 11:58 ?        00:00:43 nginx: worker process
root      85710  82556  0 12:04 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     85716  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85717  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85718  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85719  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85720  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85721  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85723  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85724  85710  0 12:04 ?        00:00:00 nginx: worker process

#cat /app/nginx/logs/nginx.pid
85710
可以看出nginx.pid已经变成新master进程号

#cat /app/nginx/logs/nginx.pid.oldbin
82556
nginx.pid.oldbin存放老master进程号。
  • 向老master进程发送WINCH信号。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
kill -WINCH `cat /app/nginx/logs/nginx.pid.oldbin`
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ps -ef | grep nginx
root      82556      1  0 11:58 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     82569  82556  1 11:58 ?        00:00:06 nginx: worker process is shutting down
nginx     82570  82556 11 11:58 ?        00:00:43 nginx: worker process is shutting down
root      85710  82556  0 12:04 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     85716  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85717  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85718  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85719  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85720  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85721  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85723  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85724  85710  0 12:04 ?        00:00:00 nginx: worker process

此过程要不停有请求访问到nginx才能看到worker优雅退出过程,一段时间后存量请求全部处理完毕。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ps -ef | grep nginx
root      82556      1  0 11:58 ?        00:00:00 nginx: master process ./sbin/nginx
root      85710  82556  0 12:04 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     85716  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85717  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85718  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85719  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85720  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85721  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85723  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85724  85710  0 12:04 ?        00:00:00 nginx: worker process
  • 检查是否回滚
    • 一段时间后,老woker请求全部处理完,就变成了新老master、新worker共存,此时老master并没有关闭listen sockets,如果新二进制有问题还有办法回滚。
    • 回滚方法:
    • 方法1
    • 向老master发送HUP信号。
    • 老master收到HUP信号会创建worker进程。
    • 向新master发送QUIT信号。
    • 新master收到QUIT会退出所有新worker和新master进程。
    • 方法2
    • 向新master发送TERM信号。
    • nginx新进程收到这个信号,对应master和worker会退出,同时老master会创建出老worker继续工作。
  • 如果不需要回滚,向老master发送QUIT信号。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
kill -QUIT `cat /app/nginx/logs/nginx.pid.oldbin`
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#ps -ef | grep nginx
root      85710      1  0 12:04 ?        00:00:00 nginx: master process ./sbin/nginx
nginx     85716  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85717  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85718  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85719  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85720  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85721  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85723  85710  0 12:04 ?        00:00:00 nginx: worker process
nginx     85724  85710  0 12:04 ?        00:00:00 nginx: worker process
源码

nginx信号处理函数:ngx_signal_handler

unix domain sockets

典型项目

envoy

mosn

原理概括

linux环境可以使用下面函数在进程间传递fd。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

mosn为例解析

交互流程

ps:下面代码均以v1.5.0版本为例。

listen fd迁移

涉及Domain Socket:

reconfig.sock记录老进程的监听

listen.sock记录新进程的监听

流程:

  • 老进程启动时候会执行ReconfigureListener函数,这里面监听reconfig.sock并通过写一个字节(uc.Write([]byte{0}))阻塞,直到有新进程启动并执行read才会继续往下执行。
  • 新进程init-->inheritConfig-->IsReconfigure通过uc.Read(buf)触发老进程执行reconfigure流程。
  • 老进程通过reconfig.sock向新进程发送fd。

ReconfigureHandler

sendInheritListeners:老进程将已经存在的 fd 通过 listen.sock 发送给新进程。

shutdownServers:老进程不再接收新连接,并优雅关闭。

WaitConnectionsDone:处理完存量请求后退出。

  • 新进程接收老进程的fd并处理:GetInheritListeners。
长连接迁移

涉及Domain Socket:conn.sock

流程:

  • 新进程启动一个协程运行TransferServer,将监听conn.sock。
  • 老进程通过transferRead和transferWrite进入长链接迁移过程。

参考文档

nginx官方文档:http://nginx.org/en/docs/control.html

MOSN 平滑升级原理解析:https://mosn.io/docs/products/structure/smooth-upgrade

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
生产环境 Nginx 在线平滑升级
生产环境 Nginx 需要增加支持 TCP 反向代理功能,需要再添加--with-stream参数重新编译后,在线升级 Nginx。
叨叨软件测试
2020/12/02
2.1K0
Nginx 基本使用
前面在提到 Nginx 的高性能,其实也和它的架构模式有关。Nginx 默认采用的是多进程的方式来工作的,当将 Nginx 启动后,我们通过 ps -ef | grep nginx 命令可以查看到如下内容:
用户9615083
2022/12/25
4290
Nginx 基本使用
Nginx平滑升级
按照原来的编译参数安装 nginx 的方法进行安装,只需要到 make,千万不要 make install
Cyylog
2020/08/19
1.3K0
Nginx平滑升级源码分析
一、平滑升级步骤 1、重命名之前的sbin/nginx文件,将新的nginx文件放到sbin/目录下 #mv ./sbin/nginx ./sbin/nginx.old #cp ~/nginx ./sbin/ 2、向正在运行的nginx发送USR2信号启动新的nginx,这个时候新老nginx都会接收请求,看那一个进程能抢到锁,抢到锁的worker进程可以accpet新请求 #kill -USR2  `cat nginx.pid` 3、观察新的nginx运行无误后,向旧nginx发信号 停止旧nginx的运
magicsoar
2018/02/06
1.3K0
Nginx平滑升级源码分析
Nginx-3.控制nginx
master进程id在默认写入到/nginx/logs/nginx.pid文件中。文件也可以在nginx.conf文件中指定。master进程支持以下信号:
_淡定_
2020/02/26
7800
Nginx在线服务状态下平滑升级或新增模块的详细操作记录
今天,产品那边发来需求,说有个 APP 的 IOS 版本下载包需要新增 https 协议,在景安购买了免费的 SSL 证书。当我往 nginx 上新增 ssl 时,发现服务器上的 nginx 居然没编译 SSL 模块! 看了下旧版本 nginx 的 configure 选项: linux-gz215:# /usr/local/sbin/nginx -V nginx version: nginx/1.0.11 built by gcc 4.1.2 20070115 (prerelease) (SUSE Lin
张戈
2018/03/23
1.9K1
又拍云tokers-谈谈 nginx 信号集
昨天下午的时候,一台引流测试机器的一个 ngx_lua 服务突然出现了一些 HTTP/500 响应,从错误日志打印的堆栈来看,是不久前新发布的版本里添加的一个 Lua table 不存在,而有代码向其进行索引导致的。这令人百思不得其解,如果是版本回退导致的,那么为什么使用这个 Lua table 的代码没有被回退,偏偏定义这个 table 的代码被回退了呢?
用户2825413
2019/07/15
6680
nginx平滑升级编译headers-more模块
不想暴露某些服务器信息的时候,需要自定义response头信息,可以去修改nginx的源码,或者编译的时候,加上headers-more这个模块.
用户1168904
2021/07/20
9820
初识Nginx
Nginx提供的基本功能服务从大体上归纳为”基本HTTP服务”、“高级 HTTP服务”和”邮件服务”等三大类。
用户11097514
2024/05/31
930
初识Nginx
如何关闭nginx服务_如何启动nginx
Nginx安装完成后,接下来我们要学习的是如何启动、重启和停止Nginx的服务。对于Nginx的启停在linux系统中也有很多种方式,我们本次课程介绍两种方式:
全栈程序员站长
2022/09/22
2.8K0
如何关闭nginx服务_如何启动nginx
Nginx架构基础
Nginx其实有两种进程结构,一种是单进程结构,一种是多进程结构。单进程结构只适合我们做开发调试,在生产环境下,为了保持 Nginx 足够健壮,以及可以利用到 CPU 的多核特性,我们用到的是多进程架构的Nginx。
mazhen
2023/11/24
2320
Nginx架构基础
【Nginx】初识与环境准备
单次请求或者高并发请求的环境下,Nginx都会比其他Web服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求),Nginx比其他Web服务器更快的响应请求。Nginx之所以有这么高的并发处理能力和这么好的性能原因在于Nginx采用了多进程和I/O多路复用(epoll)的底层实现。
十八岁讨厌编程
2022/12/10
5310
Nginx 平滑升级
随着 Nginx 越来越流行,Nginx 的版本迭代也越来越频繁,当我们需要使用某些新版本的特性或者修复某个旧版本的 BUG 时,就要对 Nginx 进行升级。然而线上业务大多是 7*24 小时不间断运行的,我们需要在升级的时候保证不影响在线用户的访问。Nginx 的热升级功能可以解决上述问题,它允许新老版本灰度地平滑过渡,这受益于 Nginx 的多进程架构。
Se7en258
2021/07/01
1.5K0
nginx+lua学习
1. nginx+lua学习 1.1. 网关架构 1.2. nginx命令和信号控制 nginx -s stop 快速关闭,不管有没有正在处理的请求 nginx -s quit 优雅关闭方式,推出前完
老梁
2019/09/10
1.3K0
nginx+lua学习
基于centos7安装部署nginx
WEB服务器主要功能是提供网上信息浏览服务。目前我们上网浏览信息,都是由不同的web服务器提供的,企业通常都会有自己的门户网站,所以对于web服务器的掌握也是至关重用。下面我们可以熟悉下常见的web服务器有哪些。
运维朱工
2021/11/28
1.3K2
基于centos7安装部署nginx
nginx基础19
原文地址http://soft.dog/2015/10/09/nginx-basic/
franket
2022/05/12
8870
nginx基础17
使用新版本Nginx测试配置 [root@h102 sbin]# ./nginx -t -c /usr/local/nginx/conf/nginx.conf nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@h102 sbin]# 平滑替
franket
2022/05/12
2080
Nginx----安装和配置文件参数详解
Nginx(“engine x”)一个具有高性能的【HTTP】和【反向代理】的【WEB服务器】,同时也是一个【POP3/SMTP/IMAP代理服务器】,是由伊戈尔·赛索耶夫(俄罗斯人)使用C语言编写的,Nginx的第一个版本是 2004年10月4号发布的0.1.0版本。
大忽悠爱学习
2021/12/08
2.5K0
Nginx----安装和配置文件参数详解
Nginx 热部署和日志切割,你学会了吗?
上篇文章,我们已经安装好 Nginx,并且配置好 Nginx 文件后,这个时候我就需要操作 Nginx 的命令行了,这篇文章主要讲解 Nginx 命令行相关知识,并通过日常遇到的热部署、切割日志文件场景来熟悉 Nginx 命令行操作。
武培轩
2019/11/04
4270
Nginx 热部署和日志切割,你学会了吗?
重识Nginx - 05 热部署_不停机更换新版本的nginx
说明: linux 的 kill 命令是向进程发送信号,kill 不是杀死的意思,-9 表示无条件退出,但由进程自行决定是否退出,这就是为什么 kill -9 终止不了系统进程和守护进程的原因
小小工匠
2022/10/04
8560
重识Nginx - 05 热部署_不停机更换新版本的nginx
相关推荐
生产环境 Nginx 在线平滑升级
更多 >
LV.1
这个人很懒,什么都没有留下~
作者相关精选
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验