AG娱乐官方网,真人、体育、棋牌、彩票、电竞、电子、捕鱼信誉无忧值得信赖

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

  无损上Xiàn实践

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

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

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

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

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

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

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

  连接池通Guò异步线程保持连接数量,默Rèn在应Yòng启动后 30 秒建立最小连接Shù的连接。

  1.解决思路

  提前建Lì连接
使用服务延迟发布特性

2.预建连接

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

  org.apache.commons.pool2.impl.GenericObjectPool #startEvictor

  protectedsynchronized voidstartEvictor( longdelay ) {

  if( null!= _evictor) {

  EvictionTimer.cancel(_evictor);

  _evictor = null;

  }

  if(delay > 0) {

  _evictor = newEvictor;

  EvictionTimer.schedule(_evictor, delay, delay);

  }

  }

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

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

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

  同样Yǒu类似问题,预建数据Kù连接等异步建连逻辑,保证在业务流量进来之前,异步连接资源一Qiè就绪。

  3.延迟发布

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

  通过 delay 配置方Shì

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

  online 命Lìng上线

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

  也可以在 MSE 实例详情通过服务上XiànQù注册Fù务。

  Zǔ塞在 ASMClassLoader 类Jiā载器上

  AG娱乐官方网,真人、体育、棋牌、彩票、电竞、电子、捕鱼信誉无忧值得信赖ag5622.com 大量线程阻塞在 fastjson 的 ASMClassLoader 类加Zài器加载类的过程中,翻看 ClassLoader 加载类的Dài码其默认是同Bù类加载。在高并发场景下会导致大量线程阻塞在类加载上,从而影响服务端性能,造成线程池满等问题。

  privateClassLoader( Void unused, ClassLoader parent) {

  this.parent = parent;

  // 开启并行类加载

  if(ParallelLoaders.isRegistered( this.getClass)) {

  parallelLockMap = newConcurrentHashMap<>;

  package2certs = newConcurrentHashMap<>;

  domains =

  Collections.synchronizedSet( newHashSet);

  assertionLock = newObject;

  } else{

  // no finer-grained lock; lock on the classloader instance

  parallelLockMap = null;

  package2certs = newHashtable<>;

  domains = newHashSet<>;

  assertionLock = this;

  }

  }

  protectedClass loadClass(String name, boolean resolve)

  throws ClassNotFoundException

  {

  synchronized (getClassLoadingLock(name)) {

  returnc;

  }

  }

  protectedObject getClassLoadingLock( String className) {

  Object lock= this;

  //如果开启类加载器并行类加载,则锁在所加载的类上,而不是Lèi加载Qì上

  if(parallelLockMap != null) {

  Object newLock = newObject;

  lock= parallelLockMap.putIfAbsent(className, newLock);

  if( lock== null) {

  lock= newLock;

  }

  }

  returnlock;

  }

  1.解决思路

  开启类加载器并行加载

2.类加载器开Qǐ并行类加载

  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

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

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

  其他一些问题

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

1.解决思路

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

2.业务日志异步化

  同步进行日志打印,由于日志打Yìn使用De是业务线程,由于日志打印过程中Cún在Xù列化、类加Zài等逻辑,在高并发的场景下会Dǎo致业务线程hang住,导致服务框架线程池满等问题。MSE Agent 支持动态使用异Bù日志打印能力,将日志打印任务与业务线程分开,提高业务线程吞吐量。

  3.Xiǎo流量预热

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

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

小流量预热,MSE 服务治理通过 OneAgent 无QīnRùTí供了以下Jǐ种能力:

  客户端负载均衡

通过增强客户端负载均衡能力,对于刚上Xiàn的需Yào预Rè的节点进行流量权重的调整,做到刚上线的应用按照用户所配置的规则进行小流量预热,用户只需指定预热Guī则即可按照预期对刚Shàng线的节点进行小流Liàng预热

  业务方的一Tái服务端实例Shǐ用服务预热Hòu的效果:

  服务预热开启后,待预Rè的应用将在Yù热周期内通过小流量实现Yīng用启Dòng过程的预热初始化。下图预热时长为 120 秒,预热曲线为 2 次的预热效果图:

  说明 该测试 Demo 是定时伸缩模拟应用Qǐ动,因此Chú了预热过Chéng,还包含应用下线的过程。下图预热时长为 120 秒,预热曲线为 5 次的预热Xiào果图:

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

  Fù务端分层发布

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

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

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

  4.打Tōng K8s 与Wēi服务生命周期

  K8s 提供两Zhòng健康检查机制:

  livenessProbe,用于探测不健康的 Pod,Tàn测失败将会重启 Pod。
readinessProbe,Yòng于探测一个 Pod 是否就绪接受流量,探测失败将会Zài Service 路由上摘取该节点。

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

  Wǒ们需要在 MSE 无损上线页Miàn开启无损滚动发布的配置:

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

  该Yīng用在下次Zhòng启时,该配置即可生效。

  5.服务并行订阅与注册

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

  以并行服务订阅为例:

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

  总结

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

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

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

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

  MSE 无损上Xiàn

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

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

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

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

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

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

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

  无损上线功能可以总结为以下这Zhāng图: