解锁滴滴ES的性能潜力:JDK 17和ZGC的升级之路

news2024/7/6 18:12:40

前文介绍了滴滴自研的ES强一致性多活是如何实现的,其中也提到为了提升查询性能和解决查询毛刺问题,滴滴ES原地升级JDK17和ZGC,在这个过程中我们遇到了哪些问题,怎样解决的,以及最终上线效果如何,这篇文章就带大家深入了解。

背景

滴滴ES在2020年的时候由2.X升级到7.6.0,该版本是在官方7.6.0的基础上改造而来,支持的是JDK11,采用的垃圾回收器是G1。ES的业务主要分为两类,一类是日志场景,该场景写多读少,高峰期CPU使用率在85%左右,写入性能是它的主要瓶颈;另一类是非日志场景,例如POI检索、订单、支付,这些场景对查询耗时及查询稳定性都有着较高的要求。

随着ES业务数据量的增长,GC导致的查询稳定性压力剧增,已经逐渐无法满足业务需求。以下是ES面临的主要问题:

非日志场景的GC问题

1、Yong GC平均暂停时间长,一些集群的平均暂停时间达到百毫秒级别。

GC暂停时间长在订单集群这种112G大内存的进程中表现尤为明显。下图为订单集群的GC暂停时间,可以发现一次Yang GC的平均暂停时间就达到了200ms,有些甚至超过了1s。ES的核心业务POI、订单等对查询耗时的P99以及Max都有一定的需求,GC暂停导致的查询延时以及毛刺问题无法满足业务需求。

c98c909aaf5c079d5b90837b743a8a0b.png

 订单集群的GC暂停时间

2、Full GC问题频繁,影响集群稳定性。

G1的Full GC会导致GC模式退化为串行扫描整个堆,导致几十秒甚至是分钟级别的暂停。这种长时间的暂停不仅影响用户的查询,还容易造成节点间的通信超时,导致master、dataNode脱离集群,影响集群稳定性。

3、JDK11-G1内存不回收问题频发,如下图所示,通过调优G1参数也没有很好地解决内存问题。                                               3d058390212a12fa9a4d5489205252c7.png

 GC不回收现象

日志场景的Reject问题

ES的日志场景写入量大,GC频繁且性能较差,这也进一步加剧日志集群的写入Reject问题。

JDK17落地

2022年上半年,ES开启了扫雷专项,意在打造一个更高性能、更低延迟、更加稳定的ES检索引擎。在这种背景下,对JDK17-ZGC进行调研,经过测试ZGC可以将GC暂停时间控制在10ms内,能够很好地解决GC导致的查询耗时问题。

同时针对日志这种高吞吐场景,测试了JDK17-G1,发现GC性能相较于JDK11-G1提升了15%,并且JDK17在向量化支持、字符串处理等方面做了许多优化,能在一定程度上缓解日志集群的写入压力。如图所示:

2a67240f9c8ba5555c81285b06bc75ce.png        官方GC吞吐性能          

9a0be3ad67081139fc3ce760d39f9f1b.png

官方GC延迟

生产环境需要稳定、可维护并且免费的JDK版本,同时JDK17是JDK11后又一个可长期支持的版本,在性能、稳定性和安全性上都有很大的提升对ZGC的适配也进一步加强,对G1的稳定性和性能有极大的提升。因此,选择了这一版本。

ZGC 是一个并发的、单代的、基于区域的、NUMA 感知的垃圾回收器,Stop-the-world 阶段仅限于根扫描,因此 GC 暂停时间不会随堆或 live set 的变大而增加。

ZGC垃圾回收过程几乎全程并发,如下图所示,这得益于它所采用的着色指针和读屏障技术。这两项技术解决了对象转移过程中的对象地址定位不准确问题,从而使得传统GC停顿时间最长的对象转移过程和进程并发进行。

48d85e7776748ab1ffe6abe304cd8464.png

 ZGC并发垃圾回收过程

为了实现JDK17在滴滴ES的落地,我们从以下三方面进行着手:

Gradle版本升级

