K8s有损发布问题探究

问题提出

流量有损是在应用发布时的常见问题,其现象通常会反馈到流量监控上,如下图所示,发布过程中服务RT突然升高,造成部分业务响应变慢,给用户的最直观体验就是卡顿;或是请求的500错误数突增,在用户侧可能感受到服务降级或服务不可用,从而影响用户体验。

因为应用发布会伴随流量有损,所以我们往往需要将发布计划移到业务低谷期,并严格限制应用发布的持续时间,尽管如此,还是不能完全避免发布带来的风险,有时甚至不得不选择停机发布。EDAS作为一个通用应用管理系统,应用发布是其最基本的功能之一,而K8s 应用是EDAS中最普遍的应用的形态,下文将通过对EDAS客户真实场景的归纳,从K8s的流量路径入手,分析有损发布产生的原因,并提供实用的解决方案。

流量路径分析

K8s中,流量通常可以从以下几种路径进入到应用Pod中,每条路径大相径庭,流量损失的原因各不相同。我们将分情况探究每种路径的路由机制,以及Pod变更对流量路径的影响。

LB Service流量

通过LoadBalancer类型Service访问应用时,流量路径中核心组件是LoadBalancer和ipvs/iptables。LoadBalancer负责接收K8s集群外部流量并转发到Node节点上,ipvs/iptables负责将节点接收到的流量转发到Pod中。核心组件的动作由CCM(cloud-controller-manager)和kube-proxy驱动,分别负责更新LoadBalancer后端和ipvs/iptables规则。

在应用发布时,就绪的Pod会被添加到Endpoint后端,Terminating状态的Pod会从Endpoint中移除。kube-proxy组件会更新各节点的ipvs/iptables规则,CCM组件监听到了Endpoint的变更后会调用云厂商API更新负载均衡器后端,将Node IP和端口更新到后端列表中。流量进入后,会根据负载均衡器配置的监听后端列表转发到对应的节点,再由节点ipvs/iptables转发到实际Pod。

Service支持设置externalTrafficPolicy,根据该参数的不同,节点kube-proxy组件更新ipvs/iptables列表及CCM更新负载均衡器后端的行为会有所不同:

  • Local模式:CCM 仅会将目标服务所在节点添加入负载均衡后端地址列表。流量到达该节点后仅会转发到本节点的Pod中。
  • Cluster模式:CCM会将所有节点都添加到负载均衡后端地址列表。流量到达该节点后允许被转发到其他节点的Pod中。

Nginx Ingress流量

通过Nginx Ingress提供的SLB访问应用时,流量路径核心组件为Ingress Controller,它不但作为代理服务器负责将流量转发到后端服务的Pod中,还负责根据Endpoint更新网关代理的路由规则。

在应用发布时,Ingress Controller会监听Endpoint的变化,并更新Ingress网关路由后端,流量进入后会根据流量特征转发到匹配规则上游,并根据上游后端列表选择一个后端将请求转发过去。

默认情况下,Controller在监听到Service的Endpoint变更后,会调用Nginx中的动态配置后端接口,更新Nginx网关上游后端列表为服务Endpoint列表,即Pod的IP和端口列表。因此,流量进入Ingress Controller后会被直接转发到后端Pod IP和端口。

微服务流量

使用微服务方式访问应用时,核心组件为注册中心。Provider启动后会将服务注册到注册中心,Consumer会订阅注册中心中服务的地址列表。

在应用发布时,Provider启动后会将Pod IP和端口注册到注册中心,下线的Pod会从注册中心移除。服务端列表的变更会被消费者订阅,并更新缓存的服务后端Pod IP和端口列表。流量进入后,消费者会根据服务地址列表由客户端负载均衡转发到对应的Provider Pod中。

原因分析与通用解决方案

应用发布过程其实是新Pod上线和旧Pod下线的过程,当流量路由规则的更新与应用Pod上下线配合出现问题时,就会出现流量损失。我们可以将应用发布中造成的流量损失归类为上线有损和下线有损,总的来看,上线和下线有损的原因如下,后文将分情况做更深入讨论:

  • 上线有损:新Pod上线后过早被加入路由后端,流量被过早路由到了未准备好的Pod。
  • 下线有损:旧Pod下线后路由规则没有及时将后端移除,流量仍路由到了停止中的Pod。

