Springcloud基于K8S滚动更新方案设计与原理

文章分析了在K8S中使用滚动更新策略发布微服务时,由于Pod生命周期和Nacos服务发现机制,可能导致短暂的流量损失。解决方案是在Pod预停止阶段主动从Nacos注销服务,并阻塞一段时间确保其他服务完成同步更新。同时,文章提及SpringCloud服务注册流程,强调服务注册在Web应用启动完成后进行。
摘要由CSDN通过智能技术生成

前言

由于近期使用k8s进行发布发现后端微服务流量有损失:

  • 发布过程中接口偶尔返回500状态
  • 微服务间接口调用返回500

本文分析产生原因,k8s组件工作原理及pod生命周期,最终解决方案。

K8S滚动更新介绍

K8S 滚动更新是Deployment默认更新策略,其本质是启动一个新pod然后在停止一个旧pod直到所有pod更新完成。滚动更新发布速率可以通过如下参数进行控制

maxSurge

maxUnavailable

  1.  表示当前deployment运行2个pod
  2. 更新deployment(应用发布)
  3. 创建新的pod(蓝色pod)新pod启动成功k8s检测到readniess状态ready后停止老pod(红色)
  4. 老pod停止后(红色pod)继续创建新pod
  5. 新pod状态为ready 停止老pod(红色)
  6. 发布完成,所有pod都为新pod,老pod全部停止删除老版本replicateset

K8S服务发现介绍

在pod创建好以后k8s会为pod分配ip但次ip只能在k8s内部访问,随着pod的频繁创建删除ip也会随时改变,因此k8s提供service关联一组pod并对外进行服务发现,当service设置lable后k8s会自动创建endpoint并维护一个ip列表代表当前service下有那些pod与之关联。

下图表示删除pod与新增pod对应service的endpoint的IP列表变化

  1. 代表正在运行的service维护的pod列表
  2. 新增pod当pod的状态变为ready后,endpoint 监听到有新pod自动将新pod ip 加入到自己的列表,次列表存储在etcd中
  3. 当pod收到 terminal信号后,endpoint watch到该信号后将次pod ip 从ip列表中删除

K8S pod生命周期

 pod是Kubernetes 中创建和管理的、最小的可部署的计算单元。pod的生命周期中对位提供不同的调用方式方便做一些回调处理。

  • initContainer是pod中运行的init容器可以对pod进行初始化例如设置文件路径,设置环境变量等,initContainer可以存在多个,在pod启动中顺寻执行
  • poststart是一个回调接口在maincontainer启动时进行回调,但此接口为异步接口
  • maincontainer 为主容器,微服务主要运行在此容器中
  • readniess 为回调接口,表示主容器中的应用是否启动完成并可以对外部提供服务,如果readniss返回成功,pod的状态才会变为ready,否在会不停尝试重启pod
  • healthness为pod运行时k8s检测内部应用是否运行的回调接口,如果检测接口返回失败则重新创建pod
  • prestop 为pod停止时前置执行回调接口,此接口运行逻辑运行完才会停止主容器,此接口为同步接口

在了解了以上内容的工作逻辑后,下面重点分析为什么在k8s中发布微服务会产生流量损失,本文微服务的注册中心采用nacos且独立部。

K8S 启停微服务产生流量损失的原因

下图为k8s发布某个微服务时各个组件的状态以及其他的微服务注册信息变更逻辑

  1. 发布新的deployment根据滚动更新策略创建新pod,pod状态编程ready后endpoint更新新pod ip到etcd表中,然后向nacos注册自己(绿色线部分)
  2. 停止老pod,endpoint删除etcd中老pod ip,但此时老pod ip 并未从nacos中删除,因为nacos与服务提供者通过心跳方式维护服务提供者状态,当服务提供者15内没有发动心跳nacos标记服务提供者为不健康状态,超过30才会将ip从nacos中删除
  3. 其他微服务获取nacos中的服务列表通过拉去的方式进行,每次拉去最新的列表时间间隔为30秒,30秒内会将服务列表缓存在本地机器。

因此在某个服务发布的过程中其他微服务还是会持有下线服务机器ip 大概30秒左右的时间,在此期间调用就会出现流量损失,因为老服务ip对应的pod已经停止无法相应请求了。

在分析完产生原因后提出如下改造方案。

K8S 发布微服务实现方案

在pod创建过程中因为新pod的状态是在ready后才被k8s服务发现因此部存在流量损失问题,产生生问题在pod停止时发生因此在pod停止时做如下处理:

  1. pod停止后调用prestop先将自身ip从nacos摘掉不对外提供服务
  2. 由于微服务每隔30s从nacos同步服务列表,因此在摘到nacos中ip后接口prestop接口阻塞90s,90s包含nacos同步时间间隔以及老的相应完处理的时间
  3. 90s过后在停止pod中的应用

因此在代码中增加nacos取消注册的接口如下所示

 在deployment中增加prestop回调函数

通过以上改造完美解决了流量损失问题。

springcloud服务注册流程

springcloud启动时合适向nacos中注册服务ip?

带着这个问题我们看下nacos注册的源代码,其本质就是在服务注册时会监听当前应用启动状态是否为完成状态,由于微服务都是web应用因此在web启动完成后springcloud会发布一个web初始化完成的事件。监听到此事件后向nacos中注册服务

 

总结

以上也是在网上使用的比较多的方案,本文进行简单总结分析,欢迎大家交流

Spring Cloud是一个用于构建分布式系统的开发工具包,它提供了一系列的组件和工具,用于简化分布式系统的开发和部署。而Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。 当Spring CloudKubernetes结合使用时,可以实现更高级别的服务治理和部署管理。具体来说,Spring Cloud可以利用Kubernetes的强大功能来管理和调度应用程序的容器实例,实现自动化的容器部署、伸缩和故障恢复。同时,Spring Cloud还可以通过与Kubernetes的集成,实现服务注册与发现、负载均衡、断路器等分布式系统的核心功能。 在使用Spring Cloud依赖Kubernetes时,你需要引入相应的依赖,并进行配置。具体步骤如下: 1. 引入Spring Cloud Kubernetes依赖: 在你的项目中,添加以下依赖到你的构建文件(如pom.xml)中: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes</artifactId> </dependency> ``` 2. 配置Kubernetes相关信息: 在你的应用程序配置文件(如application.yml)中,添加以下配置信息: ```yaml spring: cloud: kubernetes: enabled: true ``` 3. 使用Kubernetes相关功能: 通过Spring Cloud Kubernetes提供的注解和工具类,你可以使用Kubernetes的功能,例如服务注册与发现、配置管理等。具体使用方法可以参考Spring Cloud Kubernetes的文档和示例。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值