ES依靠Gradle进行项目管理,Gradle使用一种基于Groovy的特定领域语言(DSL)来声明项目设置。Gradle版本、JDK版本和Groovy版本,三者是一一对应的。滴滴ES7.6.0采用的是Gadle6.0版本,支持JDK11。

相应地,如果要使用JDK17,就需要将Gradle升级到7.3版本以上。实现跨大版本的Gradle升级,主要从以下四个方面进行了优化调整。

1、语法升级

82b5d8c590a379069a134ed170c84a7f.png

以上是部分配置升级,还包括Project.afterEvaluate()、getBaseName()等方法替换等。

2、插件加载方式调整

插件的使用方式由apply plugin ‘xxx’ 更改为 plugins{ id 'xxx' id'xxx'},否则容易出现插件找不到问题。

3、解决语法格式导致代码编译失败问题

Gradle由6.0升级到7.3.2,对应的Groovy也从2.x升级到了3.0.7版本。新版本的Groovy有着更加严格的解析器,可能无法编译以前Groovy已经接收的代码。部分解决操作如下图:

389e76d62ac38f98ff02f24e1e627484.png

代码注解格式调整

4、Plugin重构

由于一些groovy语法已失效或调整,部分Groovy plugin需要通过java语言进行重构,例如校验类插件PrecommitPlugin.groovy重构为PrecommitPlugin.java。

源码编译

1、解决ES源码触发JVM编译BUG

使用lambda表达式代替方法引用,解决方法引用导致的JDK编译BUG。部分修改如下图所示。  

d3ac65dd544e565916afc841a294ff73.png

方法引用替换

2、依赖jar包升级:例如Jetty升级到9+版本、jackson升级到2.3.3版本等。

3、类无法使用:通过类替换、BuildPlugin.groovy插件重构等方式解决。

4、注解类问题:部分gradle注解进行了升级替换,例如一些任务类插件需要增加@TaskAction注解等。

搭建ZGC指标监控体系

一套完整的监控体系能够快速的发现问题并止损,才能更好的保障服务的稳定性。为此,ES基于G1搭建了一套完善的JVM指标监控体系,监控一些核心指标并配置报警,能够很好的判断内存的健康度。例如:

  • 监控G1 老年代使用率,当老年代使用率长时间超过阈值时触发报警。

  • 监控Full GC指标,当进程发生Full GC时及时触发报警。

G1的Full GC非常影响查询性能,容易导致用户查询耗时飙升甚至查询超时。通过监控老年代的使用率能够很好的判断内存压力,从而决定是否需要进行扩容、业务治理等,也能在一定程度上降低Full GC发生的频率。如果发生了Full GC,更需要去判断原因,并采取相应的策略进行优化处理。

ZGC是一个单代的垃圾回收器,也就没有新生代和老年代之分,那么通过什么指标去衡量内存压力呢?内存用满了,ZGC如何进行处理?是否也会存在类似G1 FullGC这种十分影响查询的操作?该如何发现这类情况?

我们发现,ZGC在内存用满的时候会发生Allocation Stall(内存分配速率过快,ZGC回收不过来,触发线程粒度的分配暂停),这个操作和G1 Full GC类似,区别在于G1 Full GC会将整个进程挂起,ZGC则是根据预测模型选择性地挂起部分线程。在后期的上线过程中,Allocation Stall对查询性能影响十分严重,因此对Allocation Stall事件的监控非常重要。

通过查找资料了解到当下ZGC的大规模使用场景较少,关于ZGC监控指标的相关信息匮乏。目前JDK17自带的ZGC指标bean只有两个:

  • ZGC Cycles:统计的是ZGC发生的次数以及总耗时

  • ZGC Pauses:统计的是ZGC在GC过程中暂停的次数及暂停时间,这是JDK17新增的指标bean,无法统计Allocation Stall导致的线程挂起时间

G1能够通过指标bean获取到Full GC的次数、gc时间,新生代、老年代的内存使用率等。ZGC是单代垃圾回收器没有老年代,同时ZGC无法直接通过JDK自带的指标bean获取到Allocation Stall的次数,只能在它发生的时候通过GC日志去查看。

