昔有打码之辛,今有ELK之便,潸然泪下

2020-06-03 00:00:00 索引 数据 分析 的是 配置

文·黄崇远

说起ELK,熟悉的看官可能都知道接下来要讲什么了,就算是不熟悉的,想必也多少知道一丢丢子,毕竟ELK的经典组合是具有一定年份的了。

笔者按:
遥想N年前,哪有这么多高度封装的工具,都是自己写代码屁颠屁颠去获取数据,老老实实的调ES的Rest full API自己灌数据,等等诸如此类。
每思及此,潸然泪下!(近在看裴松之注的《三国志》,有点抽风,莫理会)

就算如此,这里还是花少许笔墨,简单的描述一把,再做其他的阐述。

什么是ELK?

首先ELK肯定不是一个东西,要不然标题也就不会叫“三剑客ELK”了,但实际上也不是三个东西,以前或许是,但现在已经不能算了。

官方说法就是,ELK的核心代表是ElasticSearch,Logstash,Kibana,这三者是核心套件,但目前已经不止如此了,已经形成了围绕三者的整套解决方案,以应对各种不同的业务场景。

ElasticSearch是实时的全文搜索和分析引擎,起源于搜索还是依托于Lucene的草莽时代,他将Lucene进行了集成了,然后在此基础上不但简化了搜索引擎的搭建成本,也在性能提升上做了很多优化,目前已经算是开源搜索领域里一家独大的底层框架了。

当然,早期的ES多也只能算个搜索引擎,在集成了分析体系之后,再配合Kibana的分析可视化的话,你说他也是个分析引擎,一点毛病都没有,支持大规模的数据分析溜溜的。

他本身集成了搜索,分析,以及可扩展的存储等功能,在查询的支持上,不仅提供了大家喜闻乐见的Rest full访问,还提供了很程序员化的JAVA API等,并且速度真的是公认的快。

Logstash从名字上不难发现,与log强相关,早期定义为用来搜集,分析和过滤日志的工具。他的强大之处在于几乎支持任何类型的日志输入,实际上是依托于其强大的日志解析插件(这个后面会讲到),并且目前对于输入源,他已经彻底的开放了,什么消息队列(常用的数据源),各种常见的数据库,redis,甚至是直接做端口监控等等,简直逆天。

三剑客中后一剑是Kibana,目前他核心提供了ES的界面化查询,ES集群以及索引情况监控,数据的可视化分析,甚至提供了各种图表支持等,当然他同样也可以基于Logstash去做数据可视化的分析。

除了ELK三个,后续又补充了一个实力组件Filebeat。看名字就知道,他是与文件强关联的一个组件。我们知道Logstash本身就支持从log文件中进行数据的获取,而Filebeat就是大大加强数据搜集这层的组件,甚至在Logstash中作为一个数据源的插件做数据源的介入集成。

至于说怎么安装部署ELK,这里不会过多赘述,自行百度谷歌,有很多教程,我这里用我们目前的使用方式,以快的方式简单讲讲如何使用ELK,仅作为一个用例的参考,帮助大家快速入门,更多资料还得依靠官网。

我司ELK使用的一个场景

在我司,或者更确切的说在我司大数据团队里,ELK基本框架服务的是我们的基础搜索,而不是做日志分析用,运维那边使用ELK做日志分析暂且不表。

以商品搜索为例,业务数据库在生产环境,我们使用canel+otter的架构来做商品业务库的变动同步,几百万级的属性变更同步肯定是支撑的住的。

然后在数据这边的环境中,将商品对应的画像属性进行加挂,以及其他相关属性的计算合并,然后以20分钟的时间,周期性的变更到商品的索引文档中。

所以回到ELK这边来说就是,数据源是MySQL,对应的是周期性计算的临时表,然后Logstash读取MySQL对应的临时计算变更表,写入ES对应的索引中,通过Kibana进行ES的状态监管,以及必要时替代旧时代的head组件进行索引查询等。

