作者介绍: 肖康,SelectDB 技术副总裁
导语
日志数据的解决与剖析是最典型的大数据分析场景之一,过来业内以 Elasticsearch 和 Grafana Loki 为代表的两类架构难以同时兼顾高吞吐实时写入、低成本海量存储、实时文本检索的需要。Apache Doris 借鉴了信息检索的核心技术,在存储引擎上实现了面向 AP 场景优化的高性能倒排索引,对于字符串类型的全文检索和一般数值、日期等类型的等值、范畴检索具备更高效的反对,相较于 Elasticsearch 实现性价比 10 余倍的晋升,以此为日志存储与剖析场景提供了更优的抉择。
日志数据分析的需要与特点
日志数据在企业大数据中十分广泛,其体量往往在企业大数据体系中占据十分高的比重,包含服务器、数据库、网络设备、IoT 物联网设施产生的零碎运维日志,与此同时还蕴含了用户行为埋点等业务日志。
日志数据对于保障系统稳固运行和业务倒退至关重要:基于日志的监控告警能够发现零碎运行危险,及时预警;在故障排查过程中,实时日志检索能帮忙工程师疾速定位到问题,尽快恢复服务;日志报表能通过长历史统计发现潜在趋势。而用户埋点日志数据则是用户行为剖析以及智能举荐业务所依赖的决策根底,有助于用户需要洞察与体验优化以及后续的业务流程改良。
因为其在业务中能施展的重要意义,因而构建对立的日志剖析平台,提供对日志数据的存储、高效检索以及疾速剖析能力,成为企业开掘日志数据价值的要害一环。而日志数据和利用场景往往出现如下的特点:
- 数据增长快:每一次用户操作、零碎事件都会触发新的日志产生,很多企业每天新增日志达到几十甚至几百亿条,对日志平台的写入吞吐要求很高;
- 数据总量大:因为本身业务和监管等须要,日志数据常常要存储较长的周期,因而累积的数据量常常达到几百 TB 甚至 PB 级,而较老的历史数据拜访频率又比拟低,面临惨重的存储老本压力;
- 时效性要求高:在故障排查等场景须要能疾速查问到最新的日志,分钟级的数据提早往往无奈满足业务极高的时效性要求,因而须要实现日志数据的实时写入与实时查问。
这些日志数据和利用场景的特点,为承载存储和剖析需要的日志平台提出了如下挑战:
- 高吞吐实时写入:既须要保障日志流量的大规模写入,又要反对低提早可见;
- 低成本大规模存储:既要存储大量的数据,又要升高存储老本;
- 反对文本检索的实时查问:既要能反对日志文本的全文检索,又要做到实时查问响应;
业界日志存储剖析解决方案
以后业界有两种比拟典型的日志存储与剖析架构,别离是以 Elasticsearch 为代表的倒排索引检索架构以及以 Loki 为代表的轻量索引 / 无索引架构,如果咱们从实时写入吞吐、存储老本、实时交互式查问性能等几方面进行比照,不难发现以下论断:
- 以 ES 为代表的倒排索引检索架构,反对全文检索、查问性能好,因而在日志场景中被业内大规模利用,但其仍存在一些有余,包含实时写入吞吐低、耗费大量资源构建索引,且须要耗费微小存储老本;
- 以 Loki 为代表的轻量索引或无索引架构,实时写入吞吐高、存储老本较低,然而检索性能慢、要害时候查问响应跟不上,性能成为制约业务剖析的最大掣肘。
ES 在日志场景的劣势在于全文检索能力,能疾速从海量日志中检索出匹配关键字的日志,其底层核心技术是倒排索引(Inverted Index)。
倒排索引是一种用于疾速查找文档中蕴含特定单词或短语的数据结构,最早利用于信息检索畛域。如下图所示,在数据写入时,倒排索引能够将每一行文本进行分词,变成一个个词(Term),而后构建词(Term)-> 行号列表(Posting List)的映射关系,将映射关系依照词进行排序存储。当须要查问某个词在哪些行呈现的时候,先在 词 -> 行号列表 的有序映射关系中查找词对应的行号列表,而后用行号列表中的行号去取出对应行的内容。这样的查问形式,能够防止遍历对每一行数据进行扫描和匹配,只须要拜访蕴含查找词的行,在海量数据下性能有数量级的晋升。
图:倒排索引原理示意
倒排索引为 ES 带来疾速检索能力的同时,也付出了写入速度吞吐低和存储空间占用高的代价——因为数据写入时倒排索引须要进行分词、词典排序、构建倒排表等 CPU 和内存密集型操作,导致写入吞吐大幅降落。而从存储老本角度思考,ES 会存储原始数据和倒排索引,为了减速剖析可能还须要额定存储一份列存数据,因而 3 份冗余也会导致更高的存储空间占用。
Loki 则放弃了倒排索引,尽管带来来写入吞吐和存储空间的劣势,然而损失了日志检索的用户体验,在关键时刻不能施展疾速查日志的作用。老本尽管有所升高,然而没有真正解决用户的问题。
更高性价比的日志存储剖析解决方案
从以上计划比照可知,以 Elasticsearch 为代表的倒排索引检索架构以及以 Loki 为代表的轻量索引 / 无索引架构无奈同时兼顾 高吞吐、低存储老本和实时高性能的要求,只能在某一方面或某几方面做衡量取舍。如果在放弃倒排索引的文本检索性能劣势的同时,大幅晋升零碎的写入速度与吞吐量并升高存储资源老本,是否日志场景所面临的窘境就迎刃而解呢?答案是必定的。
如果咱们心愿应用 Apache Doris 来更好解决日志存储与剖析场景的痛点,其实现门路也十分清晰——在数据库外部减少倒排索引、以满足字符串类型的全文检索和一般数值 / 日期等类型的等值、范畴检索,同时进一步优化倒排索引的查问性能、使其更加符合日志数据分析的场景需要。
在同样实现倒排索引的状况下,相较于 ES,Apache Doris 怎么做到更高的性能体现呢?或者说现有倒排索引的优化空间有哪些呢?
- ES 基于 Apache Lucene 构建倒排索引,Apache Lucene 自 2000 年开源至今已有超过 20 年的历史,设计之初次要面向信息检索畛域、功能丰富且简单,而日志和大多数 OLAP 场景只须要其外围性能,包含分词、倒排表等,而相关度排序等并非强需要,因而存在进一步性能简化和性能晋升的空间;
- ES 和 Apache Lucene 均采纳 Java 实现,而 Apache Doris 存储引擎和执行引擎采纳 C++ 开发并且实现了全面向量化,绝对于 Java 实现具备更好的性能;
- 倒排索引并不能决定性能体现的全副,作为一个高性能、实时的 OLAP 数据库,Apache Doris 的列式存储引擎、MPP 分布式查问框架、向量化执行引擎以及智能 CBO 查问优化器,相较于 ES 更为高效。
通过在 Apache Doris 2.0.0 最新版本的摸索与继续优化,在雷同硬件配置和数据集的测试体现上,Apache Doris 在数据库内核实现高性能倒排索引后,绝对于 ES 实现了日志数据写入速度晋升 4 倍、存储空间升高 80%、查问性能晋升 2 倍,再联合 Apache Doris 2.0.0 版本引入的冷热数据拆散个性,整体性价比晋升 10 倍以上!
接下来咱们进一步介绍设计与实现细节。
高性能倒排索引的设计与实现
业界各类零碎为了反对全文检索和任意列索引,往往有两种实现形式:一是通过外接索引零碎来实现,原始数据存储在原零碎中、索引存储在独立的索引零碎中,两个零碎通过数据的 ID 进行关联。数据写入时会同步写入到原零碎和索引零碎,索引零碎构建索引后不存储残缺数据只保留索引。查问时先从索引零碎查出满足过滤条件的数据 ID 汇合,而后用 ID 汇合去原零碎查原始数据。
这种架构的劣势是实现简略,借力内部索引零碎,对原有零碎改变小。然而问题也很显著:
- 数据写入两个零碎,异样有数据不统一的问题,也存在肯定冗余存储;
- 查问需在两个零碎进行网络交互有额定开销,数据量大时用 ID 汇合去原零碎查性能比拟低;
- 保护两套零碎的复杂度高,将零碎的复杂性从开发测转移到运维测;
而另一种形式则是间接在零碎中内置倒排索引,只管技术难度更高,但性能更好、且无需破费额定的系统维护老本,对用户更加敌对,这也是 Apache Doris 所抉择的形式。
数据库内置倒排索引
在抉择了在数据库内核中内置倒排索引后,咱们须要进一步对 Apache Doris 索引构造进行剖析,判断是否通过在已有索引根底上进行拓展来实现。
Apache Doris 现有的索引存储在 Segment 文件的 Index Region 中,依照实用场景能够分为跳数索引和点查索引两类:
-
跳数索引:包含 ZoneMap 索引和 Bloom Filter 索引。
- ZoneMap 索引对每一个数据块和文件保留 Min/Max/isnull 等汇总信息,能够用于等值、范畴查问的粗粒度过滤,只能排除不满足查问条件的数据块和文件,不能定位到行,也不反对文本分词。
- BloomFilter 索引也是数据块和文件级别的索引,通过 Bloom Filter 判断某个值是否在数据块和文件中,同样不能定位到行、不反对文本分词;
-
点查索引:包含 ShortKey 前缀排序索引和 Bitmap 索引。
- ShortKey 在排序的根底上,依据给定的前缀列实现疾速查问数据的索引形式,可能对前缀索引的列进行等值、范畴查问,但不反对文本分词,另外因为数据要按前缀索引排序、因而一个表只容许一组前缀索引。
- Bitmap 索引记录数据值 -> 行号 Bitmap 的有序映射,是一种很根底的倒排索引,然而索引构造比较简单、查问效率不高、不反对文本分词。
原有索引构造很难满足日志场景实时文本检索的需要,因而设计了全新的倒排索引。倒排索引在设计和实现上咱们采取了无侵入的形式、不扭转 Segment 数据文件格式,而是减少了新的 Inverted Index File,逻辑上在 Table 的 Column 级别。具体流程如下:
- 数据写入和 Compaction 阶段:在写 Segment 文件的同时,同步写入一个 Inverted Index 文件,文件门路由 Segment ID + Index ID 决定。写入 Segment 的 Row 和 Index 中的 Doc 一一对应,因为同步程序写入,Segment 中的 Rowid 和 Index 中的 Docid 齐全对应。
- 查问阶段:如果查问 Where 条件中有建了倒排索引的列,会主动去 Index 文件中查问,返回满足条件的 Docid List,将 Docid List 一一对应的转成 Rowid Bitmap,而后走 Doris 通用的 Rowid 过滤机制只读取满足条件的行,达到查问减速的成果。
图:Doris 倒排索引架构图
这个设计的益处是已有的数据文件无需批改,能够做到兼容降级,而且增减索引不影响数据文件和其余索引,用户增建索引没有累赘。
通用倒排索引优化
C++ 和向量化实现
Apache Doris 应用 CLucene 作为底层的倒排索引库,CLucene 是一个用 C++ 实现的高性能、稳固的 Lucene 倒排索引库,它的性能比拟残缺,反对分词和自定义分词算法,反对全文检索查问和等值、范畴查问。
Apache Doris 的存储模块和 CLucene 都用 C++ 实现,防止了 Java Lucene 的 JVM GC 等开销,同样的计算 C++ 实现绝对于 Java 性能劣势显著,而且更利于做向量化减速。Doris 倒排索引进行了向量化优化,包含分词、倒排表构建、查问等,性能失去进一步晋升。整体来看 Doris 的倒排索引写入速度能够超过单核 20MB/s,而 ES 的单核写入速度不到 5MB/s,有 4 倍的性能劣势。
列式存储和压缩
Lucene 自身是文档存储模型,主数据采纳行存,而 Doris 中不同列的倒排索引是互相独立的,因而倒排索引文件也采纳列式存储,有利于向量化构建索引和进步压缩率。
采纳压缩比高且速度快的 ZSTD,通常能够达到 5 ~10 倍的压缩比,与罕用的 GZIP 压缩相比有 50% 以上的空间节俭且速度更快。
BKD 索引与 数值、日期类型 列优化
针对数值、日期类型的列,咱们还实现了 BKD 索引,能够对范畴查问进步性能,存储空间也绝对于转成定长字符串更加高效,具备以下次要个性和劣势:
- 高效范畴查问:BKD 索引采纳多维数据结构,为范畴查问带来高效率。它能迅速定位数值或日期类型列中所需的数据范畴,升高查问工夫复杂度。
- 存储空间优化:与其余索引办法相比,BKD 索引在存储空间应用上更高效。通过聚合并压缩相邻数据块,缩小索引所需存储空间,升高存储老本。
- 多维数据反对:BKD 索引具备良好扩展性,反对多维数据类型,如地理坐标(GEO point)和范畴(Range),使其在解决简单数据类型时具备高适应性。
此外,咱们在原有 BKD 索引能力根底上进行了进一步拓展:
- 优化低基数场景:针对数值散布集中、单个数值倒排列表较多的低基数场景,咱们调整了针对性的压缩算法,升高大量倒排表解压缩和反序列化所带来的 CPU 性能耗费。
- 预查问技术:针对查问后果命中数较高的场景,咱们采纳预查问技术进行命中数预估。若命中数显著超过阈值,可跳过索引查问,间接利用 Doris 在大数据量查问下的技术劣势进行数据过滤。
面向 OLAP 的倒排索引优化
日志存储和剖析场景对检索的需要很简略,不须要特地简单的性能(比方相关性排序),更须要升高存储老本和疾速依照条件查出数据。因而,在面对海量数据的写入和查问时,Apache Doris 还针对 OLAP 数据库的特点优化了倒排索引的构造,使其更加简洁高效。例如:
- 在写入流程保障不会多个线程写入一个索引,从而防止写入时多线程锁竞争的开销;
- 在存储构造上去掉了不必要的正排、norm 等文件,缩小写入 IO 开销和存储空间占用;
- 查问过程中简化相关性打分和排序逻辑,升高不必要的开销,晋升查问性能。
针对日志等数据有按工夫分区、历史数据拜访频度低的特点,基于独立的索引文件设计,Apache Doris 还将在后续的版本中提供更细粒度、更灵便的索引治理性能:
- 指定分区构建倒排索引,比方新增一个索引的时候指定最近 7 天的日志构建索引,历史数据不建索引
- 指定分区删除倒排索引,比方删除超过 1 个月的日志的索引,开释拜访频度低的索引存储空间
性能测试
高性能是 Apache Doris 倒排索引设计和实现的首要出发点,咱们通过公开的测试数据集别离与 ES 以及 Clickhouse 进行性能测试,测试成果如下:
vs Elasticsearch
咱们采纳了 ES 官网的性能测试 Benchmark esrally 并应用其中的 HTTP Logs 日志,在同样的硬件资源、数据、测试 Case 以及测试工具下,记录并比照各自的数据写入工夫、吞吐以及查问提早。
- 测试数据:esrally HTTP Logs track 中自带测试数据集,1998 年 World Cup HTTP Server Logs,未压缩前 32G、共 2.47 亿行、单行均匀长度 134 字节;
- 测试查问:esrally HTTP Logs 测试关键词检索、范畴查问、聚合、排序等 11 个 Query,所有查问跑 100 次串行执行;
- 测试环境:3 台 16C 64G 云主机组成的集群。
在最终的测试后果中,Doris 写入速度是 ES 的 4.2 倍 、达到 550 MB/s,写入后的数据压缩比靠近 1:10、 存储空间 节俭 超 80% ,查问耗时降落 57%、查问性能是 ES 的 2.3 倍。加上冷热数据拆散升高冷数据存储老本,整体相较 ES 实现 10 倍以上的性价比晋升。**
vs Clickhouse
Clickhouse 近期的 v23.1 版本也引入了相似 Feature,将倒排索引作为试验性功能公布,因而咱们同样进行了跟 Clickhouse 倒排索引的性能比照。在本次测试中,咱们采纳了 Clickhouse 官网 Inverted Index 介绍博客中应用的 Hacker News 样例数据以及查问 SQL,同样放弃雷同的物理资源、数据、测试 Case 以及测试工具。
(参考文章:https://clickhouse.com/blog/clickhouse-search-with-inverted-i…)
- 测试数据:Hacker News 2873 万条数据,6.7G,Parquet 格局;
- 测试查问:3 个查问,别离查问 ‘clickhouse’、’olap’ OR ‘oltp’、’avx’ AND ‘sve’ 等关键字呈现的次数;
- 测试机器:1 台 16C 64G 云主机
在最终的测试后果中,3 个 SQL Apache Doris 的查问性能别离是 Clickhouse 的 4.7 倍、12.0 倍以及 18.5 倍,有显著的性能劣势。
如何应用
上面以一个 Hacker News 100 万条测试数据的示例展现 Doris 如何利用倒排索引实现高效的日志剖析。
-
建表时指定索引
- INDEX idx_comment (
comment
) 指定对 comment 列建一个名为 idx_comment 的索引 - USING INVERTED 指定索引类型为倒排索引
- PROPERTIES(“parser” = “english”) 指定分词类型为英文分词
- INDEX idx_comment (
CREATE TABLE hackernews_1m
(
`id` BIGINT,
`deleted` TINYINT,
`type` String,
`author` String,
`timestamp` DateTimeV2,
`comment` String,
`dead` TINYINT,
`parent` BIGINT,
`poll` BIGINT,
`children` Array<BIGINT>,
`url` String,
`score` INT,
`title` String,
`parts` Array<INT>,
`descendants` INT,
INDEX idx_comment (`comment`) USING INVERTED PROPERTIES("parser" = "english") COMMENT 'inverted index for comment'
)
DUPLICATE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES ("replication_num" = "1");
注:对于曾经存在的表,也能够通过 ADD INDEX idx_comment ON hackernews_1m(`comment`) USING INVERTED PROPERTIES("parser" = "english")
来减少索引。值得一提的是,和 Doris 原先存储在 Segment 数据文件中的智能索引和二级索引相比,减少倒排索引的过程只会读 comment 列构建新的倒排索引文件,不会读写原有的其余数据,效率有显著晋升。
- 导入数据后查问,应用
MATCH_ALL
在 comment 这一列上匹配 OLAP 和 OLTP 两个词,和 LIKE 扫描硬匹配相比,查问性能有十余倍的晋升。(这仅是 100 万条数据下的测试成果,而随着数据量增大、性能晋升越显著)
mysql> SELECT count() FROM hackernews_1m WHERE comment LIKE '%OLAP%' AND comment LIKE '%OLTP%';
+---------+
| count() |
+---------+
| 15 |
+---------+
1 row in set (0.13 sec)
mysql> SELECT count() FROM hackernews_1m WHERE comment MATCH_ALL 'OLAP OLTP';
+---------+
| count() |
+---------+
| 15 |
+---------+
1 row in set (0.01 sec)
更多具体性能介绍和测试步骤能够参考 Apache Doris 倒排索引官网文档。
总结
通过内置高性能倒排索引,Apache Doris 对于字符串类型的全文检索和一般数值、日期等类型的等值、范畴检索具备更高效的反对,进一步晋升了数据查问的效率和准确性,对于大规模日志数据查问剖析有了更好的性能体现,为须要检索能力的用户提供了更高性价比的抉择。
目前倒排索引曾经反对了 String、Int、Decimal、Datetime 等罕用 Scalar 数据类型和 Array 数组类型,后续还会减少对 JSONB、Map 等简单数据类型的反对。而 BKD 索引能够反对多维度类型的索引,为将来 Doris 减少 GEO 地理位置数据类型和索引打下了根底。与此同时 Apache Doris 在半结构化数据分析方面还有更多能力扩大,比方主动依据导入数据扩大表构造的 Dynamic Table、丰盛的简单数据类型(Array、Map、Struct、JSONB)以及高性能字符串匹配算法等。
除倒排索引以外,Apache Doris 在 2.0.0 Alpha 版本中还实现了单节点数万 QPS 的高并发点查问能力、基于对象存储的冷热数据拆散、基于代价模型的全新查问优化器以及 Pipeline 执行引擎等,欢送大家下载体验。高并发点查问的具体介绍能够查看 SelectDB 技术团队过往公布的技术博客,其余性能的应用介绍请参考社区官网文档,同时也敬请继续关注咱们后续公布的个性解读系列文章。
为了让用户能够体验社区开发的最新个性,同时保障最新性能能够播种到更广范畴的应用反馈,咱们建设了 2.0.0 版本的专项反对群,欢送宽广社区用户在应用最新版本过程中多多反馈应用意见,帮忙 Apache Doris 继续改良,通过此处填写申请加入专项反对群。