Elasticsearch 实战案例(索引切分、模板、别名、数据迁移)

背景

基于ELK搭建的日志平台,前期匆忙建设过程中一些参数和设计未做过多的考虑,上线后就需要不断根据实际情况做调整,而一些调整限于ELK的一些特性,一旦操作不当就会出现丢数据、数据写入异常、数据查不到等情况。

因此如何在这种背景下,做到对使用方无感知的动态调整是我们所要实现的目标。本文更加注重实践而非深层次的理论讲解,有兴趣深入了解的可以自行研习。

总体架构


Elasticsearch 实战案例(索引切分、模板、别名、数据迁移)



CASES

CASE1:按日/月生成索引

创建的nginx access_log索引,开始采集2周后,数据达到25G+(number_of_replicas=1,因此总体数据超过50G),如果不进行索引拆分,该索引将越来越大,最终会严重影响查询效率,并且一旦出现索引损坏造成的风险也更大。

通过配置logstash ouput 插件实现按照日期生成新索引:

output {
elasticsearch {
hosts => ["192.168.0.1:9200"]
index => "php-nginx-log-%{+YYYY.MM.DD}" #按照天生成索引
}
}

通过我们的配置,目前会存在2个index,分别为历史的php-nginx-log索引和以php-nginx-log.2019-01-15索引。

CASE2:Kibana查询所有数据

由于目前我们的索引不再是指定的具体索引,还是一类按照事先约定的命名格式索引集合,这时我们想要能够在Kibana查询数据时不受影响,能够正常查询到数据,此时主要有两种解决方式:

1、更改Kibana的Create index pattern,使用通配符关联出所有index


Elasticsearch 实战案例(索引切分、模板、别名、数据迁移)



2、使用index aliases,详情:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/indices-templates.html

Elasticsearch的别名,就类似数据库的视图,别名不仅仅可以关联一个索引,它能聚合多个索引,下文还会提到别名的更重要的特性。

通过别名的方式是更加建议的方式。

POST /_aliases
{
"actions" : [
{ "add" : { "index" : "new_index1", "alias" : "alias1" } }
]
}

说明:这里使用Elasticsearch的REST API进行设置,具体详情参考官网:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/docs.html ,下文中的类似代码块都是此类调用。

CASE3:通过模板创建Index

创建index后,如果未指定具体mapping,则在插入具体doc数据时,会自动生成,具体数据字段的数据类型Elasticsearch会做一定的动态识别,但是大部分都将以string定义,这种情况下我们在使用数据时 ,就会出现一些不便,如 Kibana一些函数必须是整型类型、ip类型的字段才可以使用,另外全部默认为string类型会导致查询效率的低下和存储容量的浪费。

这时就需要我们去指定index的mapping,而很重要的一点:mapping中的filed一点指定后(无论是默认生成还是手动声明)就无法进行update filed操作,如果要修改通常只能进行create 新的index。因此我们往往会在index写入数据前就创建好index的mapping,如下:

PUT new_index1
{
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"_doc" : {
"properties" : {
"field1" : { "type" : "text" }
}
}
}
}

而通过CASE1中,已经说明了我们的index都是由Logstash按照日期自动创建的,因此手动通过API的方式无法满足我们的需求,这时我们就需要使用Elasticsearch的template特性:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/indices-templates.html

创建template:

PUT _template/template_nginx_log
{
"index_patterns": ["php-nginx-log*"],
"settings": {
"number_of_shards": "5",
"number_of_replicas": "1"
},
"aliases": {
"php-nginx-log": {}
},
"mapping": {
"doc": {
"properties": {
"@timestamp": {

"type": "date"
},
"geoip": {
"type": "object"
},
"geoip_city_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"geoip_continent_code": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"geoip_country_code2": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},

"user_device_os_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}

具体说明:

  • index_patterns:指定index匹配表达式,这个特性十分重要,如果配置为 ”php-nginx-log*“,则所有以php-nginx-log为前缀的索引都将自动使用该template进行索引创建,而不需要特殊指定
  • aliases:为索引指定一个别名,同样的,通过该配置就能实现我们前面提到的问题,让按照日期创建的新index能够被正确的查询到

CASE4:原index数据迁移(mapping有修改)

1)CASE3开头的时候提到过,需要按照固定的mapping创建index,来达到生成的index能使用规范的数据类型的目的,而历史index中数据想要修改mapping只能重新创建,这时我们通常使用Elasticsearch的reindex特性:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/docs-reindex.html

POST _reindex?slices=5&refresh
{
"source": {
"index": "php-nginx-log-2019.01",
"size": 10000
},
"dest": {
"index": "php-nginx-log-2019.01.15"
}

}

说明:

  • 默认情况下,_reindex使用1000进行批量操作,您可以在source中调整batch_size,如上面设置为了1万
  • Reindex支持Sliced Scroll以并行化重建索引过程。 这种并行化可以提高效率,并提供一种方便的方法将请求分解为更小的部分,如上面设置为了slices=5
  • 1)slices大小的设置可以手动指定,或者设置slices设置为auto,auto的含义是:针对单索引,slices大小=分片数;针对多索引,slices=分片的最小值。

  • 2)当slices的数量等于索引中的分片数量时,查询性能最高效。slices大小大于分片数,非但不会提升效率,反而会增加开销。

  • 3)如果这个slices数字很大(例如500),建议选择一个较低的数字,因为过大的slices 会影响性能。
  • 如果要进行大量批量导入,请考虑通过设置index.number_of_replicas来禁用副本:0。
  • 主要原因在于:复制文档时,将整个文档发送到副本节点,并逐字重复索引过程。这意味着每个副本都将执行分析,索引和潜在合并过程。

  • 相反,如果使用零副本进行索引,然后在提取完成时启用副本,则恢复过程本质上是逐字节的网络传输。 这比复制索引过程更有效。

2)我们要保证新旧index的数据平滑迁移对用户无感知,此时可以使用前文提到的alias,流程为:

1 . 就index使用alias,数据使用方通过alias查询数据

2 . reindex生成的新index不要创建别名,进行数据reindex操作

3 . 待数据复制完成后,调用remove+add alias接口,该操作为原子操作,可以保证数据无缝迁移,具体代码如下:https://www.elastic.co/guide/en/elasticsearch/reference/6.5/indices-aliases.html

POST /_aliases
{
"actions" : [
{ "remove" : { "index" : "test1", "alias" : "alias1" } },
{ "add" : { "index" : "test2", "alias" : "alias1" } }
]
}

总结

至此我们就总结完了一些Elasticsearch及ELK架构下常用CASE,通过合理的使用组件的特性,来满足我们的业务需求。

后面我们还将总结一些Logstash的经典CASE。


欢迎关注 高广超的简书博客 与 收藏文章 !


分享到:


相關文章: