微服务治理热门技术揭秘:无损上线

为什么有了无损下线,还需要无损上线?无损上线可以解决哪些问题?

本篇文章将一一回答这些问题。

无损上线功能不得不说是一个客户打磨出来的功能

我们将从一次发布问题的排查与解决的过程说起。

背景

阿里云内部某应用中心服务在发布过程中出现了大量的 5xx 超时异常。初步怀疑是无损下线问题,于是很快便接入了 MSE 提供的无损下线功能。但是接入无损下线功能后继续发布,应用的发布过程依然存在大量的超时报错。根据业务方同学的反馈,大概应用在启动后 5 秒左右,会有大量超时请求。

无损下线功能未生效?

于是拉了相关的同学开始排查。应用的调用情况如下:gateway - > A -> C 。

发布的应用为 C 应用,发布过程中出现大量超时报错。我们通过相关日志与应用的启动情况,整理如下线索:

【服务端视角】:找了一台 C 应用的机器 xxx.xxx.xxx.60 观察

第一阶段:xxx.xxx.xxx.60 (C 应用)下线阶段

  • 20:27:51 开始重启,执行重启脚本
    • 同时观察到执行了 sendReadOnlyEvent 动作,表明服务端发送只读事件,客户端不会再请求该服务端
    • 在 sendReadOnlyEvent 后,开始陆续执行注销服务动作
  • 20:27:54 注销所有 provider seivce 完成
  • 20:28:15 应用收到 kill -15 信号

第二阶段:xxx.xxx.xxx.60 (C 应用)上线阶段

  • 20:28:34 服务端重新启动
  • 20:29:19 在 Dubbo 注册中心控制台观察到 xxx.xxx.xxx.60 注册完毕
  • 20:29:19,257 日志中看到 start NettyServer

【客户端视角】:找了一台 A 应用的机器 XXX.XXX.XXX.142 观察

  • 20:27:51 received readOnly event,收到服务端发送的只读事件,此时该客户端不会请求至 XXX.XXX.XXX.60 机器
  • 20:27:56 close [xxx.xxx.xxx.142:0 -> /XXX.XXX.XXX.60:20880] ,关闭channel连接

业务日志报错信息

同时搜 C 应用的机器 XXX.XXX.XXX.60 的报错相关的日志,共 237 条日志

其中最早的 time: 2020-07-30 20:29:26,524

其中最晚的 time: 2020-07-30 20:29:59,788

结论

观察这些迹象可以初步得出结论:

  • 无损下线过程均符合预期,并且下线过程中并没有出现任何报错
  • 报错期间处于服务端应用成功启动后且注册成功后,与业务方观察的现象一致

这时候怀疑是上线期间的问题,同时排查服务端相关日志,发在报错期间,服务端线程被打满:

问题定位为上线过程中的问题,与无损下线无关。

无损上线实践

我们帮助用户解决问题的思路:帮助用户发现问题的本质、找到问题的通用性、解决问题、将解决通用问题的能力产品化。

发现用户 Dubbo 版本比较低,缺少自动打线程堆栈的能力:

  • 通过 MSE 增加 Dubbo 线程池满自动 JStack 能力

这是每次发布必现的问题,通过观察线程池满时的 JStack 日志,有助于我们定位问题。

阻塞在异步连接等资源准备上

初步观察 JStack 日志,发现不少线程阻塞在 taril/druid 等异步连接资源准备上:

同时我们云上也有有客户遇到过,应用启动后一段时间内 Dubbo 线程池满的问题,后经过排查由于 Redis 连接池中的连接未提前建立,流量进来后大量线程阻塞在 Redis 连接建立上。

连接池通过异步线程保持连接数量,默认在应用启动后 30 秒建立最小连接数的连接。

1、解决思路

  • 提前建立连接
  • 使用服务延迟发布特性

2、预建连接

以 JedisPool 预建连接为例,提前建立 Redis 等连接池连接,而不是等流量进来后开始建立连接导致大量业务线程等待连接建立。

 

JedisPool 通过定时任务去异步保证最小连接数的建立,但这会导致应用启动时,Redis 连接并未建立完成。

主动预建连接方式:在使用连接之前使用 GenericObjectPool#preparePool 方法去手动去准备连接。

在微服务上线过程中,在初始化 Redis 的过程中提前去创建 min-idle 个 redis 连接,确保连接建立完成后再开始发布服务。

同样有类似问题,预建数据库连接等异步建连逻辑,保证在业务流量进来之前,异步连接资源一切就绪。

3、延迟发布

