应用在虚机和容器场景下如何优雅上下线

在生产场景中部署的服务提供者常因业务升级或其他场景需要下线和上线的部署操作,本文总结了应用在上下线过程中会遇到的典型问题,并思考在虚机和容器场景该如何处理这些问题,规避该过程中可能出现的服务消费者的请求失败,实现应用的优雅上下线。

一、微服务应用上 / 下线发布过程中存在的问题

在应用上下线发布过程中,如何做到流量的无损上 / 下线,是一个系统能保证 SLA 的关键。如果应用上下线不平滑,就会出现短时间的服务调用报错,比如连接被拒绝、请求超时、没有实例和请求异常等问题。

1.1 上线过程中的问题

在应用上线发布过程中,由于过早暴露服务,实例可能仍处在 JVM JIT 编译或者使用的中间件还在加载,若此时大量流量进入,可能会瞬间压垮新起的服务实例。我们在实际场景中,曾经遇到 provider 服务启动后,但是数据库连接出现异常,未做好启动前的资源准备,导致该 provider 服务在注册中心暴露后 DB 异常还未修复,无法正常提供被 consumer 调用的能力,导致大量请求异常返回。如下图日志所示,应用初始化时,DB 连接失败(该服务对 DB 是弱依赖)。

1.2 下线过程中的问题

在应用下线过程中,服务消费者感知服务提供者下线有延迟,在一段时间内,被路由到已下线服务提供者实例的请求都抛连接被拒绝异常。其次服务实例在接收到 SIGKILL 信号时,会立即关闭,但是这时候可能在请求队列中存在一部分请求还在处理,如果立即关闭这些请求都会损失掉。实际应用中,我们在环境上部署了 provider 的唯一一个实例,该服务被 consumer 调用,然后再执行 kill -9 强杀应用 provider 的唯一实例后,服务进程实际上已经被终止,但是服务的注册信息还会在注册中心(该场景使用的是 ServiceComb)保留一段时间,未及时清除,如下图所示。若此时消费者服务 consumer 调到该实例会报连接拒绝错误。因为消费者 consumer 服务还能发现该实例,获取其 IP 和端口尝试去调用,但是该 provider 服务实例其实已经被销毁了。

二、如何处理应用上 / 下线问题

那么有哪些优化措施,可以减少应用上 / 下线中流量的损失?

2.1 处理应用上线问题

应用上线发布主要问题是:其中一个原因是注册太早,过早的暴露了服务;另一个原因是一些应用初始化缓慢,若遇到大量流量,应用容易宕机。可以采取以下优化措施:

  • 延迟注册 :微服务应用可以采用延迟注册的方式,即在应用启动之后一定时间再进行注册。这样可以确保应用完全就绪后再注册,避免了服务未就绪就被外部访问的情况。

  • 健康检查 :微服务应用可以实现健康检查接口,通过该接口可以检查服务是否就绪。注册中心可以通过定期调用该接口来判断服务是否可以对外提供服务,从而避免了服务未就绪就被外部访问的情况。

  • 预热 :对新实例进行预热,而不是突然将所有流量转移到新实例上,从而避免新实例遇到大量流量,应用容易宕机的情况。

  • 启动优化 :对于整个服务启动的过程,可以进行一些优化措施,比如减少不必要的依赖、调整启动顺序等,从而加快服务启动速度。

2.2 应用合理的上线过程

合理的应用上线大致分为这样一个过程:当应用启动后,通过设置延迟注册时间(服务对外暴露的时间)确保应用多久后可提供服务,其次可依赖平台检查服务的就绪状态(比如 K8S 的就绪探针)确保服务对外提供服务为就绪状态,然后通过预热对刚启动应用进行保护,确保流量慢慢进入刚启动的应用,最后流量逐渐增到正常情况。

2.3 处理应用下线问题

