对比Elasticsearch,使用Doris进行高效日志分析

数据库 其他数据库
基于SQL的分析引擎确保数据工程师和分析师能够在短时间内轻松掌握Apache Doris,并将其在SQL方面的经验应用到这个OLAP引擎中。借助SQL的丰富功能,用户可以执行数据检索、聚合、多表连接、子查询、UDF、逻辑视图和物化视图,以满足自身需求。

作为公司数据资产的重要组成部分,日志在系统的可观察性、网络安全和数据分析方面扮演着关键角色。日志记录是故障排除的首选工具,也是提升系统安全性的重要参考。日志还是一个宝贵的数据源,通过对其进行分析,可以获取指导业务增长的有价值信息。

日志是计算机系统中事件的顺序记录。一个理想的日志分析系统应该是:

  • 具备无模式支持。 原始日志是非结构化的自由文本,基本无法直接进行聚合和计算,因此,在将日志用于数据库或数据仓库进行分析之前,需要将其转化为结构化的表格形式(这个过程称为“ETL”)。如果发生日志模式更改,需要在ETL流程和结构化表中进行一系列复杂的调整。为了应对此情况,可以使用半结构化日志,主要采用JSON格式进行记录。在这种格式的日志中,可以相对容易地添加或删除字段,而日志存储系统会相应地调整其模式。
  • 低成本。 日志数据庞大且持续不断生成。一个相当大的公司每年会产生10~100 TB的日志数据。基于业务或合规要求,应该保留半年或更长时间的日志。这意味着需要存储以PB为单位的日志大小,成本相当可观。
  • 具备实时处理能力。 日志应该实时写入,否则工程师将无法及时捕捉故障排查和安全追踪中的最新事件。此外,良好的日志系统应该提供全文搜索功能,并能快速响应交互式查询。

1 基于Elasticsearch的日志分析解决方案

数据行业内常用的日志处理解决方案是ELK技术栈:Elasticsearch、Logstash和Kibana。该流程可分为五个模块:

  • 日志收集:Filebeat收集本地日志文件并将其写入Kafka消息队列。
  • 日志传输:Kafka消息队列收集和缓存日志。
  • 日志转换:Logstash过滤和转换Kafka中的日志数据。
  • 日志存储:Logstash以JSON格式将日志写入Elasticsearch进行存储。
  • 日志查询:用户通过Kibana可视化搜索日志或通过Elasticsearch DSL API发送查询请求。

图片图片

ELK堆栈具有优秀的实时处理能力,但也存在一些问题。

1.1 缺乏无模式支持

Elasticsearch中的索引映射定义了表的结构,包括字段名称、数据类型以及是否启用索引创建。

图片图片

Elasticsearch还拥有自动根据输入的JSON数据添加字段到映射的动态映射机制。这提供了某种程度的无模式支持,但这还不够,因为:

  • 动态映射在处理脏数据时经常会创建过多的字段,从而中断整个系统的运行。
  • 字段的数据类型是不可变的。为了确保兼容性,用户通常将数据类型配置为"文本",但这会导致比二进制数据类型(如整数)慢得多的查询性能。
  • 字段的索引也是不可变的。用户无法为特定字段添加或删除索引,因此经常为所有字段创建索引,以便在查询中方便地进行数据过滤。但是太多的索引需要额外的存储空间,并减慢数据摄入速度。

1.2 分析能力不足

Elasticsearch拥有独特的领域特定语言(DSL),与大多数数据工程师和分析师熟悉的技术栈非常不同,所以存在陡峭的学习曲线。此外,Elasticsearch相对封闭的生态系统,在与BI工具集成方面会遇到一些阻力。最重要的是,Elasticsearch仅支持单表分析,滞后于现代OLAP对多表连接、子查询和视图的需求。

图片图片

1.3 高成本和低稳定性

Elasticsearch用户一直在抱怨计算和存储成本。根本原因在于Elasticsearch的工作方式。

  • 计算成本:在数据写入过程中,Elasticsearch还执行计算密集型操作,包括倒排索引的创建、分词和倒排索引的排序。在这些情况下,数据以每个核心约2MB/s的速度写入Elasticsearch。当CPU资源紧张时,数据写入需求往往会在高峰时段被拒绝,进一步导致更高的延迟。
  • 存储成本:为了加快检索速度,Elasticsearch存储原始数据的正排索引、倒排索引和文档值,消耗了更多的存储空间。单个数据副本的压缩比仅为1.5:1,而大多数日志解决方案的压缩比为5:1。

