Spring Cloud + Nacos + K8S 零影响发布方案
问题描述
在生产环境中使用 springcloud 框架,由于服务更新过程中,容器服务会被直接停止,部分请求仍被分发到终止的容器,导致服务出现500错误,这部分错误请求数据占用比较少,因为Pod滚动更新都是一对一。因为部分用户会产生服务器错误的情况,考虑使用优雅的终止方式,将错误请求降到最低,直至滚动更新不影响用户。这里结合nacos使用来分析。
在 K8s 的滚动升级中,比如 5 个 Pod 服务在升级过程中,会先启动一半左右(比如:3 个新的启动),然后下线一部分服务……直到所有的旧服务被新服务完全替代,简单粗暴的理解滚动升级。如果我们不涉及 Nacos 还好,因为 K8s 会保证在升级过程中,因为负载的情况很有可能在升级过程中会一部分请求打到旧服务里,但是如果在旧服务准备关闭服务时,旧情求还没返回回去的话就会出现 HTTP 连接关闭情况等一些不可预测的意外发生,导致本次请求的业务失败,这是在生产上绝不能出现的事故。针对 K8s 的优雅关闭问题,我们可以继续往下看,下面会介绍 Nacos & K8s 一个结合优雅关闭的方案。
我们来再谈谈 Nacos 在这里如果无优雅关闭的话会出现的情况,其实和 K8s 的本质很类似,假如我们已经解决了 K8s 的优雅关闭问题,那和 Nacos 之间又有什么联系呢?
我们可以想象下,还是举例上面的 5 个 Pod 的情景,在一个 Pod 启动时,服务的也自然会注册到 Nacos 上去,同理可得,在服务关闭时,Nacos 注册列表里服务也自然会被下线。那么类似的情况也会出现,如果说此时的情求打到旧服务上面,但是由于 Nacos 有监听时间(默认 30s)拉取一次最新情况,以及在每个 Pod 服务里本地也有一份缓存映射表(也有一个窗口时间更新),所以很有可能在这个窗口期之内,还有一些的旧的请求访问负载到旧服务里,但是这里会出现两种情况
K8s Pod 服务已下线,但是 Nacos 在窗口时间之内注册列表未更新,导致请求达到一个根本不存在的旧服务里 旧请求已经打到旧服务里,但是高峰期时,程序处理较慢,还没来及返回响应体,服务就被关闭了 以上这两种情况都会导致本次请求出现失败,生产上更是无语~ 所以我们针对 Nacos 的优雅关闭情况也会有一个解决方案,见“Nacos & K8s 优雅关闭方案”
一、思路
为了解决这个问题, 我们将利用 springboot 的 graceful shutdown 功能和 nacos 的主动下线功能来解决这个问题. 具体思路如下:
1、让新的服务先启动起来,注册到注册中心,等待客户端发现新服务。
2、把待下线的服务从注册中心下线,等待客户端刷新服务列表。
3、把待下线的服务优雅停机。
二、实现方式
1.创建从 nacos 中下线副本的API
我们通过创建自定义名为 deregister 的 endpoint 来通知 nacos 下线副本
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistry;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;@Component
@Endpoint(id = "deregister")
@Log4j2
public class LemesNacosServiceDeregisterEndpoint {@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties;@Autowiredprivate NacosRegistration nacosRegistration;@Autowiredprivate NacosServiceRegistry nacosServiceRegistry;/*** 从 nacos 中主动下线,用于 k8s 滚动更新时,提前下线分流流量** @param* @return com.lenovo.lemes.framework.core.util.ResultData<java.lang.String>* @author Yujie Yang* @date 4/6/22 2:57 PM*/@ReadOperationpublic String endpoint() {String serviceName = nacosDiscoveryProperties.getService();String groupName = nacosDiscoveryProperties.getGroup();String clusterName = nacosDiscoveryProperties.getClusterName();String ip = nacosDiscoveryProperties.getIp();int port = nacosDiscoveryProperties.getPort();log.info("deregister from nacos, serviceName:{}, groupName:{}, clusterName:{}, ip:{}, port:{}", serviceName, groupName, clusterName, ip, port);// 设置服务下线nacosServiceRegistry.setStatus(nacosRegistration, "DOWN");return "success";}}
2.支持 Graceful Shutdown
Spring Boot 原生支持已经支持优雅停机。
我们需要添加下面的配置,超时需要根据平时请求的耗时来定,可以稍微大一点也没关系。我们只需要在 bootstrap.yaml 中添加一下配置即可。
server:# 开启优雅下线shutdown: gracefulspring:lifecycle:# 优雅下线超时时间timeout-per-shutdown-phase: 5m
# 暴露 shutdown 接口
management:endpoint:shutdown:enabled: trueendpoints:web:exposure:include: shutdown
3.配置K8s
有了上面两个 API, 接下来就配置到 k8s 上
1.K8S容器本身有一个就绪探针配置,当就绪探针返回正常,则开始删除旧POD。
2.terminationGracePeriodSeconds 如果关闭应用的时间超过 10 分钟, 则向容器发送 kill 信号, 防止应用长时间下线不了
terminationGracePeriodSeconds要大于preStop+spring.lifecycle.timeout-per-shutdown-phase,可以设置大一点没什么关系。
3.preStop 先执行下线操作, 等待30s, 留够通知到其他应用的时间, 然后执行 graceful shutdown 关闭应用。
---
apiVersion: apps/v1
kind: Deployment
metadata:name: lemes-service-commonlabels:app: lemes-service-common
spec:replicas: 2selector:matchLabels:app: lemes-service-common
# strategy:
# type: RollingUpdate
# rollingUpdate:
## replicas - maxUnavailable < running num < replicas + maxSurge
# maxUnavailable: 1
# maxSurge: 1template:metadata:labels:app: lemes-service-commonspec:
# 容器重启策略 Never Always OnFailure
# restartPolicy: Never
# 在pod优雅终止时,定义延迟发送kill信号的时间,此时间可用于pod处理完未处理的请求等状况。默认单位是秒
# 如果关闭时间超过10分钟, 则向容器发送kill信号terminationGracePeriodSeconds: 600affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- podAffinityTerm:topologyKey: "kubernetes.io/hostname"labelSelector:matchExpressions:- key: appoperator: Invalues:- lemes-service-commonweight: 100
# requiredDuringSchedulingIgnoredDuringExecution:
# - labelSelector:
# matchExpressions:
# - key: app
# operator: In
# values:
# - lemes-service-common
# topologyKey: "kubernetes.io/hostname"volumes:- name: lemes-host-pathhostPath:path: /data/logstype: DirectoryOrCreate- name: sidecaremptyDir: { }containers:- name: lemes-service-commonimage: 10.176.66.20:5000/lemes-cloud/lemes-service-common-server:v0.1imagePullPolicy: AlwaysvolumeMounts:- name: lemes-host-pathmountPath: /data/logs- name: sidecarmountPath: /sidecarports:- containerPort: 80resources:
# 资源通常情况下的占用requests:memory: '2048Mi'
# 资源占用上限limits:memory: '4096Mi'livenessProbe:httpGet:
# 指定 Kubernetes 访问的健康检查 URL 路径path: /actuator/health/livenessport: 80initialDelaySeconds: 5
# 探针可以连续失败的次数failureThreshold: 10
# 探针超时时间timeoutSeconds: 10
# 多久执行一次探针查询periodSeconds: 10startupProbe:httpGet:path: /actuator/health/livenessport: 80failureThreshold: 30timeoutSeconds: 10periodSeconds: 10readinessProbe:httpGet:path: /actuator/health/readinessport: 80initialDelaySeconds: 5timeoutSeconds: 10periodSeconds: 10lifecycle:preStop:exec:
#应用关闭操作:1. 从 nacos 下线,2. 等待30s, 保证 nacos 通知到其他应用 2.触发 springboot 的 graceful shutdowncommand:- sh- -c- curl http://127.0.0.1/actuator/deregister;sleep 30;curl -X POST http://127.0.0.1/actuator/shutdown;
相关文章:
Spring Cloud + Nacos + K8S 零影响发布方案
问题描述 在生产环境中使用 springcloud 框架,由于服务更新过程中,容器服务会被直接停止,部分请求仍被分发到终止的容器,导致服务出现500错误,这部分错误请求数据占用比较少,因为Pod滚动更新都是一对一。因…...
Git命令摘录
使用 Git 升级软件通常是指通过 Git 仓库获取软件的最新版本或更新代码。以下是详细的步骤和方法: 1. 克隆软件仓库 如果这是你第一次获取软件代码,可以使用 git clone 命令将远程仓库克隆到本地。 git clone <仓库地址> 例如: git cl…...
2024年博客之星年度评选—创作影响力评审+主题文章创作评审目前排名(2024博客之星陪跑小分队助力2024博客之星创作者成长)
2024年博客之星年度评选—创作影响力评审主题文章创作评审目前排名 2024年博客之星主题文章创作评审文章得分公布!2024年博客之星创作影响力评审2024年博客之星主题文章创作评审目前排名公布! 【2024博客之星】恭喜完成✅主题创作的226位博主࿰…...
unity 0基础自学2.1:unity 中button的各类状态
文章目录 1、Button的状态2、脚本中获取button的状态2.1 分析状态获取2.2 通过实现接口获取button的状态2.2.1 鼠标点击与释放2.2.2 高亮模式2.2.3 退出选中模式(高亮状态)2.2.4 选择模式selected2.2.5 退出选择模式 3、射线与UI交互设置3.1 Canvas中组件…...
《C++ Primer》学习笔记(一)
第一部分:C基础 在C和C编程语言中,main函数必须返回int类型的值。这一要求自C标准的第一次规范(C89,也叫ANSI C)开始就已经明确规定了。std::endl和\n都用于插入换行符。std::endl除了换行,还会强制刷新输…...
DedeBIZ系统审计小结
之前简单审计过DedeBIZ系统,网上还没有对这个系统的漏洞有过详尽的分析,于是重新审计并总结文章,记录下自己审计的过程。 https://github.com/DedeBIZ/DedeV6/archive/refs/tags/6.2.10.zip 📌DedeBIZ 系统并非基于 MVC 框架&…...
基于 Python(Flask)、JavaScript、HTML 和 CSS 实现前后端交互的详细开发过程
以下是一个基于 Python(Flask)、JavaScript、HTML 和 CSS 实现前后端交互的详细开发过程: --- ### 一、技术选型 1. **后端**:Python Flask(轻量级Web框架) 2. **前端**:HTML/CSS JavaScript&…...
作业。。。。。
顺序表按元素删除 参数:删除元素,顺序表 1.调用元素查找的函数 4.根据下表删除 delete_sub(list,sub); //删除元素 void delete_element(int element, Sqlist *list) …...
C#快速排序QuickSort将递归算法修改为堆栈Stack非递归方式
我们知道,方法的调用是采用Stack的方式[后进先出:LIFO], 在DeepSeek中快速搜索C#快速排序, 搜索结果如图: 我们会发现是采用递归的方式 . 递归的优点: 简单粗暴,类似于直接写数学公式,因代码量较少,易于理解.递归与循环迭代的运行次数都是一致的 递归的缺点: 占用大量的内…...
15.最大二叉树、合并二叉树、二叉搜索树
最大二叉树 就是一个提供了额外信息的中序遍历 class Solution { public:TreeNode* sol(vector<int>& nums,int start,int end){if(startend)return nullptr;int maxnums[start],indexstart;for(int istart;i<end;i){if(nums[i]>max){maxnums[i];indexi;}}Tr…...
【DeepSeek × Postman】请求回复
新建一个集合 在 Postman 中创建一个测试集合 DeepSeek API Test,并创建一个关联的测试环境 DeepSeek API Env,同时定义两个变量 base_url 和 api_key 的步骤如下: 1. 创建测试集合 DeepSeek API Test 打开 Postman。点击左侧导航栏中的 Co…...
Repo命令使用
repo 命令与 git 类似,但它主要用于管理多个 Git 仓库的操作。以下是等效的 repo 命令: 1. 获取新仓库代码 克隆仓库 repo init -u <manifest_url> -b <branch_name> repo sync repo init:初始化 repo,指定远程清单…...
npm install 失败
考虑原因: node版本不符代理镜像连接失败权限不足 症状1: 卡住 尝试降低nodejs版本 症状2:报错 报错1:permission not permitted 报错2: 超时 应对方法: node版本不符 降版本 镜像失败 – 切换镜像 …...
排序算法整理(冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序、计数排序、桶排序、基数排序)
排序算法是计算机科学中用于将数据元素按照特定顺序进行排列的算法,常见的排序算法有以下几类: 比较排序 冒泡排序:通过重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作…...
Kimi实战1/100 - 读接口文档,编写接口
文章目录 Kimi实战1/100 - 读接口文档,编写接口接口调用requests 调用代码说明注意事项 接口提供FastAPI 接口代码代码说明测试方法 Kimi实战1/100 - 读接口文档,编写接口 接口调用 User: 根据 接口文档 https://www.eiisys.com/home/apiDetails?id00…...
Spring Cache @Cacheable:提升应用性能的利器
在构建企业级应用时,性能优化至关重要。Spring Cache 提供了一种简便而强大的方式来缓存方法调用的结果,从而减少数据库访问、提高响应速度。其中,Cacheable 注解是 Spring Cache 的核心,本文将深入剖析 Cacheable 注解࿰…...
css块级元素和行内元素区别
在CSS中,元素可以分为两大类:块级元素(Block-level elements)和行内元素(Inline elements)。这两种元素在网页布局中起着不同的作用,主要体现在它们的显示方式、尺寸控制、以及与其他元素的交互…...
AWTK fscript 中的 TCP/UDP 客户端扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 TCP/UDP 客户端扩展函数。 1.iostream_tcp_create 创建 TCP 客户端输入输出流对象。 原型 iostream_tcp_create(host, por…...
[免费]Springboot+Vue医疗(医院)挂号管理系统【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的SpringbootVue医疗(医院)挂号管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue医疗(医院)挂号管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 在如今社会上,关于信息上…...
计算机毕业设计PySpark+hive招聘推荐系统 职位用户画像推荐系统 招聘数据分析 招聘爬虫 数据仓库 Django Vue.js Hadoop
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Jmeter+Influxdb+Grafana平台监控性能测试过程
一、Jmeter自带插件监控 下载地址:https://jmeter-plugins.org/install/Install/ 安装:下载后文件为jmeter-plugins-manager-1.3.jar,将其放入jmeter安装目录下的lib/ext目录,然后重启jmeter,即可。 启动Jmeter&…...
fatal: unable to access ‘https://github.com/xxx/‘: SSL peer certificat
从github上clone代码时报错 F:\Projects>git clone https://github.com/xxx into xxx... fatal: unable to access https://github.com/xxx/: SSL peer certificate or SSH remote key was not OK **可能的原因****解决方法****1. 检查系统时间****2. 禁用 SSL 验证…...
Prompt通用技巧
Prompt 的典型构成 角色:给 AI定义一个最匹配任务的角色,比如:「你是一位软件工程师」「你是一位小学老师」指示:对任务进行描述上下文: 给出与任务相关的其它背景信息(尤其在多轮交互中)。例子 : 必要时给出举例,学术中称为 one-shot learning,few-sho…...
ROACH
End-to-End Urban Driving by Imitating a Reinforcement Learning Coach CARLA-Roach ICCV‘21论文:模仿一个强化学习教练的端到端城市驾驶 文章目录 Roach输入BEV语义分割图像测量向量 Roach输出训练策略网络价值网络 具体实现由 Roach 监督的模仿学习(…...
机械臂运动学笔记(一):正向运动学
正向运动学指的是通过相邻关节间的转动和移动坐标,将末端的坐标计算出来。 反向运动学指的是已知机械臂末端的坐标,反算每个关节可能的转动和移动参数。 参考资料:4.机械臂几何法与DH表示法_哔哩哔哩_bilibili 一.任意连杆连接的变量定义&a…...
【DuodooBMS】给PDF附件加“受控”水印的完整Python实现
给PDF附件加“受控”水印的完整Python实现 功能需求 在实际工作中,许多文件需要添加水印以标识其状态,例如“受控”“机密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是…...
GitCode 助力 Dora SSR:开启游戏开发新征程
项目仓库(点击阅读原文链接可直达) https://gitcode.com/ippclub/Dora-SSR 跨越技术藩篱,构建游戏开发乐园 Dora SSR 是一款致力于打破游戏开发技术壁垒的开源游戏引擎。其诞生源于开发者对简化跨平台游戏开发环境搭建的强烈渴望࿰…...
Mediamtx+Python读取webrtc流
一、功能思路: 1、我采用ffmpeg -re -stream_loop -1 -i xcc.mp4 -c:v libx264 -profile:v baseline -x264opts "bframes0:repeat_headers1" -b:v 1500k -preset fast -f flv rtmp://127.0.0.1:1835/stream/111推流到mediamtx的rtmp上 2、通过mediamtx自…...
每日一题——矩阵最长递增路径
矩阵最长递增路径问题 题目描述数据范围:进阶要求:示例示例 1示例 2 题解思路算法步骤:代码实现代码解释复杂度分析总结 题目描述 给定一个 n 行 m 列的矩阵 matrix,矩阵内所有数均为非负整数。你需要在矩阵中找到一条最长路径&a…...
【CLIP系列】4:目标检测(ViLD、GLIP)
目录 1 ViLD2 GLIP2.1 前言2.2 损失计算2.3 模型框架 1 ViLD OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION 从标题就能看出来,作者是把CLIP模型当成一个Teacher,去蒸馏他自己的网络,从而能Zero Shot去…...