应用下线过程最主要问题是:消费者应用无法及时感知到注册中心列表的刷新,导致可能还有新流量访问下线应用。可以采取以下优化措施:

  • 减少注册中心缓存时间 :将注册中心中服务列表的缓存时间缩短,可以使消费者应用更快地获取到服务列表的最新信息。这样可以减少因服务列表缓存而导致的访问下线应用的流量。

  • 实时性优化 :在服务消费者和注册中心之间使用长连接、实时通知等机制,从而能够实时获取注册中心中服务列表的变化。

  • 实现熔断机制 :在消费者应用中实现熔断机制,当某个服务实例出现故障或不可用时,可以快速切换到其他可用的服务实例。这样可以避免将流量发送到已下线的应用程序上,并确保消费者应用的可用性。

2.4 应用合理的下线过程

合理的应用下线大致分为这样一个过程:当应用接受到外部的关闭(停止服务)请求后,不能在接收新的业务请求,但是会存在一些正在处理的业务请求,需等这些请求处理完后再销毁应用使用的资源,最后就可以通知主进程退出。

三、应用下线注意点

针对应用下线在虚机场景和容器场景需要关注一些注意点。

3.1 虚机场景

当我们要关闭虚拟机应用时,我们一般会使用 ps -ef | grep xxx 查找到进程 ID,然后再执行 kill -9 PID 操作。

kill 命令使用科普 :

  • kill -9, 系统会发出 SIGKILL(9)信号,由操作系统内核完成杀进程操作,该信号不允许忽略和阻塞,应用程序会 立即终止(强制杀死)。

  • kill -15,默认使用信号,系统向应用发送 SIGTERM(15)信号,给目标进程一个清理善后工作的机会是一种优雅终止进程的方式,告诉进程需要停止运行并开始清理资源。

因为 kill -9 PID 会强制杀死应用,以合理的应用下线流程看,应需处理完相关旧业务请求,清理相关资源后再退出进程,所以当要关闭虚拟机应用时,请执行 kill PID—— 以优雅的方式停止运行。

3.2 容器场景

Kubernetes 目前是业界容器编排领域的事实标准,业界一般默认都是用 K8S 来管理容器。K8S 提供了 Pod 优雅退出机制,允许 Pod 在退出前完成一些清理工作。preStop 会先执行完,然后 K8S 才会给 Pod 发送 TERM 信号。在容器场景利用 K8S 提供的 preStop 机制,配合延迟下线 API 使用,这样就能保证流量的无损下线。

...
spec:
 containers:
 - name: lifecycle-demo-container
 image: nginx
 lifecycle:
 preStop:
 exec:
 command: ["/bin/sh","-c","to do xxx; do sleep 30; done"]
...

(1)为什么容器应用(K8S 环境)要配置 preStop?首先要介绍一下 Pod 的终止过程。

参考: https://kubernetes.renkeju.com/chapter_4/4.5.5.pod_termination_process.html

  1. 用户发送删除 Pod 对象的命令。

  2. API 服务器中的 Pod 对象会随着时间的推移而更新,在宽限期内(默认为 30 秒),Pod 被视为 “dead”。

  3. 将 Pod 标记为 “Terminating” 状态。

  4. (与第 3 步同时运行)kubelet 在监控到 Pod 对象转为 “Terminating” 状态的同时启动 Pod 关闭程序。

  5. (与第 3 步同时运行)端点控制器监控到 Pod 对象的关闭行为时将其从所有匹配到此端点的 Service 资源的端点列表中移除。

  6. Pod 对象中的容器进程收到 TERM 信号。

  7. 如果当前当前 Pod 对象定义了 preStop 钩子处理器,则在其标记为 “Terminating” 后即会以同步的方式启动执行;如若宽限期结束后,preStop 仍未执行结束,则第 2 步会被重新执行并额外获取一个时长为 2 秒的小宽限期。

  8. 宽限期结束后,若存在任何一个仍在运行的进程,那么 Pod 对象即会收到 SIGKILL 信号。

  9. kubelet 请求 API Server 将此 Pod 资源的宽限期设置为 0 从而完成删除操作,它变得对用户不在可见。

默认情况下,所有删除操作的宽限期都是 30 秒,不过,kubectl delete 命令可以使用 “--grace-period=” 选项自定义其时长,若使用 0 值则表示直接强制删除指定的资源,不过,此时需要同时为命令使用 “--force” 选项。