随着数据量和集群规模的增长,保持稳定性会成为另一个问题:

  • 在数据写入高峰期:集群在数据写入高峰期容易超载。
  • 在查询期间:由于所有查询都在内存中处理,大型查询很容易导致JVM OOM(内存溢出)。
  • 恢复缓慢:对于集群故障,Elasticsearch需要重新加载索引,这对资源消耗很大,因此恢复过程可能需要几分钟。这对于服务可用性的保证是一个挑战。

2 更具成本效益的方案

在反思基于Elasticsearch的解决方案的优点和局限性后,Apache Doris开发人员对Apache Doris进行了日志处理的优化。

  • 增加写入吞吐量: Elasticsearch的性能受到数据解析和倒排索引创建的限制,因此改进了Apache Doris在这些方面的性能:通过SIMD指令和CPU向量指令加快了数据解析和索引创建的速度;然后移除了在日志分析场景中不必要的数据结构,例如正排索引,以简化索引创建过程。
  • 减少存储成本: 移除了正排索引,这部分数据占据了索引数据的30%。采用了列式存储和ZSTD压缩算法,从而实现了5:1到10:1的压缩比。考虑到大部分历史日志很少被访问,引入了分层存储来分离热数据和冷数据。超过指定时间段的日志将被移动到存储成本更低的对象存储中。这可以将存储成本降低约70%。

Elasticsearch的官方测试工具ES Rally进行的基准测试显示,Apache Doris在数据写入方面比Elasticsearch快约5倍,在查询方面快约2.3倍,并且仅消耗Elasticsearch使用存储空间的1/5。在HTTP日志的测试数据集上,它实现了550 MB/s的写入速度和10:1的压缩比。

图片图片

下图显示了一个典型的基于Doris的日志处理系统的样貌。它更加全面,从数据摄取、分析到应用,都可以更灵活地使用:

  • 数据导入:Apache Doris支持多种日志数据的摄入方式。可以通过使用Logstash的HTTP输出将日志推送到Doris,可以在将日志写入Doris之前使用Flink预处理日志,或者可以通过常规加载和S3加载从Flink或对象存储中加载日志到Doris中。
  • 数据分析:可以把日志数据放入Doris,并在数据仓库中进行跨日志和其他数据的联接查询。
  • 应用:Apache Doris兼容MySQL协议,因此可以把各种数据分析工具和客户端集成到Doris中,例如Grafana和Tableau。还可以通过JDBC和ODBC API将应用程序连接到Doris。这里计划构建一个类似于Kibana的系统来可视化日志。

图片图片

此外,Apache Doris具有更好的无模式支持和更用户友好的分析引擎。

2.1 原生支持半结构化数据

首先,在数据类型上进行优化。通过矢量化优化了字符串搜索和正则表达式匹配的文本性能,性能提升了2~10倍。对于JSON字符串,Apache Doris将其解析并存储为更紧凑和高效的二进制格式,可以加快查询速度4倍。还为复杂数据添加了一种新的数据类型:Array Map。它可以将连接的字符串进行结构化,以实现更高的压缩率和更快的查询速度。

其次,Apache Doris支持模式演化。这意味着可以根据业务变化调整模式。可以添加或删除字段和索引,并更改字段的数据类型。

Apache Doris提供了轻量级的模式更改功能,因此开发人员可以在几毫秒内添加或删除字段:

-- 添加列。结果会在毫秒级返回。
ALTER TABLE lineitem ADD COLUMN l_new_column INT;

还可以仅为目标字段添加索引,以避免不必要的索引创建带来的开销。在添加索引后,默认情况下,系统将为所有增量数据生成索引,并且可以指定需要索引的历史数据分区。

-- 添加倒排索引。Doris会为以后的所有新数据生成倒排索引。
ALTER TABLE table_name ADD INDEX index_name(column_name) USING INVERTED;

-- 为指定的历史数据分区构建索引。
BUILD INDEX index_name ON table_name PARTITIONS(partition_name1, partition_name2);

2.2 基于SQL的分析引擎

基于SQL的分析引擎确保数据工程师和分析师能够在短时间内轻松掌握Apache Doris,并将其在SQL方面的经验应用到这个OLAP引擎中。借助SQL的丰富功能,用户可以执行数据检索、聚合、多表连接、子查询、UDF、逻辑视图和物化视图,以满足自身需求。

Apache Doris具备MySQL兼容性,可以与大数据生态系统中的大多数GUI和BI工具集成,使用户能够实现更复杂和多样化的数据分析。

