Apache Doris是Elasticsearch + Grafana Loki优点的综合


理想的日志处理系统应该支持:

  • 高吞吐量实时数据摄取:它应该能够批量写入博客,并使它们立即可见。
  • 低成本存储:它应该能够存储大量的日志而不需要花费太多的资源。
  • 实时文本搜索:它应该能够快速搜索文本。

业界常见的日志处理方案有两种,分别是Elasticsearch和Grafana Loki。

  • 倒排索引(Elasticsearch):由于支持全文搜索和高性能而广受欢迎。缺点是实时写入吞吐量低,索引创建资源消耗大。
  • 轻量级索引/无索引(Grafana Loki):它与倒排索引相反,它具有高实时写入吞吐量和低存储成本但提供慢查询。

Elasticsearch 和 Grafana Loki 代表了高写入吞吐量、低存储成本和快速查询性能之间的不同权衡。

那么能不能同时拥有高写入吞吐量、低存储成本和快速查询?
Apache Doris(实时分析数据库)开源社区在2.0.0版本引入了倒排索引,并进一步优化,以其1/5的存储空间实现了比Elasticsearch快两倍的日志查询性能。这两个因素结合起来,这是一个好 10 倍的解决方案。


倒排索引Inverted index简介
Elasticsearch 在日志处理方面的一个突出优势是在海量日志中快速搜索关键词。这是由倒排索引启用的。
倒排索引最初用于检索文本中的单词或短语。下图说明了它是如何工作的:
在写入数据时,系统将文本标记为术语,并将这些术语存储在一个发布列表中,该列表将术语映射到它们所在行的 ID。在文本查询中,数据库在posting list中找到关键字(term)对应的行ID,根据行ID获取目标行。通过这样做,系统将不必遍历整个数据集,从而将查询速度提高几个数量级。

在Elasticsearch的倒排索引中,快速检索是以写入速度、写入吞吐量和存储空间为代价的。为什么?首先,tokenization、字典排序、倒排索引创建都是CPU和内存密集型操作。其次,Elasticsearch 必须存储原始数据,倒排索引,以及存储在列中的额外数据副本以用于查询加速。那是三重冗余。

但是没有倒排索引,比如Grafana Loki,查询速度慢,影响用户体验,是日志分析工程师最大的痛点。

Apache Doris 中的倒排索引
索引的实现方式一般有两种:外部索引系统或者内置索引。

外部索引系统:您将外部索引系统连接到您的数据库。在数据摄取中,数据被导入到两个系统中。索引系统创建索引后,会删除自己内部的原始数据。当数据用户输入查询时,索引系统提供相关数据的ID,然后数据库根据ID查找目标数据。
构建外部索引系统更容易,对数据库的干扰更小,但它有一些恼人的缺陷:

  • 需要将数据写入两个系统会导致数据不一致和存储冗余。
  • 数据库和索引系统的交互会带来开销,所以当目标数据很大时,跨两个系统的查询会很慢。
  • 维护两个系统很累。

Apache Doris中,我们选择了另一种方式。内置倒排索引制作起来比较困难,但是一旦完成,速度更快,更人性化,维护起来也更省事。

我们以非侵入式的方式实现倒排索引:

  1. Data ingestion & compaction : 当一个段文件被写入 Doris 时,一个倒排索引文件也会被写入。索引文件路径由段ID和索引ID决定。段中的行对应索引中的文档,RowID 和 DocID 也是如此。
  2. 查询:如果where子句中包含倒排索引的列,系统会在索引文件中查找,返回一个DocID列表,并将DocID列表转换成RowID Bitmap。在 Apache Doris 的 RowID 过滤机制下,只会读取目标行。这就是加速查询的方式。

这种非侵入式的方法将索引文件与数据文件分开,因此您可以对倒排索引进行任何更改,而不必担心影响数据文件本身或其他索引。

倒排索引的优化

1、一般优化
C++ 实现和向量化
与使用 Java 的 Elasticsearch 不同,Apache Doris 在其存储模块、查询执行引擎和倒排索引中实现了 C++。与 Java 相比,C++ 提供更好的性能,允许更容易的矢量化,并且不会产生 JVM GC 开销。我们对 Apache Doris 中倒排索引的每一步都进行了矢量化,例如标记化、索引创建和查询。给大家提供一个视角,在倒排索引中,Apache Doris 以每核 20MB/s 的速度写入数据,是 Elasticsearch(5MB/s)的四倍。