从上述 Pod 终止过程的时序图可知,关闭 Pod 流程(关注红色框),给 Pod 内的进程发送 TERM 信号 (即 kill, kill -15),如果配置了 preStop 钩子也会同时处理,最后宽限期结束后,若存在任何一个仍在运行的进程,那么 Pod 对象即会收到 SIGKILL(kill-9)信号 。

(2) 存在这样一种情况 Pod 中的业务进程接受不到 SIGTERM 信号

存在这样一种情况 Pod 中的业务进程接受不到 SIGTERM 信号(而且没有配置 preStop 钩子),等待一段时间业务进程直接被 SIGKILL 强制杀死了。

为什么业务进程接受不到 SIGTERM 信号?

通常都是因为容器启动入口使用了 shell,比如使用了类似 /bin/sh -c my-app 或 /docker-entrypoint.sh 这样的 ENTRYPOINT 或 CMD,这就可能就会导致容器内的业务进程收不到 SIGTERM 信号,原因是:

  1. 容器主进程是 shell,业务进程是在 shell 中启动的,成为了 shell 进程的子进程。

  2. shell 进程默认不会处理 SIGTERM 信号,自己不会退出,也不会将信号传递给子进程,导致业务进程不会触发停止逻辑。

  3. 当等到 K8S 优雅停止超时时间 (terminationGracePeriodSeconds,默认 30s),发送 SIGKILL 强制杀死 shell 及其子进程。

(3) 如何解决上述 Pod 中的业务进程接收不到 SIGTERM 信号问题

  1. 配置 preStop 钩子(K8S 场景),处理退出前完成一些清理工作,比如使用无损上下线插件的应用服务需在停止前通知实例进行下线。

  2. 如果可以的话,尽量不使用 shell 启动业务进程。

  3. 如果一定要通过 shell 启动,比如在启动前需要用 shell 进程一些判断和处理,或者需要启动多个进程,那么就需要在 shell 中传递下 SIGTERM 信号了。  

  参考: https://imroc.cc/k8s/faq/why-cannot-receive-sigterm/

所以容器应用(K8S 环境)要配置 preStop,在停止前通知实例进行下线,加了一层防护,保证 Pod 中的业务能优雅的结束。

四、Sermant 如何解决应用上 / 下线问题

针对应用上下线发布过程中的问题,Sermant 插件提供预热和延迟下线机制,为应用提供无损上下线的能力。预热是无损上线的核心机制,延迟下线是无损下线的核心机制,而且为了无损上线,还做了延迟注册机制。

4.1 上线问题的解决方式

  • 延迟注册 : 若服务还未完全初始化就已经注册到注册中心提供给消费者调用,很有可能因资源为加载完成导致请求报错。可以通过设置延迟注册,让服务充分初始化后再注册到注册中心对外提供服务。

  • 预热 :是基于客户端实现的,当流量进入时,Sermant 会动态调整流量,根据服务的预热配置,对流量进行动态分配。对于开启服务预热的实例,在刚启动时,相对于其他已启动的实例,分配的流量会更少,流量将以曲线方式随时间推移增加直至与其他实例近乎持平。目的是采用少流量对服务实例进行初始化,防止服务崩溃。 4.2 下线问题的解决方式

上图描述了 Sermant 是如何解决服务下线问题的: 0. 微服务应用 consumerA、providerA、consumerB、providerB 携带 Sermant 启动,并将相关 ip:port 等信息注册到注册中心;

  1. 微服务应用 consumerA 可以正常调用 providerA 和 providerB;

  2. 若要重启 providerA,providerA 会标记自身将下线(通知注册中心将下线),并开始统计请求确保当前请求已全部处理完成;

  3. providerA 会通知其上游应用其自身的下线信息;

  4. consumerA 接受到 providerA 下线信息后,将其从缓存实例列表移除;

  5. providerA 在处理完当前的所有请求后,即可重启。