3 使用案例中的性能表现

一家游戏公司已经从ELK技术栈转向了Apache Doris解决方案。他们基于Doris的日志系统所需的存储空间只有之前的1/6。

一家网络安全公司利用Apache Doris中的倒排索引构建了他们的日志分析系统,支持每秒写入30万行数据,仅使用以前所需的1/5服务器资源。

4 实践指南

现在按照以下三个步骤来构建一个基于Apache Doris的日志分析系统。

在开始之前,从官方网站下载Apache Doris 2.0或更新版本,并部署集群。

4.1 步骤1:创建表格

这是一个表格创建的示例。

对配置的解释:

  • 将DATETIMEV2时间字段指定为键,以加快对最新N条日志记录的查询速度。
  • 为频繁访问的字段创建索引,并使用解析器参数指定需要进行全文搜索的字段。
  • "PARTITION BY RANGE"意味着根据时间字段将数据按范围进行分区,启用动态分区以进行自动管理。
  • "DISTRIBUTED BY RANDOM BUCKETS AUTO"意味着将数据随机分布到桶中,系统会根据集群大小和数据量自动决定桶的数量。
  • "log_policy_1day"和"log_s3"意味着将超过1天的日志移动到S3存储。
CREATE DATABASE log_db;
USE log_db;

CREATE RESOURCE "log_s3"
PROPERTIES
(
   "type" = "s3",
   "s3.endpoint" = "your_endpoint_url",
   "s3.region" = "your_region",
   "s3.bucket" = "your_bucket",
   "s3.root.path" = "your_path",
   "s3.access_key" = "your_ak",
   "s3.secret_key" = "your_sk"
);

CREATE STORAGE POLICY log_policy_1day
PROPERTIES(
   "storage_resource" = "log_s3",
   "cooldown_ttl" = "86400"
);

