第一步:定下好名字
第一步当然是给新的业务起一个响当当的名字啦。后面的各处变更,都要用到这个名字。所以起名时请三思,想出一个别具一格且能顾名思义的好名字。
第二步:添加对应的映射模板
确定名字之后,先给 elasticsearch 准备对应的映射模板。这样一来,新创建的索引就能立即拥有自己的映射规则:
type_name_template.json
{
"template": "type_name-*",
"mappings": {
"type_name": {
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "string",
"index":"not_analyzed"
}
}
}],
"properties" : {
"@timestamp" : {
"type" : "date",
"format" : "strict_date_optional_time||epoch_millis"
},
...
(示例中用的是 elasticsearch 2.x 的语法,5.x 的略有变动)
# 更新 elasticsearch 的映射模板
curl 'http://localhost:9200/_template/type_name' -d @type_name_template.json
第三步:编写 logstash 配置规则
一般情况下,接入方的输入需要遵从一致的约定,比如提供 type
字段来标记不同的输入数据。
据此能够在 logstash 中区分特定的业务。类似这样:
filter {
if [type] == "type_name1" {
...
}
else if [type] == "type_name2" {
...
}
}
output {
elasticsearch {
hosts => "localhost:9200"
# 采用第二步提交到 elasticsearch 的模版
manage_template => false
index => "%{[type]}-%{+YYYY.MM.dd}"
}
}
假如因为某些乱七八糟的原因,接入方无法调整其输入,也可以根据输入来源作区分。
比如 HTTP 输入中,logstash 会给事件打上 [headers][request_path]
标签,表示 HTTP 输入时实际的请求路径。
所以给不同的业务分配不同的 HTTP 请求路径,就等于分配用于区分的字段。
当然 [headers][request_path]
通常并没有入库的必要。
logstash 事件有一个 @metadata
属性,这个属性里面的值只在 logstash 内部可见,不会输出到 elasticsearch。
在删掉 [headers][request_path]
之前,可以把该标签的值转存到 [@metatdata][type]
之中。
由于编写过滤规则的逻辑的重担是落在我身上的,在更改到线上之前,我需要在本地过一遍,以确保编写的过滤规则能够满足接入方的需求。
为了实现这一目的,我编写了一套接口测试。这套接口测试会读取接入方准备的输入内容,模拟实际的 HTTP 请求打到 logstash 上,看看过滤规则是否能产生接入方预期的输出。
如果测试通过,说明 logstash 的过滤规则已经没问题了。(或者,至少在接入方所给的输入下,能够给出预期的输出)
第四步:更新 logstash 配置
终于到最后一步,更新线上的 logstash 配置了。
如果没有启用 auto reload
功能(-r
选项),直接全量更新配置文件,在替换完毕后给 logstash 发送 SIGHUP
,让它重新加载配置即可。
如果启用了 auto reload
,具体操作会复杂一点。为了避免 reload 配置后,因缺少 grok pattern
而出错,我们先要更新配置文件中涉及的 patterns
目录下的文件。更新 patterns
文件是不会触发 reload 的。
接下来再更新 logstash 的配置文件,让它 reload 最新的配置。这一过程中 logstash 会重新读取 patterns
目录下的文件。完整的配置更新过程到此结束。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。