针对这些问题,我们设计了一套ZGC指标统计体系。首先重构ES指标统计模块,使其能够统计ZGC Cycles和ZGC Pauses指标。其次,针对Allocation Stall没法统计问题,通过注册GC事件监听器,配合事件回调机制,解析GC Caues从而实现对Allocation Stall的统计。与此同时搭建ZGC Allocation Stall的监控报警体系。指标统计流程如下图所示,ZGC部分指标展示如下:

       5cb2253de8ed64577c0f0cf3253c757a.png

ZGC Allocation Stall指标统计流程图

{
   "gc": { // ES node stats ZGC指标
       "collectors": {
           "ZGC Cycles": { // JDK自带指标bean
               "collection_count": 242,
               "collection_time_in_millis": 97209
           },
           "ZGC Pauses": { // JDK17新增的指标bean
               "collection_count": 726,
               "collection_time_in_millis": 27
           },
           "ZGC AllocationStallCount": {  // ES指标模块新增的AllocationStall指标bean
               "collection_count": 0,
               "collection_time_in_millis": 0
           }
       }
   }
}

生产环境踩坑与调优

1、Allocation Stall 问题

前文也提到了Allocation Stall是由于分配速率过快,ZGC回收不过来导致的。Allocation Stall对ES的影响如下:

  • 查询耗时增加问题:从下图的监控可以看出发生Allocation Stall之后P99的查询耗时突增。

  • 内存熔断问题:ZGC触发的是线程级别Allocation Stall,触发时会选择性地挂起部分线程,其他线程仍然会继续申请内存,就会触发ES的内存熔断机制,导致查询熔断、写入熔断、分片分配熔断等一系列影响用户使用和集群稳定的问题。

01659a740a8f273f4db73f6272508dd1.png

 Allocation Stall监控图

f34d3059806b66f3ea87cc2c6cb89fbe.pngP99耗时

调优和解决方式如下:

  • 根据机器内存使用情况,调整-Xmx增加堆内存的大小,例如一些dataNode由31G调整为64G。

  • 调整修正系数ZAllocationSpikeTolerance,由默认2调大至5,可以更快的触发GC 。

  • 根据不同的堆大小,调大GC线程数 ConcGCThread,降低并发标记时间,例如96G内存的GCThread由16调整到24。

  • -XX:+UseDynamicNumberOfGCThreads(JDK17的ZGC新特性):配置动态GC线程,降低CPU的使用量。

2、GC大毛刺问题

如果查询毛刺或分析GC日志时发现超大的暂停时间(几十到几百毫秒),可以关闭NUMA的Auto Balance,因为开启Auto- Balance后,调动器会做大量的工作如现有页释放、分配本地node页等,来迁移进程和memory到同一个node上,从而造成一些不确定性的卡顿。

3、其他

  • 单独开启类压缩:+UseCompressedClassPointers ,JDK15之后支持单独开启类压缩,通过减少所有对象报头的大小,从而减少整体堆的使用(适用于内存配置31G以内)。

  • 软限制堆大小:ES一些集群存在定时更新大量数据的场景,在此期间内存使用率会突增。同时,ES底层的Lucene需要依赖操作系统缓存来提升查询速度。面对这种场景,可以通过SoftMaxHeapSize配合-XX:ZUncommitDelay参数使用,将未使用的内存归还操作系统。

上线效果

经过三个多月的实践与优化,ES目前已经在15个集群上线了JDK17版本,上线后ES可以提供更低延时、更高性能、更稳定的检索服务,主要效果如下:

更低延时

1、A业务集群上线效果

之前,有集群经常发生内存不回收问题。如下图,上线ZGC后,P99从800ms降低到30ms,下降96%;平均查询耗时从25ms降低到6ms,下降75%

24b948cceade8d6b9e1fa193d93d343b.png

2、B业务集群上线效果

如图,上线后毛刺明显减少,能够提供更加稳定且低延时的检索服务。     50b2d06204c099a222bdbef0586869b1.png

3、某隔离集群上线效果

如图,上线后P99从16ms降低到8ms降低50%。

88c7d6e5a8eda0623dc1972134741911.png

更高性能

1、某日志集群A上线效果

ES某日志集群A上线JDK17后,CPU使用率下降20%,写入性能提升,解决了写入队列堆积和reject问题。