延迟发布为了一些需要异步加载的前置资源如提前准备缓存资源,异步下载资源等,需要控制服务注册时机,即控制流量进入的时机保证服务所需的前置资源准备完成该服务才可以进行发布,延迟发布有两种方式

  • 通过 delay 配置方式

通过指定 delay 大小例如 300 s,Dubbo/Spring Cloud 服务将会在 Spring 容器初始化完成后进行后等待 5 分钟,再执行服务注册逻辑。

  • online 命令上线

通过打开默认不注册服务配置项,再配合发布脚本等方式执行 curl 127.0.0.1:54199/online 地址触发主动注册。我们可以在前置资源准备完成后,通过 online 命令去注册服务。

也可以在 MSE 实例详情通过服务上线去注册服务。

阻塞在 ASMClassLoader 类加载器上

大量线程阻塞在 fastjson 的 ASMClassLoader 类加载器加载类的过程中,翻看 ClassLoader 加载类的代码其默认是同步类加载。在高并发场景下会导致大量线程阻塞在类加载上,从而影响服务端性能,造成线程池满等问题。

 

1、解决思路

  • 开启类加载器并行加载

2、类加载器开启并行类加载

JDK7 上,如果调用下面的方法,则会开启并行类加载功能,把锁的级别从 ClassLoader 对象本身,降低为要加载的类名这个级别。换句话说只要多线程加载的不是同一个类的话,loadClass 方法都不会锁住。

我们可以看 Classloader.registerAsParallelCapable 方法的介绍

protected static boolean registerAsParallelCapable()
Registers the caller as parallel capable.
The registration succeeds if and only if all of the following conditions are met:
1. no instance of the caller has been created
2. all of the super classes (except class Object) of the caller are registered as parallel capable
Classloader.registerAsParallelCapable

它要求注册该方法时,其注册的类加载器无实例并且该类加载器的继承链路上所有类加载器都调用过registerAsParallelCapable,对于低版本的 Tomcat/Jetty webAppClassLoader 以及 fastjson 的 ASMClassLoader 都未开启类加载,如果应用里面有多个线程在同时调用 loadClass 方法进行类加载的话,那么锁的竞争将会非常激烈。

MSE Agent 通过无侵入方式在类加载器被加载前开启其并行类加载的能力,无需用户升级 Tomcat/Jetty,同时支持通过配置动态开启类加载并行类加载能力。

其他一些问题

  • JVM JIT 编译问题引起 cpu 飙高
  • 日志同步打印导致线程阻塞
  • Jetty 低版本类加载类同步加载
  • K8s 场景下,微服务与 K8s Service 生命周期未对齐

1、解决思路

  • 服务预热
    • 客户端负载均衡
    • 服务端服务分层发布
  • 业务日志异步化
  • 提供微服务 Readiness 接口

2、业务日志异步化

同步进行日志打印,由于日志打印使用的是业务线程,由于日志打印过程中存在序列化、类加载等逻辑,在高并发的场景下会导致业务线程hang住,导致服务框架线程池满等问题。MSE Agent 支持动态使用异步日志打印能力,将日志打印任务与业务线程分开,提高业务线程吞吐量。

3、小流量预热

应用启动后,大量请求进入,导致应用存在许多问题,所以需要微服务的一些能力来解决服务预热问题:

  • JVM JIT 编译线程占用 CPU 过高,CPU/load 短期内飙高,Dubbo 处理请求性能下降
  • 瞬时请求量过大,导致线程阻塞在类加载、缓存等,从而导致 Dubbo 服务线程池满

小流量预热,MSE 服务治理通过 OneAgent 无侵入提供了以下几种能力:

  • 客户端负载均衡

通过增强客户端负载均衡能力,对于刚上线的需要预热的节点进行流量权重的调整,做到刚上线的应用按照用户所配置的规则进行小流量预热,用户只需指定预热规则即可按照预期对刚上线的节点进行小流量预热

业务方的一台服务端实例使用服务预热后的效果:服务预热开启后,待预热的应用将在预热周期内通过小流量实现应用启动过程的预热初始化。下图预热时长为 120 秒,预热曲线为 2 次的预热效果图:

说明 该测试 Demo 是定时伸缩模拟应用启动,因此除了预热过程,还包含应用下线的过程。下图预热时长为 120 秒,预热曲线为 5 次的预热效果图:

如上图所示,相比于 2 次预热过程,5 次预热过程刚启动的这段时间(即17:41:01~17:42:01),QPS 一直保持在一个较低值,以满足需要较长时间进行预热的复杂应用的预热需求。

  • 服务端分层发布

