K8s+Nacos实现应用的优雅上下线【生产实践】

`

文章目录

  • 前言
  • 一、环境描述
  • 二、模拟请求报错
  • 三、配置优雅上下线
    • 1.修改nacos配置
    • 2.修改depolyment配置
    • 3.重新apply deployment后测试
    • 4.整体(下单)测试流程验证是否生效
  • 四、期间遇到的问题


前言

我们在使用k8s部署应用的时候,虽然k8s是使用滚动升级的,先启动一个新Pod 等这个新Pod运行成功后,再干掉旧Pod;在这个过程中Pod会一直接收请求的,如果在Pod被干掉的那一刻正好有一部分请求打进来了,那么Pod被杀死了,就不会给这个请求返回结果,就会导致客户端出现请求500错误,这样就做不到平滑升级了,我们要做的就是在Pod升级的时候不能或者尽量避免这种情况;

我们公司使用的是java,中间件用的是nacos,应用在启动时会注册到nacos,然后走应用之间的内部调用,服务会不间断的向注册中心nacos发送自己的心跳(3s) 以及在每个 Pod 服务里本地也有一份缓存映射表(也有一个窗口时间更新30s),服务在停止的时候,自然也会在nacos中进行下线 但是如果有请求在应用下线的这个窗口期发起的话,就会出现K8s Pod 服务已下线,但是 Nacos 在窗口期之内注册列表未更新,导致请求达到一个根本不存在的旧服务里导致请求返回404或者旧请求已经打到旧服务里,但是高峰期时,程序处理较慢,还没来及返回响应体,服务就被关闭了返回500;

我们使用的解决方案是,在应用下线的第一时间(Pod被删除)先进行在nacos的下线操作不让其接受新的请求,然后等待Pod已接收的请求处理完成后 再进行删除Pod;
这里会使用到的知识以及需要自身考虑的点有:

  • k8s的prestop钩子(容器关闭前执行操作)
  • 需要判断自己应用处理的请求的时间(基本上30s内都能处理完成 如果不放心的话调整成50s 但是这样的话也会相应的增加上线时长,需要注意)
  • 需要在nacos(v2.x)中配置Nacos自动清理过期服务的过期时间(删除服务的元数据信息),防止请求过多/代码问题导致Pod的cpu打满 触发Pod的健康检查后 Pod重启以后依然是下线状态(不可用) 这样就出大问题了;
    在这里插入图片描述

一、环境描述

名称版本部署方式
kubernetesv1.20.11二进制
nacosv2.0.3集群模式

二、模拟请求报错

模拟请求报错就是不加任何配置直接使用测试脚本(这里用的是jmeter)不间断的去调用我们的应用,然后发布我们的新应用会有失败的请求

##现在的deployment文件为如下##
apiVersion: apps/v1
kind: Deployment
metadata:namespace: data-centername: energy-order-apilabels:app: energy-order-api
spec:replicas: 3selector:matchLabels:app: energy-order-apitemplate:metadata:labels:app: energy-order-apispec:imagePullSecrets:- name: harbor-secretcontainers:- name: energy-order-apiimage: registry.xxxx/hqt-registry-pro/energy-order-api:P-1391-2023xxxx-15.47.45imagePullPolicy: IfNotPresentcommand: ["/bin/sh"]args: ["-c","java -jar -Xmx2688m -Xms2688m -Xmn961m -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=512m -Xloggc:/logs/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/data/logs/heapdump_$MY_POD_NAME.hprof-XX:+PrintGCDetails -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:NativeMemoryTracking=detail -javaagent:/data/skywalking/skywalking-agent.jar=agent.service_name=energy-order-api,agent.instance_name=$MY_POD_NAME,collector.backend_service=internal-skywalking.xxxx.xxm:11800 -Dapollo.meta=http://apollo-configservice.infrastructure.svc.cluster.local:8080 -Denv=pro /data/app.jar;/sbin/tini -s"]env:#获取pod实例名称,因为一个pod可能会有多个副本,所以需要根据名称来进行区分;- name: MY_POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.nameresources:requests:memory: "4Gi"cpu: "2000m"limits:memory: "4Gi"cpu: "2000m"volumeMounts:- name: energy-order-api-logsmountPath: /data/logssubPathExpr: $(MY_POD_NAME)ports:- containerPort: 80livenessProbe:httpGet:path: /actuator/infoport: 80initialDelaySeconds: 70 #pod启动多长时间后开始去探测;periodSeconds: 5 #每隔多长时间去探测一次;failureThreshold: 6readinessProbe:httpGet:path: /actuator/infoport: 80initialDelaySeconds: 70periodSeconds: 5failureThreshold: 6affinity:#节点亲和性nodeAffinity:#硬策略requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:#标签键- key: ResourcePooloperator: In#标签值values:- core#pod反亲和性配置podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- energy-order-apitopologyKey: kubernetes.io/hostname        volumes:- name: energy-order-api-logspersistentVolumeClaim:claimName: energy-order-api-logs---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: energy-order-api-logsnamespace: data-center
spec:accessModes:- ReadWriteManystorageClassName: alicloud-nas-subpathresources:requests:storage: 1Gi

Pod启动成功如下:
在这里插入图片描述

在这里插入图片描述
设置30个线程开始去请求我们服务的接口
可以看到目前的请求都是成功的,此时我们修改镜像apply可以模拟下我们的服务发布,当新Pod启动后 删除旧Pod时注意观察请求是否有报错!

在这里插入图片描述

在这里插入图片描述
可以发现在删除pod时的这个动作会出现错误请求,随后就会正常
在这里插入图片描述
以上就是发版(新Pod替换旧Pod)的过程中会出现的问题;

三、配置优雅上下线

1.修改nacos配置

[root@iZbp1iz5ayf044rk5cqq26Z ~]# vim /hqtbj/hqtwww/nacos_workspace/conf/application.properties
#打开注释并修改
### The interval to clean expired metadata, unit: milliseconds.
nacos.naming.clean.expired-metadata.interval=5000
### The expired time to clean metadata, unit: milliseconds.
nacos.naming.clean.expired-metadata.expired-time=5000

保存后重启nacos

2.修改depolyment配置

需要添加k8s的prestop钩子,以及设置强制关闭pod的时间要比sleep的时间长
'curl -X PUT "http://my-nacos.xxx.com/nacos/v1/ns/instance?serviceName=服务名称&ip=服务IP&port=服务端口&weight=0" && sleep 30 && PID= && kill -SIGTERM $PID && while ps -p $PID > /dev/null; do sleep 1; done'
terminationGracePeriodSeconds: 40
如上命令的作用:

  1. 使用curl将注册到nacos的实例权重设置为0,设置为0后就不会再接受请求了,也可以调用nacos的下线接口,只需要将weight=0改为enabled=false即可;
  2. 不接受请求后sleep睡眠30秒 用于处理已经发送过来的请求;
  3. 然后再kill -SIGTERM进行优雅的关闭服务;
  4. 等待Pod中的服务完全停止,如果在 terminationGracePeriodSeconds 40s内 (默认 30s) 还未完全停止,就发送 SIGKILL 信号强制杀死进程(kill -9)。
#添加prestop钩子
lifecycle:preStop:exec:command: ["/bin/sh","-c",'curl -X PUT "http://my-nacos.xxx.com/nacos/v1/ns/instance?serviceName=energy-order-api&ip=${POD_IP}&port=80&weight=0" && sleep 30 && PID=`pidof java` && kill -SIGTERM $PID && while ps -p $PID > /dev/null; do sleep 1; done']  
#设置强制杀死Pod(kill -9)的时间,默认为30s   
terminationGracePeriodSeconds: 40

完整deployment内容如下

---
apiVersion: apps/v1
kind: Deployment
metadata:namespace: data-centername: energy-order-apilabels:app: energy-order-api
spec:replicas: 3selector:matchLabels:app: energy-order-apitemplate:metadata:labels:app: energy-order-apispec:imagePullSecrets:- name: harbor-secretcontainers:- name: energy-order-apiimage: registry.xxxx/hqt-registry-pro/energy-order-api:P-1391-2023xxxx-15.47.45imagePullPolicy: IfNotPresentcommand: ["/bin/sh"]args: ["-c","java -jar -Xmx2688m -Xms2688m -Xmn961m -XX:MaxMetaspaceSize=512m -XX:MetaspaceSize=512m -Xloggc:/logs/gc-%t.log -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/data/logs/heapdump_$MY_POD_NAME.hprof-XX:+PrintGCDetails -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:NativeMemoryTracking=detail -javaagent:/data/skywalking/skywalking-agent.jar=agent.service_name=energy-order-api,agent.instance_name=$MY_POD_NAME,collector.backend_service=internal-skywalking.xxxx.xxm:11800 -Dapollo.meta=http://apollo-configservice.infrastructure.svc.cluster.local:8080 -Denv=pro /data/app.jar;/sbin/tini -s"]env:#获取pod实例名称,因为一个pod可能会有多个副本,所以需要根据名称来进行区分;- name: MY_POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.nameresources:requests:memory: "4Gi"cpu: "2000m"limits:memory: "4Gi"cpu: "2000m"volumeMounts:- name: energy-order-api-logsmountPath: /data/logssubPathExpr: $(MY_POD_NAME)ports:- containerPort: 80lifecycle:preStop:exec:command: ["/bin/sh","-c",'curl -X PUT "http://nacos.wonxxxnk.cc/nacos/v1/ns/instance?serviceName=energy-order-api&ip=${POD_IP}&port=80&weight=0" && sleep 30 && PID=`pidof java` && kill -SIGTERM $PID && while ps -p $PID > /dev/null; do sleep 1; done']terminationGracePeriodSeconds: 40livenessProbe:httpGet:path: /actuator/infoport: 80initialDelaySeconds: 70 #pod启动多长时间后开始去探测;periodSeconds: 5 #每隔多长时间去探测一次;failureThreshold: 6readinessProbe:httpGet:path: /actuator/infoport: 80initialDelaySeconds: 70periodSeconds: 5failureThreshold: 6affinity:#节点亲和性nodeAffinity:#硬策略requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:#标签键- key: ResourcePooloperator: In#标签值values:- core#pod反亲和性配置podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- energy-order-apitopologyKey: kubernetes.io/hostname        volumes:- name: energy-order-api-logspersistentVolumeClaim:claimName: energy-order-api-logs---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: energy-order-api-logsnamespace: data-center
spec:accessModes:- ReadWriteManystorageClassName: alicloud-nas-subpathresources:requests:storage: 1Gi

3.重新apply deployment后测试

在这里插入图片描述
在这里插入图片描述
如上,现在Pod已经启动成功并且在nacos中也是可用状态

开始测试
在这里插入图片描述
如上当开始停止旧pod时, 会先调用我们配置的prestop钩子 如下 先把nacos中旧pod的权重改为0 不让其接受请求,然后再处理已接受的请求最后彻底关闭pod

在这里插入图片描述
可以看到整个流程下来是没有发现有请求失败的!
在这里插入图片描述

这是单对这一个order服务进行的测试,接下来需要走一遍整体下单的流程,调用多个服务进行测试的同时重新发布这个order服务看是否有失败的请求

4.整体(下单)测试流程验证是否生效

已启动的pod以及nacos状态如下:
在这里插入图片描述
在这里插入图片描述
开始测试
在这里插入图片描述
在这里插入图片描述
如上可以发现在停止Pod时,跟上面的结果是一样的,都是先把nacos中旧pod的权重改为0,然后等待处理请求再彻底关闭pod;

如下测试,整体一个下单流程再发布期间也是不回受到影响的,无报错
在这里插入图片描述

四、期间遇到的问题

如果不配置nacos清理元数据信息的话,会导致当cpu/内存使用超过限制而导致健康检查重启时(Pod实例自身重启而不是会起一个新pod),会出现即使pod重启完nacos里注册的服务权重是0/下线,导致服务直接不可用,只能手动再去启用!!所以下面在nacos的配置一定要进行使用!
在这里插入图片描述

如下:
服务因健康检查失败开始重启

在这里插入图片描述
在这里插入图片描述
此时的请求开始报错
在这里插入图片描述
服务的权重变为0,不接收请求
在这里插入图片描述
pod重启完成
在这里插入图片描述
发现nacos里注册的服务权重依然为0,并没进行接收请求
在这里插入图片描述
请求依旧报错
在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

selenium自动化登录模块HTMLTestRunner测试报告

1.下载HTMLTestRunner.py放到python的Lib目录下,python3之后的,文件要修改以下内容: 第94行,将import StringIO修改成import io 第539行,将self.outputBuffer StringIO.StringIO()修改成self.outputBuffer io.Strin…

【微服务】微服务架构的最佳实践总结!

目录 推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战构建和管理微服务是一项艰巨的任务。这是因为微服务就像多个并行的整体应用程序,它们都必须处于同步通信和并发运行时间。因此,在设计和构建它们时考虑并应用最佳实践非常重要。以下…

C++ —— 日期计算器

1. 头文件 #pragma once #include <iostream> using namespace std;class Date { public:Date(int year 1, int month 1, int day 1);int GetMonthDay();bool operator>(const Date& d) const;bool operator>(const Date& d)const;bool operator<(c…

GPU算力池管理工具Determined AI部署与使用教程(2024.03)

1. 概念 1.1 什么是Determined&#xff1f; Determined AI 是一个全功能的深度学习平台&#xff0c;兼容 PyTorch 和 TensorFlow。它主要负责以下几个方面&#xff1a; 分布式训练&#xff1a;Determined AI 可以将训练工作负载分布在多个 GPU&#xff08;可能在多台计算机上…

鸿蒙预览报错 Only files in a module can be previewed

HarmonyOS第一课下载的源码无法运行&#xff0c;也无法预览&#xff0c;报错如题。 解决&#xff1a; 1、在预览页如“index.ets”文件下预览。 2、如果在通知栏看到如图提示&#xff0c;可看出是ohos/hvigor-ohos-plugin插件版本的问题&#xff0c;可点击蓝色解决方案同步并导…

python 函数(解包**、互相调用、作用域、函数的封装、内置函数:eval()、zip()、文件处理open())

函数解包 """ 1、函数的注释&#xff1a;参数和返回值 在注释里可以自动添加显示&#xff0c;只需手动加说明。2、函数的解包【拆包】&#xff1a;函数的参数要传递数据有多个值的时候&#xff0c;中间步骤拿到数据 保存在元组或者列表 或者字典里。 - 传递参数…

活用 C语言之union的精妙之用

一、union的基本定义 Union的中文叫法又被称为共用体、联合或者联合体。它的定义方式与结构体相同,但意义却与结构体完全不同。下面是union的定义格式: union 共用体名 {成员列表}共用体变量名;它与结构体的定义方式相同,但区别在于共用体中的成员的起始地址都是相同的,…

【理解机器学习算法】之Clustering算法(DBSCAN)

DBSCAN&#xff08;基于密度的空间聚类应用噪声&#xff09;是数据挖掘和机器学习中一个流行的聚类算法。与K-Means这样的划分方法不同&#xff0c;DBSCAN特别擅长于识别数据集中各种形状和大小的聚类&#xff0c;包括存在噪声和离群点的情况。 以下是DBSCAN工作原理的概述&am…

KubeSphere的基本使用操作

KubeSphere的基本使用操作 基本使用用户角色创建企业空间创建项目 创建应用创建密钥创建MySQL密钥创建WordPress密钥 创建存储卷创建MySQL存储卷创建Wordpress存储卷 添加组件服务类型添加MySQL组件添加WordPress组件 访问Wordpress 基本使用 用户角色 KubeSphere 中的权限控制…

FloodFill算法——岛屿数量

文章目录 题目解析算法解析代码解析 题目解析 岛屿数量 题目依旧是熟悉的配方&#xff0c;熟悉的味道&#xff0c;还是那个0还是那个1还是那个二维矩阵&#xff0c;这时候BFS和DFS闻着味就来了&#xff0c;我们来看一下这个题目&#xff0c;这个题目也很容易理解如下图有一个…

【每日一问】IOS手机上Charles证书过期怎么办?

1、如何查看证书是否过期? 设置>通用>VPN与设备管理 2、在Charles中重置证书 步骤1&#xff1a;重置证书 Help>SSL Proxying>Reset Charles Root Certificate… 步骤2&#xff1a;在浏览器中&#xff0c;下载证书 首先&#xff0c;手机连上代理&#xff0c;然…

qt+ffmpeg 实现音视频播放(三)之视频播放

一、视频播放流程 &#xff08;PS&#xff1a;视频的播放流程跟音频的及其相似&#xff01;&#xff01;&#xff09; 1、打开视频文件 通过 avformat_open_input() 打开媒体文件并分配和初始化 AVFormatContext 结构体。 函数原型如下&#xff1a; int avformat_open_inpu…

Java项目:71 ssm基于ssm+vue的外卖点餐系统+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统功能 系统分为前台订餐和后台管理&#xff1a; 1.前台订餐 用户注册、用户登录、我的购物车、我的订单、商品列表 2.后台管理 商品管理&#xf…

QT tableWidget横向纵向设置

横向控件 要设置QTabWidget选项卡的字体方向&#xff0c;可以使用QTabWidget的setTabPosition()方法。通过传递Qt枚举值QTabWidget.east或QTabWidget.west作为参数&#xff0c;可以设置选项卡的字体方向为从左到右或从右到左。 myTabWidget QTabWidget() myTabWidget.setTabP…

Grass手机注册使用教程,利用闲置手机WiFi带宽赚钱

文章目录 Grass是什么&#xff1f; 项目介绍Grasss手机使用步骤第一步&#xff1a;下载狐猴浏览器第二步&#xff1a;注册账户&#xff08;已注册直接跳过&#xff09;第三步&#xff1a;安装Grass Chrome插件1、推荐离线安装2、在线安装 第四步&#xff1a;登录第五步&#xf…

MySQL 更新执行的过程

优质博文&#xff1a;IT-BLOG-CN Select语句的执行过程会经过连接器、分析器、优化器、执行器、存储引擎&#xff0c;同样的 Update语句也会同样走一遍 Select语句的执行过程。 但是和 Select最大不同的是&#xff0c;Update语句会涉及到两个日志的操作redo log&#xff08;重做…

欧科云链OKLink:坎昆升级后,Layer2项目是否更具竞争力?

在坎昆升级激活之际&#xff0c;OKLink 上线以太坊坎昆升级 Dencun 专题页 &#x1f449; 从专业链上数据分析角度&#xff0c;带来一场充实且即时的 Layer2 数据盛宴。 在近日由 137Labs 发起&#xff0c;Cointime 主持的 Layer2 生态专场讨论中&#xff0c;OKLink 产品…

InnoDB 缓存

本文主要聊InnoDB内存结构, 先来看下官网Mysql 8.0 InnoDB架构图 MySQL :: MySQL 8.0 Reference Manual :: 17.4 InnoDB Architecture 如上图所示,InnoDB内存主要包含Buffer Pool, Change Buffer, Log Buffer, Adaptive Hash Index Buffer Pool 其实 buffer pool 就是内存中的…

练习实践-进程回收01-找到并清理僵尸进程

参考来源&#xff1a; https://blog.csdn.net/qq_36528114/article/details/71076110 https://blog.51cto.com/u_12083623/2363384 极客时间-性能优化实战-CPU性能篇 进程回收中的孤儿和僵尸进程的特点 演示环境&#xff1a; 操作系统&#xff1a;Ubuntu18.04 查询工具&#x…

Golang案例开发之gopacket抓包三次握手四次分手(3)

文章目录 前言一、理论知识三次握手四次分手二、代码实践1.模拟客户端和服务器端2.三次握手代码3.四次分手代码验证代码完整代码总结前言 TCP通讯的三次握手和四次分手,有很多文章都在介绍了,当我们了解了gopacket这个工具的时候,我们当然是用代码实践一下,我们的理论。本…