上线有损分析与对策

K8s中Pod上线流程如下图所示:

如果在Pod上线时,不对Pod中服务进行可用性检查,这会使得Pod启动后过早被添加到Endpoint后端,后被其他网关控制器添加到网关路由规则中,那么流量被转发到该Pod后就会出现连接被拒绝的错误。因此,健康检查尤为重要,我们需要确保Pod启动完成再让其分摊线上流量,避免流量损失。K8s为Pod提供了readinessProbe用于校验新Pod是否就绪,设置合理的就绪探针对应用实际的启动状态进行检查,进而能够控制其在Service后端Endpoint中上线的时机。

基于Endpoint流量场景

对于基于Endpoint控制流量路径的场景,如LB Service流量和Nginx Ingress流量,配置合适的就绪探针检查就能够保证服务健康检查通过后,才将其添加到Endpoint后端分摊流量,以避免流量损失。例如,在Spring Boot 2.3.0以上版本中增加了健康检查接口/actuator/health/readiness和/actuator/health/liveness以支持配置应用部署在K8S环境下的就绪探针和存活探针配置:

 

微服务流量场景

对于微服务应用,服务的注册和发现由注册中心管理,而注册中心并没有如K8s就绪探针的检查机制。并且由于JAVA应用通常启动较慢,服务注册成功后所需资源均仍然可能在初始化中,比如数据库连接池、线程池、JIT编译等。如果此时有大量微服务请求涌入,那么很可能造成请求RT过高或超时等异常。

针对上述问题,Dubbo提供了延迟注册、服务预热的解决方案,功能概述如下:

  • 延迟注册功能允许用户指定一段时长,程序在启动后,会先完成设定的等待,再将服务发布到注册中心,在等待期间,程序有机会完成初始化,避免了服务请求的涌入。
  • 服务预热功能允许用户设定预热时长,Provider在向注册中⼼注册服务时,将⾃身的预热时⻓、服务启动时间通过元数据的形式注册到注册中⼼中,Consumer在注册中⼼订阅相关服务实例列表,根据实例的预热时长,结合Provider启动时间计算调用权重,以控制刚启动实例分配更少的流量。通过小流量预热,能够让程序在较低负载的情况下完成类加载、JIT编译等操作,以支持预热结束后让新实例稳定均摊流量。

我们可以通过为程序增加如下配置来开启延迟注册和服务预热功能:

 

配置以上参数后,我们通过为Provider应用扩容一个Pod,来查看新Pod启动过程中的QPS曲线以验证流量预热效果。QPS数据如下图所示:

根据Pod接收流量的QPS曲线可以看出,在Pod启动后没有直接均摊线上的流量,而是在设定的预热时长120秒内,每秒处理的流量呈线性增长趋势,并在120秒后趋于稳定,符合流量预热的预期效果。

下线有损分析与对策

在K8s中,Pod下线流程如下图所示:

从图中我们可以看到,Pod被删除后,状态被endpoint-controller和kubelet订阅,并分别执行移除Endpoint和删除Pod操作。而这两个组件的操作是同时进行的,并非我们预期的按顺序先移除Endpoint后再删除Pod,因此有可能会出现在Pod已经接收到了SIGTERM信号,但仍然有流量进入的情况。

K8s在Pod下线流程中提供了preStop Hook机制,可以让kubelet在发现Pod状态为Terminating时,不立即向容器发送SIGTERM信号,而允许其做一些停止前操作。对于上述问题的通用方案,可以在preStop中设置sleep一段时间,让SIGTERM延迟一段时间再发送到应用中,可以避免在这段时间内流入的流量损失。此外,也能允许已被Pod接收的流量继续处理完成。