通过修改服务注册的逻辑,增加对应用 load 等指标的监控,对服务进行分批注册已经回滚注册等逻辑,保证服务注册过程中,流量分服务进入,系统 load 始终低于阈值,并且需要在指定时长内将服务注册上去。

缺点:在应用的服务流量平均,不存在超热点接口的情况下,分层发布可以很好地解决服务预热问题。但是如果应用存在一些超热服务,可能这个服务几乎占所有流量 90% 以上,那服务端分层发布效果并不会很明显。

注意:对于一些存在依赖的服务接口,服务分层发布可能需要业务梳理服务分批发布的顺序

4、打通 K8s 与微服务生命周期

K8s 提供两种健康检查机制:

  • livenessProbe,用于探测不健康的 Pod,探测失败将会重启 Pod。
  • readinessProbe,用于探测一个 Pod 是否就绪接受流量,探测失败将会在 Service 路由上摘取该节点。

如果不配置 readinessProbe ,默认只检查容器内进程是否启动运行,而对于进程的运行情况很难考量,Mse Agent 通过对外提供 readiness 接口,只有 Spring Bean 初始化完成以及异步资源准备就绪并且开始服务注册时, readiness 才返回 200。将微服务侧的服务暴露与 K8s Service 体系打通,使 K8s 管控能感知到进程内部的服务就绪时机,从而进行正确地服务上线。

我们需要在 MSE 无损上线页面开启无损滚动发布的配置:

同时给应用配置 K8s 的就绪检查接口,如果您的应用在阿里云容器服务 ACK 上,可以在阿里云容器 ACK 服务对应应用配置的中健康检查区域,选中就绪检查右侧的开启,配置如下参数,然后单击更新。

该应用在下次重启时,该配置即可生效。

5、服务并行订阅与注册

通过并行的服务注册与订阅,可以大幅提升应用启动的速度,解决服务启动慢的问题。

以并行服务订阅为例:

如上图所示,通过 Java Agent 将服务框架 refer 的流程从 SpringBean 的初始化流程中剥离出来并且通过异步线程来实现服务的并行订阅与注册。

总结

通过不断地观察业务情况,然后进行不断地问题分析思考与解决的尝试,直到开启了服务小流量预热能力后,彻底解决了业务团队应用在上线期间线程池满导致请求有损的问题。

  • 发布期间 Exception 总量与发布日期(包含无损上线功能陆续上线的节点)的情况如下图

9 月 15 号发布了服务小流量预热能力后,发布期间相关 Exception 下降至 2。(经业务方确认不是因为发布引起的,可以忽略)

上线了无损上线功能后,业务团队的应用中心持续多个月的发布报错问题总算告一段落,但是无损上线功能远不止于此。还解决许多云上客户上线有损的情况,功能的能力与场景也在不断地解决问题中逐渐完善与丰富。

MSE 无损上线

MSE 服务治理一个特点是通过 Agent 无侵入地支持市面上近五年来 Dubbo、Spring Cloud 所有版本,所以无损上线这个功能也会是如此,下面会以 Dubbo 为例子无损上线的功能,当然所有能力我们都是无缝支持 Dubbo、Spring Cloud 的。

下面开始系统地介绍一下 MSE 服务治理的无损上线,我们可以先从开源的一个 Dubbo 应用上线的流程开始分析:

  • 应用初始化,Spring Bean容器初始化
  • 收到 ContextRefreshedEvent后,Dubbo 会去拉取 Dubbo应用所需的配置、元数据等
  • exportServices 注册服务

开源 Dubbo 上线流程还是非常完善与严谨,但是依旧存在一些场景会导致服务上线存在问题:

  • 当服务信息注册到注册中心后,在消费者看来该服务就是可以被调用的。然而,此时可能存在一些数据库、缓存资源等一些异步资源尚未加载完毕的场景,这取决于你的系统有没有对应的组件,它们何时加载完毕,也完全取决于你的业务。
  • 如果在大流量的场景下,服务在注册到注册中心后,马上有大流量进入,存在一系列问题,导致线程阻塞,对业务流量造成损失
    • 比如 Redis 的 JedisPool 连接池创建后并不会立即建立连接,会在流量进来后开始建立连接,如果一开始涌进的是大流量,则导致大量线程阻塞在连接池重的连接的建立上
    • FastJson 以及 Jetty/tomcat 等低版本中,并未开启类加载器并行类加载能力,导致大量线程阻塞在类加载器加载类上
    • JVM JIT 编译问题引起 cpu 飙高
    • 线程阻塞在业务日志上
  • 云原生场景下,微服务与 K8s 的生命周期未对齐的情况
    • 滚动发布,重启的 pod 还未注册至注册中心,但是 readiness 检查以及通过。导致第一个 pod 还未注册至注册中心,最后一个 pod 以及下线,导致短时间内的客户端 NoProvider 异常