总的来说,Sermant 对于服务下线的机制概括为:

  • 延迟下线: 即对下线的实例提供保护,插件基于 下线实时通知 + 刷新缓存的机制 快速更新上游的实例缓存,同时基于 流量统计 的方式,确保即将下线的实例尽可能的将流量处理完成,最大程度避免流量丢失。提供了延迟下线 API,方便在 K8S 环境中配置 preStop。 http://127.0.0.1:16688/\$\$sermant\$\$/shutdown

  • 流量统计: 为确保当前请求已全部处理完成,在服务下线时,Sermant 会尝试等待 30s(可配置),定时统计和判断当前实例请求是否均处理完成,处理完成后最终下线。

Sermant 优雅上下线能力的详细介绍和使用见: https://sermant.io/zh/document/plugin/graceful.html

五、总结

Sermant 插件为微服务应用提供无损上下线的能力,若要下线应用,针对虚拟场景,请使用 kill PID;针对容器场景(K8S 环境),请配置 preStop 钩子。

原文链接:应用在虚机和容器场景下如何优雅上下线 - 华为云开源的个人空间 - OSCHINA - 中文开源技术交流社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/19427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot文件上传

1.新建文件上传页面 在static目录中新建upload-test.html&#xff0c;上传页面代码如下所示&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>springboot文件上传测试</title> <…

mysql数据库的库操作 --2

目录 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.2&#xff1a;字符集和效验规则 2.3&#xff1a;修改和删除数据库 2.4&#xff1a;数据库的备份和恢复 2.5&#xff1a;查看连接情况 库操作 2.1&#xff1a;数据库的查看与创建与使用 2.1.1&#xff1a;数据库…

Redis 持久化

文章目录 1. Redis 持久化2. RDB2.1 自动触发2.2 手动触发2.3 RDB 优点2.4 RDB 缺点2.5 RDB 文件修复2.6 总结 3. AOF3.1 AOF持久化工作流程3.2 AOF 缓冲区三种写回策略3.3 AOF 优点3.4 AOF 缺点3.5 AOF 重写机制3.6 AOF 重写原理3.7 总结 4. 混合持久化5. 纯缓存模式 1. Redis…

系统移植——linux内核移植——分析内核编译过程

uImage镜像文件 1.进入linux内核源码目录 ubuntuubuntu:~$ cd FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61/ 打开Makefile文件 vi Makefile 搜索include 因为 $(SRCARCH)->arm 所以上述指令为 arch/arm/Makefile 2.进入linux内核源码目录下,arch/arm目录下…

计网笔记 数据链路层 (1-2) 封装成帧、差错控制、流量控制与可靠传输、停止等待协议、后退N帧协议(GBN)、选择重传协议(SR)

文章目录 前言在这里插入图片描述 零、数据链路层基本概念一、功能0、数据链路层功能概述1、封装成帧和透明传输1.1封装成帧1.2 透明传输1.3组帧方法 2、数据链路层的差错控制2.0差错从何而来2.1位错&#xff08;比特错&#xff0c;1变成0&#xff0c;0变成1&#xff09;2.2帧错…

复习一周,面了京东和百度,不小心都拿了Offer...

我个人情况是5年软件测试经验&#xff0c;在家复习了一周&#xff0c;面了京东和百度&#xff0c;都顺利拿下offer&#xff0c;下面是我的面试经历分享&#xff0c;希望能带来一些不一样的启发和帮助。 两家公司最常问的就是下面这些问题&#xff1a; 请介绍一下你之前做过哪些…

String类

目录 一.认识 String 类 二.常用方法 1.字符串构造&#xff08;定义&#xff09; 2.字符串指为空和null 3.String对象的比较 &#xff08;1&#xff09;equals和的区别 &#xff08;2&#xff09;compareTo比较 4.字符串查找 5.字符串转化 &#xff08;1&#xff09;…

前几天面了个32岁的测试员,年薪50w问题基本都能回答上,应该刷了不少八股文···

互联网行业竞争是一年比一年严峻&#xff0c;作为测试工程师的我们唯有不停地学习&#xff0c;不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水&#xff0c;进入心仪的企业&#xff08;阿里、字节、美团、腾讯等大厂.....&#xff09; 所以&#xff0c;大家就迎来了…

centerpoint论文和代码解读

