1. 概述
应用程序、服务器、云基础设施、IoT 和移动设备、DevOps、微服务架构—最重要的业务和 IT 发展趋势帮助我们以前所未有的方式优化运维和客户体验。但这些趋势也导致由机器生成的数据出现爆炸式成长,其中包括日志和指标等,例如,用户交易、客户行为、传感器活动、机器行为和安全威胁等。这些数据十分复杂,但同时也最为重要,因为它们包含关于 IT、安全和业务的运维情报。
日志分析涉及到对由您的 IT 系统和技术基础设施生成的机器数据进行搜索、分析与可视化,以便获得运维方面的见解。传统的数据分析工具已不能胜任如此多样性而且快速增加的机器数据的处理工作。
日志数据在不断增长。如果没有一个整体的、具有成本意识的解决方案,成本将继续不受控制地增长。人类数据和机器生成的数据正在以惊人的速度增长,其中人类生成的数据的增长率通常是商业数据的 10 倍。机器数据预计将增长更多。
传统的日志分析场景,直接在日志文件中 grep、awk 就可以获得自己想要的信息。但在规模较大的场景中,此方法效率低下,面临如下问题:
- 日志量太大如何归档?
- 文本搜索太慢怎么办?
- 如何多维度查询及关联查询分析等等
解决上面的问题,需要集中化的日志管理,所有服务器上的日志收集汇总。常见解决思路是建立集中式日志收集系统,将所有节点上的日志统一收集,管理,访问。ELK就是解决这些问题的一种解决方案。
我们知道 Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,也能支持高吞吐的复杂分析场景。基于此,Apache Doris 能够较好的满足报表分析、即席查询、统一数仓构建、数据湖联邦查询加速等使用场景,用户可以在此之上构建用户行为分析、AB 实验平台、日志检索分析、用户画像分析、订单分析等应用。
如果我们希望使用 Apache Doris 来更好解决日志存储与分析场景的痛点,其实现路径也非常清晰——在数据库内部增加倒排索引、以满足字符串类型的全文检索和普通数值/日期等类型的等值、范围检索,同时进一步优化倒排索引的查询性能、使其更加契合日志数据分析的场景需求。
在Apache Doris 2.0 给大家带来了全新的倒排索引,利用Doris的MPP执行框架、向量化计算引擎、列式存储、标准SQL、CBO的查询优化器等特性为用户提供高性能,低成本的日志分析服务。
通过在 Apache Doris 2.0.0 最新版本的探索与持续优化,在相同硬件配置和数据集的测试表现上,Apache Doris 在数据库内核实现高性能倒排索引后,相对于 ES 实现了日志数据写入速度提升 4 倍、存储空间降低 80%、查询性能提升 2 倍,再结合 Apache Doris 2.0.0 版本引入的冷热数据分离特性,整体性价比提升 10 倍以上!
关于Doris 倒排索引的更多介绍可以参考:https://mp.weixin.qq.com/s/WJXKyudW8CJPqlUiAro_KQ
下面我们将以Apache Doris 2.0 为例给大家演示怎么使用Doris来进行日志分析。我将使用下列组件来完成这个工作。演示环境是在Macos(M1芯片) 下,如果你在Linux 系统下,操作也是一样的。
- Apache Doris 2.0
- Logstash-7.17.4
- Filebeats-8.7.1
- Grafana
2. 系统安装
2.1 安装 Doris
如果你是其他Linux 系统可以直接从官网下载预编译好的Doris 2.0 安装包:
https://doris.apache.org/zh-CN/download
如果你也是Macos系统,可以参考官网文档进行本地编译:
https://doris.apache.org/zh-CN/docs/1.2/install/source-install/compilation-mac
安装可以参考:
https://zhuanlan.zhihu.com/p/559718796
2.2 安装 Nginx
Nginx的安装我也是通过Brew 安装的,其他平台的Nginx安装,请自行搜索,
brew install nginx
首先我们这里分析的是Nginx的日志信息,我对Nginx的日志格式进行了调整,特别是时间具体的配置信息如下:
这里调整了 log_format
配置,每个字段时间分隔符指定成了 # ,同时将时间格式调成yyyy-MM-dd HH:mm:ss 格式
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$year-$month-$day $hour:$minutes:$seconds#$remote_addr#$remote_user#"$request"#"$uri"#' '$status#$request_time#$request_length#$body_bytes_sent#$bytes_sent#$ssl_protocol#$ssl_cipher#' '$http_referer#$http_x_forwarded_for#"$http_user_agent"'; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") { set $year $1; set $month $2; set $day $3; set $hour $4; set $minutes $5; set $seconds $6; } #access_log logs/host.access.log main; location / { root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } include servers/*; }
Nginx 安装好之后只有一个默认的欢迎页,我这边为了生成更多日志,我在Nginx下本地部署了Doris的官网
访问后生成的日志格式如下:
2023-05-23 00:17:49#127.0.0.1#-#"GET /zh-CN/blog/summit HTTP/1.1"#"/zh-CN/blog/summit"#301#0.000#838#169#379#-#-#-#-#"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.0.0" 2023-05-23 00:17:49#127.0.0.1#-#"GET /zh-CN/blog/summit/ HTTP/1.1"#"/zh-CN/blog/summit/index.html"#200#0.000#839#65503#65744#-#-#-#-#"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.0.0"
2.3 安装Logstash
我这边是直接使用 Brew 进行直接安装的,安装命令如下:
brew install elastic/tap/logstash-full
Logstash 配置文件目录:/opt/homebrew/etc/logstash
启动命令目录:/opt/homebrew/Cellar/logstash-full/7.17.4/bin/logstash
创建并使用管道配置文件:一个 Logstash 管理通常有一个或多个 input, filter 和 output 插件
验证通道,我们使用命令行输入级命令行输出的方式
/opt/homebrew/Cellar/logstash-full/7.17.4/bin/logstash -e 'input { stdin { } } output { stdout { } }'
随便输入一串数组回车可以看到下面的信息:
我们在 Logstash 配置目录下创建一个新的Doris的管道配置文件:doris.yaml
input { beats { host =>"192.168.66.95" port => 5044 } } output { doris { http_hosts => [ "http://192.168.66.95:8030" ] user => "root" password => "zhangfeng" db => "demo" table => "nginx_log" label_prefix => "doris_logstash_nginx_log" column_separator => "#" columns => "http_time ,remote_addr,remote_user,request ,uri ,status,request_time,request_length,body_bytes_sent,bytes_sent ,ssl_protocol ,ssl_cipher ,http_referer ,http_x_forwarded_for ,http_user_agent" } }
具体Doris的管道配置说明如下:
连接相关配置:
配置 | 说明 |
http_hosts | FE的HTTP交互地址。 例如: ["http://fe1:8030", "http://fe2:8030"] |
user | 用户名,该用户需要有doris对应库表的导入权限 |
password | 密码 |
db | 数据库名 |
table | 表名 |
label_prefix | 导入标识前缀,最终生成的标识为 {label_prefix}{db}{table}_{time_stamp} |
导入相关配置:
配置 | 说明 |
column_separator | 列分割符,默认为\t。 |
columns | 用于指定导入文件中的列和 table 中的列的对应关系。 |
where | 导入任务指定的过滤条件。 |
max_filter_ratio | 导入任务的最大容忍率,默认零容忍。 |
partition | 待导入表的 Partition 信息。 |
timeout | 超时时间,默认为600s。 |
strict_mode | 严格模式,默认为false。 |
timezone | 指定本次导入所使用的时区,默认为东八区。 |
exec_mem_limit | 导入内存限制,默认为 2GB,单位为字节。 |
其他配置
配置 | 说明 |
save_on_failure | 如果导入失败是否在本地保存,默认为true |
save_dir | 本地保存目录,默认为 /tmp |
automatic_retries | 失败时重试最大次数,默认为3 |
batch_size | 每批次最多处理的event数量,默认为100000 |
idle_flush_time | 最大间隔时间,默认为20(秒) |
启动指定管道的命令如下:
/opt/homebrew/Cellar/logstash-full/7.17.4/bin/logstash -f /opt/homebrew/etc/logstash/doris.yaml --config.reload.automatic
启动之后,Logstash 开始通过管道 Input 采集数据,然后按照管道 output 配置的输出管道输出到指定的地方。
2.4 安装Filebeats
我这边是直接使用 Brew 进行直接安装的,安装命令如下:
brew install filebeat
配置 Filebeats
vi /opt/homebrew/etc/filebeat/filebeat.yml
修改下面几项:
filebeat.inputs: # Each - is an input. Most options can be set at the input level, so # you can use different inputs for various configurations. # Below are the input specific configurations. # filestream is an input for collecting log messages from files. - type: log # Unique ID among all inputs, an ID is required. id: my-filestream-id # Change to true to enable this input configuration. enabled: true # Paths that should be crawled and fetched. Glob based paths. paths: - /opt/homebrew/Cellar/nginx/1.23.4/logs/access.log #- c:\programdata\elasticsearch\logs\* ...... #output.elasticsearch: # Array of hosts to connect to. hosts: ["localhost:9200"] # Protocol - either `http` (default) or `https`. #protocol: "https" # Authentication credentials - either API key or username/password. #api_key: "id:api_key" #username: "elastic" #password: "changeme" # ------------------------------ Logstash Output ------------------------------- output.logstash: # The Logstash hosts hosts: ["192.168.66.95:5044"]
- type :改成 log
- enabled :改成 true
- paths :这里是你要采集的日志文件路径
- output.elasticsearch :注释掉
- output.logstash :打开
启动Filebeats
/opt/homebrew/opt/filebeat/bin/filebeat -e -c /opt/homebrew/etc/filebeat/filebeat.yml -d "publish"
2.5 编译安装 Doris Logstash 插件
下载 Doris 源码:
git clone https://github.com/apache/doris.git
在extension/logstash/ 目录下执行
gem build logstash-output-doris.gemspec
你将在同目录下得到 logstash-output-doris-{version}.gem 文件
安装 Doris Logstash 插件:
/opt/homebrew/opt/filebeat/bin/filebeat -e -c /opt/homebrew/etc/filebeat/filebeat.yml logstash-output-doris-{version}.gem
安装成功之后可以看到提示信息:
3. 采集分析
这里我们主要使用到Doris 2.0 里的新功能倒排索引,Doris 倒排索引的语法如下:
- 建表时指定索引
CREATE TABLE table_name ( columns_difinition, INDEX idx_name1(column_name1) USING INVERTED [PROPERTIES("parser" = "english|chinese")] [COMMENT 'your comment'] INDEX idx_name2(column_name2) USING INVERTED [PROPERTIES("parser" = "english|chinese")] [COMMENT 'your comment'] ) table_properties;
- Alter方式添加索引
-- 语法1 CREATE INDEX idx_name ON table_name(column_name) USING INVERTED [PROPERTIES("parser" = "english|chinese")] [COMMENT 'your comment']; -- 语法2 ALTER TABLE table_name ADD INDEX idx_name(column_name) USING INVERTED [PROPERTIES("parser" = "english|chinese")] [COMMENT 'your comment'];
语法说明:
- 建表时定义倒排索引,语法说明如下
- 默认不指定代表不分词
- english是英文分词,适合被索引列是英文的情况,用空格和标点符号分词,性能高
- chinese是中文分词,适合被索引列有中文或者中英文混合的情况,采用jieba分词库,性能比english分词低
- USING INVERTED 是必须的,用于指定索引类型是倒排索引
- PROPERTIES 是可选的,用于指定倒排索引的额外属性,目前有一个属性parser指定分词器
- COMMENT 是可选的,用于指定注释
下面这个是我这个例子的创建和Nginx日志格式相对应的表结构,建表语句如下:
CREATE TABLE nginx_log( http_time datetimev2, remote_addr varchar(200), remote_user varchar(200), request string, uri string, status int, request_time decimal(12,6), request_length int, body_bytes_sent int, bytes_sent int, ssl_protocol varchar(200), ssl_cipher varchar(200), http_referer varchar(200), http_x_forwarded_for varchar(200), http_user_agent string, INDEX idx_request(request) USING INVERTED PROPERTIES("parser" = "english") , INDEX idx_uri(uri) USING INVERTED PROPERTIES("parser" = "english") , INDEX idx_remote_addr(remote_addr) USING INVERTED PROPERTIES("parser" = "english") , INDEX idx_http_user_agent(http_user_agent) USING INVERTED PROPERTIES("parser" = "english") ) Duplicate KEY(`http_time`, `remote_addr`) DISTRIBUTED BY HASH(`http_time`) BUCKETS 2 PROPERTIES ( "replication_allocation" = "tag.location.default: 1", "in_memory" = "false", "storage_format" = "V2" );
这里我对部分字段创建的了倒排索引,并指定分词是英文分析,如果你的日志中有中文,你可以指定成:chinese(中文分词)
Logstash 和 Filebeats 启动之后,我们在控制台可以看到 Logstash 采集数据入库的信息:
然后我们在MySQL 命令行下可以通过SQL进行查询日志的表
日志检索及分析
- 我们按照响应状态进行分组统计请求数量
mysql> select count(*),status from nginx_log group by status ; +----------+--------+ | count(*) | status | +----------+--------+ | 13 | 304 | | 8 | 301 | | 6 | 200 | +----------+--------+
2. 统计访问社区栏目的要请求次数
mysql> select count(*) from nginx_log where request MATCH_ANY 'community'; +----------+ | count(*) | +----------+ | 12 | +----------+ 1 row in set (0.02 sec)
3. 统计访问博客栏目的要请求次数
mysql> select count(*) from nginx_log where request MATCH_ANY 'blog'; +----------+ | count(*) | +----------+ | 7 | +----------+ 1 row in set (0.03 sec)
4. Doris 倒排索引能力
Doris 倒排索引具备以下能力
- 支持字符串类型的全文检索
- 支持字符串全文检索,包括同时匹配多个关键字MATCH_ALL、匹配任意一个关键字MATCH_ANY
- 支持字符串数组类型的全文检索
- 支持英文、中文分词
- 加速普通等值、范围查询,覆盖bitmap索引的功能,未来会代替bitmap索引
- 支持字符串、数值、日期时间类型的 =, !=, >, >=, <, <= 快速过滤
- 支持字符串、数字、日期时间数组类型的 =, !=, >, >=, <, <=
- 支持完善的逻辑组合
- 新增索引对OR NOT逻辑的下推
- 支持多个条件的任意AND OR NOT组合
- 支持灵活、快速的索引管理
- 支持在创建表上定义倒排索引
- 支持在已有的表上增加倒排索引,而且支持增量构建倒排索引,无需重写表中的已有数据
- 支持删除已有表上的倒排索引,无需重写表中的已有数据