针对如上问题,MSE 服务治理不仅提供了完整的解决方案,还提供了白屏化开箱即用的能力,动态配置实时生效。

同时 MSE 服务治理针对无损上下线的场景还提供了完整的可观测能力。

无损上线功能可以总结为以下这张图:

不只是无损上下线

无损上下线能力是微服务流量治理中的重要的一环,当然除了无损下线,MSE 还提供了全链路灰度、流控降级与容错、数据库治理等一系列的微服务治理能力。服务治理是微服务改造深入到一定阶段之后的必经之路,在这个过程中我们不断有新的问题出现。

  • 除了无损上下线,服务治理还有没其他能力?
  • 服务治理能力有没一个标准的定义,服务治理能力包含哪些?
  • 多语言场景下,有无全链路的最佳实践或者标准?
  • 异构微服务如何可以统一治理?

当我们在探索服务治理的过程中,我们在对接其他微服务的时候,我们发现治理体系不同造成的困扰是巨大的,打通两套甚者是多套治理体系的成本也是巨大的。为此我们提出了 OpenSergo 项目。OpenSergo 要解决的是不同框架、不同语言在微服务治理上的概念碎片化、无法互通的问题。

作者:十眠

原文链接

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

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

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

相关文章

深度强化学习技术概述

深度强化学习介绍 强化学习主要用来学习一种最大化智能体与环境交互获得的长期奖惩值的策略,其常用来处理状态空间和动作空间小的任务,在如今大数据和深度学习快速发展的时代下,针对传统强化学习无法解决高维数据输入的问题,2013…

大屏小程序探索实践 | Cube 技术解读

所谓大屏小程序,是以 Cube 小程序技术栈 为载体,运行在智能电视或智能机顶盒等设备上的一种小程序形态。这些设备的主要特点是: 以 Android 系统为主,系统版本普遍较低,有些设备依然停留在 Android 4.2,An…

阿里云解决方案架构师张平:云原生数字化安全生产的体系建设

关于今天的分享主题——“安全生产”,内容主要分为三大部分: 第一部分是安全生产的背景,以及我们对于安全生产这个领域的理解;第二部分主要介绍阿里巴巴集团的安全生产工作到底是怎么开展的,借此给各位有作为参考和借…

从斜边之长为L的一切直角三角形中,求有最大周长的直角三角形.(多元函数的极值及其求法)

三条直线围成的直角三角形三个顶点A(16,0),B(0,8),C(0,0),设点(x,y)到AB,BC,AC的距离分别是d1,d2,d3,有: |AB|*d1|BC|*d2|AC|*d32S(ABC) 而(|AB|*d1|BC|*d2AC*d3)^24S^(ABC)/(|AB|^2|BC|^2|AC|^2)128/5 等号成立当且仅当|AB|/d1|BC|/d2|AC|/d3 就是40/|x2y-16|8/|x|16/|y| …

全链路灰度新功能:MSE上线配置标签推送

为什么需要配置标签推送 从全链路灰度谈起 在微服务场景中,应用的灰度发布迎来了新的挑战。不同于单体架构中将应用整体打包即可发布测试版本,微服务应用往往由多个服务组合而成。这些服务通常由不同的团队负责,独立进行开发。一个新功能通…

动态尺寸模型优化实践之 Shape Constraint IR Part I

在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考。本次分享的是我们最近开展的有关shape constraint IR的工作,鉴于篇幅较长,为了提升阅读体验,我们将分享拆分为两个部分: Part I 中我们将介绍问…

云原生事件驱动引擎(RocketMQ-EventBridge)应用场景与技术解析

在刚刚过去的 RocketMQ Summit 2022 全球开发者峰会上,我们对外正式开源了我们的新产品 RocketMQ-Eventbridge 事件驱动引擎。 RocketMQ 给人最大的印象一直是一个消息引擎。那什么是事件驱动引擎?为什么我们这次要推出事件驱动引擎这个产品&#xff1f…

动态尺寸模型优化实践之 Shape Constraint IR Part II

在本系列分享中我们将介绍BladeDISC在动态shape语义下做性能优化的一些实践和思考。本次分享的是我们最近开展的有关shape constraint IR的工作,鉴于篇幅较长,为了提升阅读体验,我们将分享拆分为两个部分: Part I 中我们将介绍问…

