微服务优雅停机研究
什么叫优雅停机?
—— 每个服务节点上新的服务部署包下载完成后,就要停止当前运行的服务进程,部署新版本服务。
在停止服务时,由于服务上有正在运行的请求,需要等待这些请求处理完毕,同时不让新的请求进来,这就是所谓的“优雅停机”。
我们公司用的服务注册中心是阿里的nacos,有篇文章能通过设置流量权重能实现:https://nacos.io/zh-cn/docs/console-guide.html
其中要注意下:
Nacos提供对服务进行上下线的功能,这只会标记服务不可用,与Spring Cloud的应用的UP/DOWN状态类似。并不会停止服务的进程,当新服务上线之后,还需要到服务器上关闭进程,不是很方便。(引用文章:https://blog.csdn.net/suxingrui/article/details/103795148 )
测试优雅上下线整个过程
首先我声明一下,这个只是我这边运维成功测试通过,并不表示实际就是这样配置,因为开发没空给我调试:模拟用户当表单填写进行到一半的时候,服务突然升级是否会转移到新节点?
所以这个仅仅是我的研究过程,大家请三思而后行,思路可以参考下。
一、前言
假设两台机器:
A(ljy123)是正式服务器,平时由它对外提供服务
B(ljy456)是临时服务器,只有在A发布时临时提供服务。目的:不影响业务中断,继续处理已经过来的表单请求
当A升级完之后,B下线,A重新提供服务。
二、测试流程
1、原来A每个微服务只有一个服务实例,
中台服务middle和网关gateway,都只有1个实例数,目前处于健康状态
2、发布B服务器上的服务,作为临时提供服务用
配置一个jenkins服务发布:仅仅用来发布B服务器上的两个服务,什么都不需要判断
发布完后,每个微服务就有两个实例,如下图(程序会自动注册到nacos上的)
3、运行发布A
前提查到 B服务器上已经上线了对应的服务:middle和gateway
这个时候需要调用nacos的接口,获取当前jar包服务信息,我贴下关键的jenkins配置信息(Pre Steps的执行shell步骤里)
1 #1、调用nacos接口,获取当前jar包服务信息 2 serviceinfo=`curl -X GET https://cluster.ljytest.com/nacos/v1/ns/instance/list?serviceName=$DEPLOY_SERVICE` 3 4 #2、获取jar包服务实例 5 Binstance=`echo "${serviceinfo}" | awk -F"[,}]" '{for(i=1;i<=NF;i++) { if($i~/instanceId/ && /B机器上的ip/) {print $(i)}}}'` 6 7 if [[ "$Binstance" = "" ]] 8 then 9 echo "B机器上没有提供服务:$DEPLOY_SERVICE,为了不中断,不能发布A机器上的服务......." 10 exit 1 11 fi 12 13 14 Bhealthline=`echo "${serviceinfo}" | awk -F"[,}]" '{for(i=1;i<=NF;i++) { if($i~/instanceId/ && /B服务器上的ip/) {print $(i+2)}}}'` 15 16 healthjudge=`echo $Bhealthline | grep "true"` 17 18 ### 判断不在线,不发布 19 if [[ "$healthjudge" = "" ]] 20 then 21 echo "B机器上没有提供服务:$DEPLOY_SERVICE,为了不中断业务,不能发布A机器的服务......." 22 exit 1 23 fi 24 25 done 26 27 28 echo "开始发布A机器的服务......."
##### 测试B机器没有提供服务,A机器不发布
1、B机器发布服务
middle中台服务是8200端口
2、A机器发布服务
两种情况
(1)B机器注册了服务,A机器可以下线发布
(2)B机器没有注册服务到nacos,A机器不可以下线发布!!!
假设B机器的middle服务没有注册上去,测试A是否能发布(注意上图,我把middle服务进程号干掉了)
B机器middle服务不存在,nacos页面红色一栏表示
jenkins报错,不能发布
注意:任意一个服务只要B机器没有上线,就会终止jenkins发布服务的
3、下线临时B服务器,重新让A提供服务
因为前面提到,下线只是nacos的一个标记,实际是需要登录服务器进行服务关停的
调nacos接口进行扫描 ——》 筛选服务健康值 ——》 进行发布/不发布
1 cd /home/ljy/micro_service/jar_tmp 2 cat dst/nacosservice | while read line 3 do 4 stopservice=$line 5 #1、调用nacos接口,获取当前jar包服务信息 6 serviceinfo=`curl -X GET https://cluster.ljytest.com/nacos/v1/ns/instance/list?serviceName=$stopservice` 7 8 #2、获取A上jar包服务实例 9 Binstance=`echo "${serviceinfo}" | awk -F"[,}]" '{for(i=1;i<=NF;i++) { if($i~/instanceId/ && /A机器IP/) {print $(i)}}}'` 10 11 if [[ "$Binstance" = "" ]] 12 then 13 echo "A没有提供服务,为了不中断,不能下线B的$serviceName......." 14 exit 1 15 fi 16 17 #3、获取A上jar包服务实例是否在线 18 Bhealthline=`echo "${serviceinfo}" | awk -F"[,}]" '{for(i=1;i<=NF;i++) { if($i~/instanceId/ && /A机器IP/) {print $(i+2)}}}'` 19 20 healthjudge=`echo $Bhealthline | grep "true"` 21 22 23 ### 判断A机器服务不在线,就不下线B机器的服务 24 if [[ "$healthjudge" = "" ]] 25 then 26 echo "A没有提供服务:$serviceName,为了不中断,不能下线B的服务......." 27 exit 1 28 fi 29 30 echo "开始下线B的服务......." 31 32 #4、调nacos下线接口 33 curl -X POST 'https://cluster.ljytest.com/nacos/v1/ns/instance?serviceName='$stopservice'&port=8200&ip=10.0.0.126&enabled=false&metadata={preserved.register.source=SPRING_CLOUD}' 34 35 sleep 5 36 37 #5、关临时B机器的服务 38 cat dst/outfiles| while read line 39 do 40 41 ps -ef | grep java | grep "$line" | grep -v grep |awk '{print $2}' | xargs kill -9 42 43 done 44 45 done
jenkins日志(反正curl之后的结果要处理一波的,最终获取一个Bhealthyline的变量值,大家实践下就知道了