edd222076a9046daa230053a11cb02cd.png

DataNode写入队列堆积图(集群A)

50b123d826b9561a3f17eb4acd2187e3.png

DataNode写入reject图(集群A)

    c33eadea511fd85d185ea0b6bc6105b5.png

CPU Idle图(集群A)

2、某日志集群B上线效果

ES某日志集群B上线JDK17后,CPU使用率下降8%,写入性能提升,写入reject降低30%,能够较好地缓解日志集群压力。              80277c2866fae24c2d250d25dca62bda.png

DataNode写入reject图(集群B)

更稳定

上线JDK17-ZGC和JDK17-G1后,ES关于内存问题的报警进一步收敛,最近几乎没有内存方面的报警 。

此外,ZGC是单代GC,吞吐较低并且在Concurrent Mark阶段耗时长,为避免内存分配停顿,需要更多的内存和ConcGCThread线程,这导致CPU使用率增高。因此,对于注重吞吐的日志场景采用G1,对于CPU相对富足且对延时有一定敏感性的集群,可以通过牺牲一部分CPU换取查询性能,故采用ZGC。

总结

JDK17助力ES提供更低延时、更高性能、更稳定的检索服务,滴滴ES团队对JDK的调优和优化不止原地升级JDK17,在使用G1时,也解决了很多JDK相关的疑难杂症,包括JIT Deoptimization问题,使ES写入性能提升7倍;ES重新实现读写锁,解决了ThreadLocalMap remove导致单节点CPU飙升等等,这里就不一一介绍了。

目前ES仍存在分片恢复、多租户查询互相影响、写入性能等问题,后续我们会在这些方面重点发力,更好地助力业务发展。

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

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

相关文章

云计算技术——多GPU渲染的云渲染服务

多GPU渲染的云渲染服务,是一种利用云计算技术,将多个图形处理器(GPU)集成在一起,为用户提供高效、便捷、低成本的渲染解决方案的服务。本文将从多GPU渲染的概念、优势、应用场景,云渲染服务的特点、优势&am…

【C++】初阶 --- 内联函数(inline)

文章目录 🥞内联函数🍟1、C语言实现"宏函数"🍟2、内联函数的概念🍟3、内联函数的特性🍟4、总结 🥞内联函数 🍟1、C语言实现"宏函数" 🥰用C语言先来实现普通的…

并发——volatile 关键字

文章目录 1. CPU 缓存模型2. 讲一下 JMM(Java 内存模型)3. 并发编程的三个重要特性4. 说说 synchronized 关键字和 volatile 关键字的区别 我们先要从 CPU 缓存模型 说起! 1. CPU 缓存模型 为什么要弄一个 CPU 高速缓存呢? 类比我们开发网站后台系统使…

分布式 - 服务器Nginx:一小时入门系列之静态网页配置

文章目录 1. 静态文件配置2. nginx listen 命令解析3. nginx server_name 命令解析4. nginx server 端口重复5. nginx location 命令 1. 静态文件配置 在 /home 文件下配置一个静态的AdminLTE后台管理系统: [rootnginx-dev conf.d]# cd /home [rootnginx-dev home…

flutter项目给安卓打正式包 和升级版本号

1.首先把flutter项目里的android目录整个拖进android studo里,运行一下看看是否能运行 2.Build->Generate Signed Bundle/APK… 点击APK->Next 如果没有key酒店及Create new…就生成新的key 点击Key store path:右边的图标选择保存路径 选择保存的路径,并且在Save…

【雕爷学编程】Arduino动手做(01)---干簧管传感器模块4

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

logo一键生成的操作,没有设计经验也无妨

您可能会担心,没有设计经验如何设计一个独特而专业的标志(Logo)。但是,随着技术的进步,现在有许多一键生成操作的设计工具可供使用,使人们更容易创建自己的Logo。 什么是一键生成操作? 一键生成…

若依vue -【 100 ~ 更 】