上面介绍了在变更时,由于Pod下线和Endpoint更新时机不符合预期顺序可能会导致的流量有损问题,在应用接入了多种类型网关后,流量路径的复杂度增加了,在其他路由环节也会出现流量损失的可能。

LB Service流量场景

在使用LoadBalancer类型Service访问应用时,配置Local模式的externalTrafficPolicy可以避免流量被二次转发并且能够保留请求包源IP地址。

应用发布过程中,Pod下线并且已经从节点的ipvs列表中删除,但是由CCM监听Endpoint变更并调用云厂商API更新负载均衡器后端的操作可能会存在延迟。如果新Pod被调度到了其他的节点,且原节点不存在可用Pod时,若负载均衡器路由规则没有及时更新,那么负载均衡器仍然会将流量转发到原节点上,而这条路径没有可用后端,导致流量有损。

此时,在Pod的preStop中配置sleep虽然能够让Pod在LoadBalancer后端更新前正常运行一段时间,但却无法保证kube-proxy在CCM移除LoadBalancer后端前不删除节点中ipvs/iptables规则的。场景如上图所示,在Pod下线过程中,请求路径2已经删除,而请求路径1还没有及时更新,即使sleep能够让Pod继续提供一段时间服务,但由于转发规则的不完整,流量没有被转发到Pod就已经被丢弃了。

解决方案:

  • 设置externalTrafficPolicy为Cluster能够避免流量下线损失。因为Cluster模式下集群所有节点均被加入负载均衡器后端,且节点中ipvs维护了集群所有可用Pod列表,当本节点中不存在可用Pod时,可以二次转发到其他节点上的Pod中,但是会导致二次转发损耗,并且无法保留源IP地址。
  • 设置Pod原地升级,通过为Node打特定标签的方式,设置新Pod仍然被调度到本节点上。那么该流程无需调用云厂商API进行负载均衡器后端更新,流量进入后会转发到新Pod中。

Nginx Ingress流量场景

对于Nginx Ingress,默认情况下流量是通过网关直接转发到后端PodIP而非Service的ClusterIP。在应用发布过程中,Pod下线,并由Ingress Controller监听Endpoint变更并更新到Nginx网关的操作存在延迟,流量进入后仍然可能被转发到已下线的Pod,此时就会出现流量损失。

解决方案:

  • Ingress注解“http://nginx.ingress.kubernetes.io/service-upstream”支持配置为“true”或“false”,默认为“false”。设置该注解为“true”时,路由规则使用ClusterIP为Ingress上游服务地址;设置为“false”时,路由规则使用Pod IP为Ingress上游服务地址。由于Service的ClusterIP总是不变的,当Pod上下线时,无需考虑Nginx网关配置的变更,不会出现上述流量下线有损问题。但需要注意的是,当使用该特性时流量负载均衡均由K8s控制,一些Ingress Controller特性将会失效,如会话保持、重试策略等。
  • 在Pod的preStop设置sleep一段时间,让Pod接收SIGTERM信号前等待一段时间,允许接收并处理这段时间内的流量,避免流量损失。

微服务流量场景

在Provider应用发布的过程中,Pod下线并从注册中心注销,但消费者订阅服务端列表变更存在一定的延迟,此时流量进入Consumer后,若Consumer仍没有刷新serverList,仍然可能会访问到已下线的Pod。

对于微服务应用Pod的下线,服务注册发现是通过注册中心而非不依赖于Endpoint,上述endpoint-controller移除Endpoint并不能实现Pod IP从注册中心下线。仅仅在preStop中sleep仍然无法解决消费者serverList缓存刷新延迟问题。为了旧Pod能够优雅下线,在preStop中需要首先从注册中心下线,并能够处理已经接收的流量,还需要保证下线前消费者已经将其客户端缓存的Provider实例列表刷新。下线实例可以通过调用注册中心接口,或在程序中调用服务框架所提供的接口并设置到preStop以达到上述效果,在EDAS中可以直接使用http://localhost:54199/offline:

 

企业级一站式解决方案