我们来看一下Logstash对应的配置conf就清楚了大致的流程,conf总共分三个部分input是数据源获取,filter是过滤器可以做数据中间态转换(这个很牛,一会儿单独讲讲),后是output,我们这里妥妥的就是ES了,所以需要做ES的一些连接配置。

以我们的XX.conf我们先来看看input输入的配置(请原谅我将一些敏感信息给XX了)。

input {
jdbc {
id => "item_test"
jdbc_driver_library => "/data/logstash/mysql-connector-java-5.1.44.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql://host-XX:3306/XX"
jdbc_user => "XX"
jdbc_password => "XX"
connection_retry_attempts => 3
connection_retry_attempts_wait_time => 1
jdbc_default_timezone => "Asia/Shanghai"
jdbc_fetch_size => 50000
# 使用时验证连接
jdbc_validate_connection => true
# 验证连接的时间间隔(秒)
jdbc_validation_timeout => 600
use_column_value => true
tracking_column_type => "timestamp"
tracking_column => "update_time"
# 后运行时间的文件路径
last_run_metadata_path => "/data/logstash/metadata/.just_path_XX"
# 连接池大连接数 4 默认也为4
sequel_opts => { "max_connections" => 4 }
# 执行语句的存放路径
statement_filepath => "/data/logstash/sql/XX.sql"
}
}

如上,就是一个典型从MySQL获取数据的input,前面的数据库连接相关的信息就不多说,核心注意一下last_run_metadata_path的配置,这个配置有助于你做执行进度的记录,避免重复“消费”,第二个就是执行的SQL对应文件位置。

实际上就是SQL查询文件,需要注意的就是,一是要提供document_id对应所需的字段,另一个就是查询的字段跟索引对应的属性字段名称要一一对应。

第二个就是filter过滤器,强大的过滤器,当然我这里没有体现出他的强大,因为我的数据都是规整的,不需要他强悍的转换功能,只需要将将字段进行拆分即可。所以,针对filter过滤器,样例讲完了,还得好好说道说道,这里就简单略过了。

filter{
mutate {
remove_field => [ "@timestamp", "@version"]
}
mutate {
split => { "activity_id" => "," }
}
}

这里简单说下remove_field是字段移除,split是数组切分。

后是output,数据的输出,我们这里输出至ElasticSearch,所以进行ES连接,索引指定等配置。

output {
elasticsearch {
#配置若干个ES的hosts
hosts => ["host-XX1:9200","host-XX2:9200",...,...]
index => "index-XX"
document_type => "XX"
document_id => "%{XX_id}_%{XX_id}"
action => "update"
doc_as_upsert => true
}

}

根据字面意思,很容易理解,这里稍微说明一下的就是,document_id的组合,我们这里是通过两个关键id进行组合生成的。

通过如下命令,将我们的conf加载到Logstash中,需要注意的就是path.data参数的配置,在遇到相同目标操作的时候,可以起到类似锁的作用,避免数据插入干扰。

/data/logstash/logstash/bin/logstash -f /data/logstash/conf/XX.conf --path.data=/data/logstash/data/XX

至于Kibana这里简单的说下。

需要注意的是,Kibana如果在配置文件中指定访问的ES的host和port就会默认取与Kibana本地的地址访问,具体配置为安装目录下config/kibana.yml,对应配置如下:

elasticsearch.url: "hosts-XX:9200"

如图Management进行索引管理,主要是索引的添加操作,Discover进行索引的查询,Vissulize是分析图表,如果用的溜的话,可以做一些很“可视化”的图表出来(反正我不溜),比如不是很溜的例子:

再额外说下的就是Monitoring,可以做ES集群以及索引情况的健康状态跟踪,具体的就不说了,详情请参考官网,这些信息都是比较容易拿到的。

如上,基本上就是一个简单而又实用的例子了,基本流程是过了一遍,更多的限于篇幅就不多说了,自行扩展,更多是给大家一个入门的路子。