PolarDB 助力易仓打造跨境行业生态链协同的产业链 SaaS

2022年7月,易仓ECCANG WMS东南亚版正式上线!专为东南亚海外仓业务打造,帮助东南亚海外仓企业排忧解难,实现订单、仓库、人员、财务高效管理。易仓科技是头部的跨境行业SaaS服务商,其生态涵盖了300工厂、100000卖家、17…

iLogtail 社区版使用入门 - 采集 MySQL Binlog

iLogtail是阿里云日志服务(SLS)团队自研的可观测数据采集Agent,拥有的轻量级、高性能、自动化配置等诸多生产级别特性,可以署于物理机、虚拟机、Kubernetes等多种环境中来采集遥测数据。iLogtail在阿里云上服务了数万家客户主机和…

融合数据库生态:利用 EventBridge 构建 CDC 应用

引言 CDC(Change Data Capture)指的是监听上游数据变更,并将变更信息同步到下游业务以供进一步处理的一种应用场景。近年来事件驱动架构(EDA)热度逐步上升,日渐成为项目架构设计者的第一选择。EDA 天然契合…

Pandas+ SLS SQL:融合灵活性和高性能的数据透视

Pandas是什么 Pandas是一个十分强大的python数据分析工具,也是各种数据建模的标准工具。Pandas擅长处理数字型数据和时间序列数据。Pandas的第一大优势在于,封装了一些复杂的代码实现过程,只需要调用接口就行了,避免了编写大量的…

iLogtail 开源之路

2022年6月底,阿里云iLogtail代码完整开源,正式发布了完整功能的iLogtail社区版。iLogtail作为阿里云SLS官方标配的采集器,多年以来一直稳定服务阿里集团、蚂蚁集团以及众多公有云上的企业客户,目前已经有千万级的安装量&#xff0…

迁移 Nacos 和 ZooKeeper,有了新工具

背景 注册中心迁移在行业中主要有两个方案,一个是双注册双订阅模式(类似数据库双写),一个是 Sync 模式(类似于数据库 DTS);MSE 同时支持了两种模式,对于开通 MSE 服务治理客户&…

基于 Serverless+OSS 分分钟实现图片秒变素描

场景介绍 小明接到学校老师安排的任务,需要批量将班级里同学们拍的普通照片转换为素描图,供课堂游戏使用,于是求助到程序员老爸,机智的程序员老爸分分钟用几行Python代码解决:在阿里云Serverless函数计算服务中部署普…

解析 RocketMQ 业务消息 - “顺序消息”

引言 Apache RocketMQ 诞生至今,历经十余年大规模业务稳定性打磨,服务了阿里集团内部业务以及阿里云数以万计的企业客户。作为金融级可靠的业务消息方案,RocketMQ 从创建之初就一直专注于业务集成领域的异步通信能力构建。本篇将继续业务消息…

Koordinator 0.6:企业级容器调度系统解决方案,引入 CPU 精细编排、资源预留与全新的重调度框架

阿里云原生开源的混部系统 Koordinator 基于阿里超大规模混部生产实践经验而来,旨在为用户打造云原生场景下接入成本最低、混部效率最佳的解决方案,助力用户企业实现云原生后提升计算资源利用率、降低 IT 成本。 经过社区多位成员的贡献,Koor…

KubeVela Maintainer 徐佳航:什么样的开源项目将具有可延续的生命力?

云原生的技术价值喻示着它就是未来,加入到一个具有可延续性生命力的开源社区,可以帮助我们更快地到达那里。——徐佳航,KubeVela Maintainer,来自招商银行基础设施研发中心云平台及运维平台开发团队。来自招商银行基础设施研发中心…

龙蜥社区首推“分层分类”顶设 发展以云为终态的开源产业创新生态

在刚刚结束的 2022 开放原子全球开源峰会 OpenAnolis 分论坛上,龙蜥社区技术委员会主席杨勇做了《OpenAnolis 社区技术发展报告》的主题演讲,分享龙蜥社区如何从 0 到 1 实现原生社区布局,以及发展以云为终态的开源产业创新生态。 全文整理如…

友邦人寿可观测体系设计与落地

业务场景与挑战 友邦保险是香港联合交易所上市的人寿保险集团,覆盖 18 个市场。截至 2021 年 12 月 31 号,总资产 3400 亿美元。 友邦保险于 1992 年在上海设立分公司,是改革开放后最早一批获发个人人身保险业务营业执照的非本土保险机构之…