上面我们对应用发布过程中三种常用流量路径的流量有损问题进行了原因分析并给出了解决方案。总的来说,为了保证流量无损,需要从网关参数和Pod生命周期探针和钩子来保证流量路径和Pod上下线的默契配合。EDAS在面对上述问题时,提供了无侵入式的解决方案,无需更改程序代码或参数配置,在EDAS控制台即可实现应用无损上下线。如下图所示:

  • LB Service支持配置外部流量策略(externalTrafficPolicy)

  • Nginx Ingress支持配置“http://nginx.ingress.kubernetes.io/service-upstream”注解

  • 微服务应用配置无损上线参数

除此之外,EDAS还提供了多种流量网关管理方式,如Nginx Ingress、ALB Ingress、云原生网关,也为应用的发布提供了多种部署方式,如分批发布、金丝雀发布,还提供了不同维度的可观测手段,如Ingress监控、应用监控。在EDAS平台管理应用,能够轻松实现多种部署场景下的无损上下线。

原文链接

本文为阿里云原创内容,未经允许不得转载。

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

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

相关文章

解读 K8s Pod 的13种典型异常

在K8s中,Pod作为工作负载的运行载体,是最为核心的一个资源对象。Pod具有复杂的生命周期,在其生命周期的每一个阶段,可能发生多种不同的异常情况。K8s作为一个复杂系统,异常诊断往往要求强大的知识和经验储备。结合实战…

实践教程之如何快速使用 PolarDB-X

PolarDB-X 为了方便用户体验,提供了免费的实验环境,您可以在实验环境里体验 PolarDB-X 的安装部署和各种内核特性。除了免费的实验,PolarDB-X 也提供免费的视频课程,手把手教你玩转 PolarDB-X 分布式数据库。 本期实验可以让您快…

实践教程之如何将 PolarDB-X 与大数据等系统互通

本期实验将指导您使用PolarDB-XCanalClickHouse搭建实时分析系统。 本期免费实验地址 本期教学视频地址 前置准备 假设已经根据前一讲内容完成了PolarDB-X的搭建部署,可以成功链接上PolarDB-X数据库。 实践教程之如何快速安装部署PolarDB-X 部署Canal Canal是…

加载速度提升 15%,关于 Python 启动加速探索与实践的解析

编者按:在刚刚结束的 PyCon China 2022 大会上,龙蜥社区开发者严懿宸分享了主题为《Python 启动加速的探索与实践》的技术演讲。本次演讲,作者将从 CPython 社区相关工作、本方案的设计及实现,以及业务层面的集成等方面进行介绍。…

统信软件高级工程师:关于云原生技术在容器方面的应用介绍

编者按:随着近几年来云原生生态的不断壮大,众多企业纷纷开展了用云上云的工作,学习云原生及容器技术对于现代工程师是必不可少的。本文整理自龙蜥大讲堂 54 期,统信高级研发工程师参与技术分享,为大家介绍了云原生的介…

解读最佳实践:倚天710 ARM芯片的 Python+AI 算力优化

编者按:在刚刚结束的 PyCon China 2022 大会上,龙蜥社区开发者朱宏林分享了主题为《ARM 芯片的 PythonAI 算力优化》的技术演讲。本次演讲,作者将向大家介绍他们在倚天 710 ARM 芯片上开展的 PythonAI 优化工作,以及在 ARM 云平台…

从敏捷协作到价值交付

前面我的同事在分享的时候,指出目前软件研发的最大问题不是效率,而是研发资源的浪费。可能产品经理半天写的需求,开发要埋头苦干三个月。如果错误的选择了一个对业务发展无益的需求,会带着大家往错误的方向越跑越远。 那么什么是…

行动策略过于复杂怎么办?试试下面一些解决方法

背景 随着使用SLS告警越来越深入,有些用户的行动策略会配置的特别复杂,有些时候可以让用户通过创建多个行动策略来进行一定的精简,但是在一些场景下,用户是无法创建多个行动策略的。例如用户想要通过SLS来统一管理其各个监控系统…

从效能公式解构研发效能