100 主子表代码生成详解 1 新建数据库表结构(主子表) -- ---------------------------- -- 客户表 -- ---------------------------- drop table if exists sys_customer; create table sys_customer (customer_id bigint(20) not null…

《大型网站技术架构》第二篇 架构-高可用

高可用在公司中的重要性 对公司而言,可用性关系网站的生死存亡。对个人而言,可用性关系到自己的绩效升迁。 工程师对架构做了许多优化、对代码做了很多重构,对性能、扩展性、伸缩性做了很多改善,但别人未必能直观地感受到&#…

字节编码学习

字节编码学习 文章目录 字节编码学习01_字节与ASCII码表02_每个国家都有独特的码表03_国际化UTF-804_编码本和解码本不一致,乱码 01_字节与ASCII码表 public class Demo01 {public static void main(String[] args) {// 计算机的底层全部都是字节 ---- ----// 一个…

Android Studio实现简单ListView

效果图 MainActivity package com.example.listviewtest;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.widget.ListView;import com.example.listviewtest.adapter.PartAdapter; import com.example.listviewtest.bean.PartB…

多目标优化之MOEA-D算法,MATLAB代码,免费获取

今天给大家分享一期MOEA/D算法。1 引言 基于分解的多目标进化算法(MOEA/D)的核心思想将多目标优化问题被转化为一系列单目标优化子问题或者是多个多目标的子问题,然后利用子问题之间的邻域关系,采用协作的方式对这些子问题同时进行优化。从而向整个Paret…

大麦订单截图 一键生成订单截图

新版付款图样式展示 这个样式图就是在大麦刚付款完的一个订单截图,它的状态是等待卖家发货 下滑下载源码 下载源码:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

LoRaWAN网关与网络服务器(NS)的通信LNS协议介绍

将 LoRaWAN网关连接到 LoRaWAN 网络服务器 (LNS) 是一个两步过程,该过程使用 WebSocket 作为传输协议来交换包含 JSON 编码对象的文本记录。 首先,网关向LNS查询LNS实际连接端点的URI。其次,它与该端点建立数据连接以接收设置信息。从那时起,LoRa 上行链路和下行链路帧通过…

golang专栏

GOLANG专栏订阅会员 Golang基础教程 Golang基础教程 Golang练手算法 Golang练手算法 Golang设计模式 Golang设计模式 Golang数据结构和算法 Golang数据结构和算法 Golang并发编程 Golang并发编程 ORM框架Gorm Golang ORM框架gorm Golang源码分析 Golang源码分析 MySQL教…

校园防欺凌防霸凌该怎么做

校园防欺凌防霸凌该怎么做 校园防欺凌和霸凌是一个长期而全面的过程,需要学生、教师和家长共同参与和努力。以下是一些可以采取的措施: 1. 教育和意识提高:通过教育和培训,提高学生、教师和家长对欺凌和霸凌的认识和了解。学校可…

机器人制作开源方案 | 超市服务机器人

作者:林江斌 岳沛霖 李锦扬 单位:北京理工大学 机械与车辆学院 指导老师:李忠新 朱杰 一、作品简介 1.设计背景 当前社会疫情防控已经成为常态化,超市是人员流动相对密集的公共场所,超市防疫也是社会防疫工作中重要…

linuxARM裸机学习笔记(4)----GPIO中断以及定时器中断实验

1.中断向量表 这个表里面存放的都是中断向量,中断服务程序的入口地址或存放中断服务程序的首地址成为中断向量。中断向量表是一系列中断服务程序入口地址组成的表,当某个中断触发的时候会自动跳转到中断向量表对应的中断服务程序的入口。 2.NVIC(内嵌向…

vue3+ts+element-plus大屏看板---横向轮播(anime.js)

vue3ts大屏看板---横向轮播(anime.js) 1. 安装和引入anime.js1. 安装2. 引入* 引入报错:引入时候报错 2. 基于vue3tsanime.js实现一个大屏组件轮播效果,如下1. 写一个需要轮播的模块样式✏️ 代码(有写注释&#xff09…

智能照明控制系统助力某商业综合体实现“双碳”-安科瑞黄安南

摘要:智能照明是当前非常普及的一种照明控制方式。广泛使用于建筑物,景观,公共场所。本文以智能照明在商业综合体中的应用为基础,主要介绍了智能照明系统的功能与特点,系统运用的效果,在建筑自动化系统中的地位及优势等…