目录 一、序论 二、论文结构 三、代码 论文地址&#xff1a; https://arxiv.org/pdf/2006.11275.pdf 代码地址&#xff1a;tianweiy/CenterPoint (github.com) 一、序论 centorpoint是一种anchor-free的方法&#xff0c;直接预测物体的中心点&#xff0c;然后直接回归其wh…

【C++】unordered_map与unordered_set(系列关联式容器)

文章目录 1.unordered系列关联式容器2. unordered_map3.unordered_set 1.unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;如map和set&#xff0c;它们在查询时效率可达logN&#xff0c;即最差情况下需要比较红黑树的高度…

将 Segment Anything 扩展到医学图像领域

文章目录 前言技术交流SAM 拆解分析从医学角度理解 SAM 的效用MedSAM实验总结 前言 SAM 是一种在自然图像分割方面取得成功的模型&#xff0c;但在医学图像分割方面表现不佳。MedSAM 首次尝试将 SAM 的成功扩展到医学图像&#xff0c;并成为用于分割各种医学图像的通用工具。为…

一文读懂 DNS 解析

导读 文章为“一文读懂域名与网站系列”第二篇&#xff0c;上篇文章主要介绍了域名的注册、建站和管理&#xff0c;通过本文你可以了解以下几个问题&#xff1a; 域名的结构、常用解析记录的类型 DNS 解析的过程 DNS 解析拓展知识 众所周知&#xff0c;互联网中的地址其实是…

Invicti v23.5 for Windows 发布 - 企业应用安全测试

Invicti v23.5 for Windows - 企业应用安全测试 Invicti Standard 11 May 2023 v23.5.0.40516 请访问原文链接&#xff1a;https://sysin.org/blog/invicti/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Invicti 是一种自动…

ESP32在linux下烧录,提示权限有问题,解决方法

执行idf.py -p /dev/ttyACM0 flash下载时&#xff0c;提示这个错误 serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyACM0: [Errno 13] Permission denied: /dev/ttyACM0 解决方法&#xff1a; 1检查串行端口 /dev/ttyUSB0 是否已被其他程序占用…

系统分析师之项目管理(十七)

一、范围管理 范围管理&#xff1a;确定项目的边界&#xff0c;即哪些工作是项目应该做的&#xff0c;哪些工作不应该包括在项目中。 二、时间管理 时间管理&#xff1a;也叫进度管理&#xff0c;就是用科学的方法&#xff0c;确定目标进度&#xff0c;编制进度计划和资源供应计…

SpringBoot整合Swagger

Swagger的作用&#xff1a;生成前后的接口文档&#xff1a; 了解Swagger的概念及作用 掌握在项目中集成Swagger自动生成API文档 一、SpringBoot集成Swagger 1.依赖&#xff1a; <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --><depe…

【A、B、C、D、E类IP地址划分依据,你都会吗?】

IP 地址的格式&#xff1a;IP 地址 网络地址 主机地址 如果 IP 进行了子网划分&#xff1a; 则IP地址网络地址子网地址主机地址 网络地址是互联网上的节点在网络中具有的逻辑地址。MAC 地址&#xff0c;处于数据链 路层&#xff0c;IP 地址处于网络层&#xff0c;端口号处…

人工智能基础部分15-自然语言处理中的数据处理上采样、下采样、负采样是什么?

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分15-自然语言处理中的数据处理上采样、下采样、负采样是什么&#xff1f;在自然语言处理中&#xff0c;上采样、下采样、负采样都是用于处理数据不平衡问题的技术&#xff0c;目的是为了优化模型的训…

C# 对PdfiumViewer工具栏进行自定义,实现放大缩小,首页, 尾页,上一页等功能。

文章目录 前言PdfiumViewer工具栏扩展1 创建winform工程&#xff0c;UI界面2 打印预览3 放大功能4 缩小功能5 按比例缩放6 全屏7 首页和尾页8 上一页和下一页9 页码输入框10 显示当前预览的页码 小结 前言 关于PdfiumViewer的介绍 C# 使用PdfiumViewer实现对PDF文档打印预览&a…

路径规划算法:基于麻雀优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于麻雀优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于麻雀优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法麻雀…