这几年,云原生、Web3.0、元宇宙等技术的出现和应用,正在深刻地改变着我们这个世界。以数字技术应用为主线的数字化转型是此次人类文明变革的核心动力。在这一变革过程中,软件研发模式的发展起到了重至关重要的作用。从早期瀑布式、精益敏捷、…

阿里CCO:基于 Hologres 的亿级明细 BI 探索分析实践

CCO是Chief Customer Officer的缩写,也是阿里巴巴集团客户体验事业部的简称。随着业务的多元化发展以及行业竞争的深入,用户体验问题越来越受到关注。CCO体验业务运营小二日常会大量投入在体验洞察分析中,旨在通过用户的声音数据结合交易、物…

sdut 数字三角形问题

数字三角形问题 Time Limit: 1000MS Memory Limit: 65536KBSubmit Statistic DiscussProblem Description 给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。对于给定的由n行…

SSD( Single Shot MultiBox Detector)关键源码解析

SSD(SSD: Single Shot MultiBox Detector)是采用单个深度神经网络模型实现目标检测和识别的方法。如图0-1所示,该方法是综合了Faster R-CNN的anchor box和YOLO单个神经网络检测思路(YOLOv2也采用了类似的思路,详见YOLO…

YOLO升级版:YOLOv2和YOLO9000解析

论文笔记:YOLO9000: Better, Faster, Stronger;官方网站 评论:YOLO是基于深度学习方法的端到端实时目标检测系统(YOLO:实时快速目标检测)。YOLO的升级版有两种:YOLOv2和YOLO9000。作者采用了一系…

解读Batch Normalization

【活动】Python创意编程活动开始啦!!! CSDN日报20170424 ——《技术方向的选择》 程序员4月书讯:Angular来了!解读Batch Normalization 2016-02-23 16:03 5262人阅读 评论(1) 收藏 举报 本文章已收录于&#xf…

SSD+caffe︱Single Shot MultiBox Detector 目标检测+fine-tuning(二)

承接上一篇SSD介绍:SSDcaffe︱Single Shot MultiBox Detector 目标检测(一) 如果自己要训练SSD模型呢,关键的就是LMDB格式生成,从官方教程weiliu89/caffe来看,寥寥几行code,但是前面的数据整理…

sdut 双向队列(STL)

deque<ll>q;//定义一个双向队列q&#xff0c;类型为long long q.push_front(a);//将a从队首插入队列 q.push_back(a);//将a从队尾插入队列 q.pop_front();//队首弹掉一个元素 q.pop_back();//队尾弹出一个元素 aq.front();//返回队首元素 aq.back();//返回队尾元素 aq.si…

pip install scikit-image on windows 失败 解决方案

到官网下载包 http://www.lfd.uci.edu/~gohlke/pythonlibs/#scikit-image 我们下载 scikit_image‑0.13.0‑cp35‑cp35m‑win_amd64.whl 也可到我的CNDS下载 安装时会出现一下错误 scikit_image-0.13.0-cp34-none-win_amd64.whl is not a supported wheel on this platform…

Caffe训练源码基本流程

苏的专栏 致力于学习计算机视觉、模式识别、机器学习、深度学习相关技术&#xff1a;&#xff1a;&#xff1a;&#xff1a;希望结识更多同道中人。 QQ&#xff1a;2816568984 微信&#xff1a;Suc1011 目录视图 摘要视图 订阅 【活动】2017 CSDN博客专栏评选 【评论送书】…

ubuntu16.04下安装opencv3.2版本

1、下载OpenCV的源码 OpenCV官网上有linux版本的源码包可以下载&#xff0c;不过最好是从git上下载&#xff0c;这样可以保证下载得到的是最新的代码&#xff1a;1 wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.2.0.zip 2 unzip opencv.zip 2、编译安装…

windows 静态IP设置

1.打开cmd&#xff0c;输入ipconfig 记录 IP address 子网掩码 网关 打开 wlan 属性 选中一个网络右键 “属性” 设置 ipv4&#xff0c;选择“使用下面的IP地址” 对应填写 ip地址 子网掩码 网关 tips&#xff1a;DNS建议和网关一样