重点又简单的提一下Logstash的Grok插件

Logstash对于文本的解析是非常强大的,其中Grok是Logstash是专为文本解析而生的。Grok内置了很多正则表达式,跟我们C语言的宏定义有点像,感兴趣的可以参考这里:

github.com/elastic/logs

大概是长这样子的:

举个实例可能会好理解点,以需要解析的log如下为例(这个例子是我抄来的,方便解说,哈哈):

2016-11-30 06:33:33 192.168.5.116 GET /Hotel/HotelDisplay/cncqcqb230 - 80 - 192.168.9.2 Mozilla/5.0+(Macintosh;+U;+Intel+Mac+OS+X+10.9;+en-US;+rv:1.9pre)+Gecko - 200 0 0 45

我们的过滤器配置如下:

filter {
grok {
match => [
"message" ,"\s*(?<time>([0-9]{4}\-[0-9]{2}\-[0-9]{2}\s+[0-9]{2}:[0-9]{2}:[0-9]{2}))\s+%{IPORHOST:clientip}\s+%{WORD:verb}\s+%{URIPATHPARAM:request}\s+\-\s+(?<port> ([0-9]{2}.*?))\s+\-\s+%{IPORHOST:sourceip}\s+(?<http_user_agent>(\S+\s+).*?).*"
]
}
date {
match => ["time", "yyyy-MM-dd HH:mm:ss"]
}
mutate{
remove_field =>["message"]
}
}

先来看结果(结果是直接输出到控制台,你可以做入库,入ES都可以),再来分说。

{
"message" => "2016-11-30 06:33:33 192.168.5.116 GET /Hotel/HotelDisplay/cncqcqb230 - 80 - 192.168.9.2 Mozilla/5.0+(Macintosh;+U;+Intel+Mac+OS+X+10.9;+en-US; +rv:1.9pre)+Gecko - 200 0 0 45",
"@version" => "1",
"@timestamp" => "2016-11-29T22:33:33.000Z",
"host" => "dr-mysql01.zjcap.com",
"time" => "2016-11-30 06:33:33",
"clientip" => "192.168.5.116",
"verb" => "GET",
"request" => "/Hotel/HotelDisplay/cncqcqb230",
"port" => "80",
"sourceip" => "192.168.9.2",
"http_user_agent" => "Mozilla/5.0+(Macintosh;+U;+Intel+Mac+OS+X+10.9;+en-US;+rv:1.9pre)+Gecko "
}

从模板里可以看出,他接受字对应的正则,比如<time>,也接受类似的宏定义,比如IPORHOST:clientip,URIPATHPARAM:request,等等,并且支持重命名。

例如上述说到的两个默认定义,如下:

IPORHOST (?:%{HOSTNAME}|%{IP})
URIPATHPARAM %{URIPATH}(?:%{URIPARAM})?


只要你对正则表达式很熟悉,或者说认真的看看grok-patterns,解析任何形态的log岂不是手到擒来,如果再结合其他插件诸如mutate,drop,clone,geoip等,以及Filebeat牛逼插件,可以做很多事情。

所以说ELK通过“日志分析”的名头奠定了日志分析的地位,不是白搭的。

给一些官方的各种资料入口,想要进一步研究的可以看看,这里只是给大伙儿打开一个门缝而已,如下自取(如果对ELK熟悉的略过):

Grok-patterns:
github.com/elastic/logs

Filebeat:
elastic.co/cn/products/

Logstash:
elastic.co/cn/products/

Kibana:
elastic.co/cn/products/

ElasticSearch:
elastic.co/cn/products/

elasticsearch中文社区:
elasticsearch.cn/

打完收工,梳理的很辛苦,如果觉得有用的话,不吝打赏杯深夜咖啡钱,再实在不行,顺路点点顶部或者文中的“广了个告”也行,穷的揭不开锅,写文为生了,哈哈。

--- 2018年12月7日 凌晨,癸亥月 壬申日 子时

相关文章