2、列存储和压缩
Apache Lucene 为 Elasticsearch 中的倒排索引奠定了基础。由于 Lucene 本身是为支持文件存储而构建的,因此它以面向行的格式存储数据。
在Apache Doris中,不同列的倒排索引相互隔离,倒排索引文件采用列式存储,便于向量化和数据压缩。
Apache Doris 通过使用 Zstandard 压缩,实现了5:1到10:1 的压缩比,压缩速度更快,空间占用比 GZIP 压缩减少 50%。

3、数字/日期时间列的 BKD 树
Apache Doris 为数字和日期时间列实现 BKD 树。这不仅提高了范围查询的性能,而且比将这些列转换为固定长度的字符串更节省空间。它的其他好处包括:

  1. 高效的范围查询:能够在numeric和datetime列中快速定位到目标数据范围。
  2. 更少的存储空间:聚合和压缩相邻的数据块以降低存储成本。
  3. 支持多维数据:BKD 树具有可扩展性和适应多维数据类型的能力,例如 GEO 点和范围。

除了 BKD 树,我们还进一步优化了对数字和日期时间列的查询。
  1. 针对低基数场景的优化:我们对低基数场景的压缩算法进行了微调,因此对大量倒排列表进行解压反序列化会消耗更少的CPU资源。
  2. 预取:对于命中率高的场景,我们采用预取。如果命中率超过某个阈值,Doris 将跳过索引过程并开始数据过滤。

3、针对 OLAP 的定制优化
日志分析是一种简单的查询,不需要高级功能(例如 Apache Lucene 中的相关性评分)。日志处理工具的主要功能是快速查询和低存储成本。因此,在Apache Doris中,我们精简了倒排索引结构来满足OLAP数据库的需求。

  • 在数据摄取中,我们防止多个线程将数据写入同一个索引,从而避免锁争用带来的开销。
  • 我们丢弃正向索引文件和规范文件以清理存储空间并减少 I/O 开销。
  • 我们简化了相关性评分和排名的计算逻辑,以进一步减少开销并提高性能。

鉴于日志是按时间范围分区的,历史日志访问频率较低。我们计划在 Apache Doris 的未来版本中提供更细化和灵活的索引管理:
  • 为指定数据分区创建倒排索引:为过去7天的日志等创建索引。
  • 删除 指定数据分区的倒排索引:删除一个多月前日志的索引等(以清理索引空间)。

测试
测试Apache Doris 的结果:

  • 写入速度:550MB/s,是Elasticsearch的4.2倍
  • 压缩比:10:1
  • 存储使用:Elasticsearch 的 20%
  • 响应时间:Elasticsearch 的 43%

Apache Doris VS ClickHouse
由于 ClickHouse 在 v23.1 中推出了倒排索引作为实验特性,我们使用 ClickHouse博客中描述的相同数据集和 SQL 对 Apache Doris 进行了测试,并比较了两者在相同测试资源、案例和工具下的性能。

结果:Apache Doris在三个查询中分别比 ClickHouse 快4.7 倍、12 倍、18.5 倍。

用法和示例
数据集:来自 Hacker News 的一百万条评论记录
第一步:建表时给数据表指定倒排索引。
参数:

  • INDEX idx_comment( comment):为“评论”列创建一个名为“idx_comment”评论的索引
  • USING INVERTED:为表指定倒排索引
  • PROPERTIES(“parser” = “english”): 指定分词语言为英语

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` )使用 反向 属性( "parser" = "english" ) 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")向现有表添加索引。与智能索引和二级索引不同,倒置索引的创建只涉及到对评论列的读取,所以它可以快得多。

第二步:用MATCH_ALL检索评论栏中的 "OLAP "和 "OLTP "两个词。这里的响应时间是用like硬匹配时的1/10。(随着数据量的增加,性能差距也在扩大)。

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一直在努力为数据工程师解决这个问题。它的成本效益比市场上常见的解决方案高出10倍,其原因是它为倒置索引提供了OLAP定制的优化,并由其列式存储引擎、大规模并行处理框架、矢量查询引擎和基于成本的优化器支持。