CREATE TABLE log_table
(
 ``ts` DATETIMEV2,
 ``clientip` VARCHAR(20),
 ``request` TEXT,
 ``status` INT,
 ``size` INT,
 INDEX idx_size (`size`) USING INVERTED,
 INDEX idx_status (`status`) USING INVERTED,
 INDEX idx_clientip (`clientip`) USING INVERTED,
 INDEX idx_request (`request`) USING INVERTED PROPERTIES("parser" = "english")
)
ENGINE = OLAP
DUPLICATE KEY(`ts`)
PARTITION BY RANGE(`ts`) ()
DISTRIBUTED BY RANDOM BUCKETS AUTO
PROPERTIES (
"replication_num" = "1",
"storage_policy" = "log_policy_1day",
"deprecated_dynamic_schema" = "true",
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-3",
"dynamic_partition.end" = "7",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "AUTO",
"dynamic_partition.replication_num" = "1"
);

4.2 步骤2:导入日志

Apache Doris支持多种数据导入方法。对于实时日志,推荐以下三种方法:

  • 从Kafka消息队列中拉取日志:Routine Load
  • Logstash:通过HTTP API将日志写入Doris
  • 自定义编写程序:通过HTTP API将日志写入Doris

使用Kafka进行数据摄取

对于写入Kafka消息队列的JSON日志,创建常规加载(Routine Load),以便Doris从Kafka中拉取数据。以下是示例。property.* 配置为可选配置:

-- 准备Kafka集群和主题("log_topic")

-- 创建常规加载,从Kafka的 log_topic 加载数据到 "log_table"
CREATE ROUTINE LOAD load_log_kafka ON log_db.log_table
COLUMNS(ts, clientip, request, status, size)
PROPERTIES (
   "max_batch_interval" = "10",
   "max_batch_rows" = "1000000",
   "max_batch_size" = "109715200",
   "strict_mode" = "false",
   "format" = "json"
)
FROM KAFKA (
   "kafka_broker_list" = "host:port",
   "kafka_topic" = "log_topic",
   "property.group.id" = "your_group_id",
   "property.security.protocol"="SASL_PLAINTEXT",     
   "property.sasl.mechanism"="GSSAPI",     
   "property.sasl.kerberos.service.name"="kafka",     
   "property.sasl.kerberos.keytab"="/path/to/xxx.keytab",     
   "property.sasl.kerberos.principal"="xxx@yyy.com"
);

可以通过SHOW ROUTINE LOAD命令查看常规加载的运行情况。

通过Logstash进行数据导入

配置Logstash的HTTP输出,然后通过HTTP Stream Load将数据发送到Doris。

1) 在logstash.yml中指定批量大小和批量延迟,以提高数据写入性能。

pipeline.batch.size: 100000
pipeline.batch.delay: 10000

2) 在日志收集配置文件testlog.conf中添加HTTP输出,URL为Doris中的Stream Load地址。

  • 由于Logstash不支持HTTP重定向,应该使用后端地址而不是FE地址。
  • 头部中的授权是http basic auth,使用echo -n 'username:password' | base64进行计算。
  • 头部中的load_to_single_tablet可以减少数据摄取中的小文件数量。
output {
  http {
      follow_redirects => true
      keepalive => false
      http_method => "put"
      url => "http://172.21.0.5:8640/api/logdb/logtable/_stream_load"
      headers => [
          "format", "json",
          "strip_outer_array", "true",
          "load_to_single_tablet", "true",
          "Authorization", "Basic cm9vdDo=",
          "Expect", "100-continue"
      ]
      format => "json_batch"
  }
}

通过自定义程序进行数据摄取

以下是通过HTTP Stream Load将数据摄取到Doris的示例。

注意:

  • 使用basic auth进行HTTP授权,使用 echo -n 'username:password' | base64 进行计算。
  • http header "format:json":指定数据类型为JSON。
  • http header "read_json_by_line:true":每行都是一个JSON记录。
  • http header "load_to_single_tablet:true":每次写入一个分片(tablet)。
  • 对于数据写入客户端,建议批量大小为100MB~1GB。未来的版本将在服务器端启用Group Commit,并减小客户端的批量大小。
curl \
--location-trusted \
-u username:password \
-H "format:json" \
-H "read_json_by_line:true" \
-H "load_to_single_tablet:true" \
-T logfile.json \
http://fe_host:fe_http_port/api/log_db/log_table/_stream_load

4.3 步骤3:执行查询

Apache Doris支持标准SQL,因此可以通过MySQL客户端或JDBC连接到Doris,然后执行SQL查询。

mysql -h fe_host -P fe_mysql_port -u root -Dlog_db

一些常见的日志分析查询:

  • 检查最新的10条记录。
SELECT * FROM log_table ORDER BY ts DESC LIMIT 10;
  • 检查Client IP为"8.8.8.8"的最新的10条记录。
SELECT * FROM log_table WHERE clientip = '8.8.8.8' ORDER BY ts DESC LIMIT 10;
  • 检索在"request"字段中包含"error"或"404"的最新的10条记录。MATCH_ANY是Doris中的通过全文搜索来查找包含指定关键词中任意一个的记录。
SELECT * FROM log_table WHERE request MATCH_ANY 'error 404' ORDER BY ts DESC LIMIT 10;
  • 检索在"request"字段中同时包含"image"和"faq"的最新的10条记录。MATCH_ALL也是Doris中的全文搜索语法关键词,表示查找同时包含所有指定关键词的记录。
SELECT * FROM log_table WHERE request MATCH_ALL 'image faq' ORDER BY ts DESC LIMIT 10;

5 总结

如果需要一种高效的日志分析解决方案,Apache Doris是非常友好的选择,尤其适合那些具备SQL知识的读者。相比ELK堆栈,使用Apache Doris可以获得更好的无模式支持,实现更快的数据写入和查询,并且减少存储负担。


责任编辑:武晓燕 来源: Java学研大本营
相关推荐

2023-10-29 12:54:16

Doris数据仓库

2023-12-25 11:18:12

OpenTeleme应用日志Loki

2023-11-30 18:03:55

IDEA工具

2021-04-12 08:17:12

ElasticSear分词中文

2023-10-10 07:24:59

SRE日志OnCall

2021-12-24 10:45:19

PandasLambda数据分析

2015-09-25 11:03:14

数据中心日志分析

2023-03-31 17:33:06

Oracle数据库

2024-02-04 00:00:00

Loki性能查询

2023-10-04 00:17:00

SQL数据库

2021-08-09 15:00:36

SQL数据库

2023-09-26 22:12:13

数据仓库Doris

2023-09-04 07:57:03

后端开发日志

2023-03-28 16:01:01

PytorchSimCLR算法

2014-05-21 09:14:00

VDI审计日志监控监控

2014-05-21 14:03:55

日志监控VDI

2014-12-16 10:08:25

Docker日志处理镜像

2020-03-07 18:00:17

logzeroPython日志记录

2010-03-03 15:06:52

Android 游戏开

2015-09-11 15:41:08

点赞
收藏

51CTO技术栈公众号