0x01 前言

我最近重建某些服务的时候遇到日志格式发生了变化,某些字段的type也做了修改,这时候需要将以前的索引进行reindex操作。

我刚开始配置elasticsearch的时候并没有设定别名,这里会带来一个问题:当我将索引A的数据reindex到索引B时,logstash依旧会将数据发送到索引A。

对于reindex的操作,可以参考以下文章:

如果想将数据发送到索引B,就需要修改logstash的output配置并且重启服务。这里又会有一个问题:我收集的所有日志都依赖logstash并且只有一个logstash节点在接收。一旦重启logstash服务就会有一小部分的日志丢失。

当然,这些都是我在家里测试用的服务,丢失一点点日志并不会造成任何损失。如果这是发生在生产环境中呢?这肯定是不可接受的。

0x02 别名

为了提高elasticsearch的可用性,建立一个index的别名是必不可少的。在elasticstack 6.x的文档里关于索引别名的文档连接如下:

索引别名就是一个映射关系,可以是一个索引映射到这个别名,也可以多个索引一起映射到一个别名,如:

{
  "actions": [
    {
      "add": {
        "alias": "alias1",
        "index": "test1"
      }
    },
    {
      "add": {
        "alias": "alias1",
        "index": "test2"
      }
    }
  ]
}

如果在外部通过API写入数据到别名alias1中,那么这些数据将会同时存放在两个索引中。

通过别名也可以很好地解决我已开始所说的reindex问题。我会在一开始就建立以下映射关系:

{
  "actions": [
    {
      "add": {
        "alias": "public-ngx-alias",
        "index": "public-nginx-main-v1"
      }
    }
  ]
}

而logstash的ouput如下:

output {
  if "server_ngx_access_log" in [tags] {
    elasticsearch {
      hosts => ["es6-node1.t.com:9200", "es6-node2.t.com:9200", "es6-node3.t.com:9200"]
      manage_template => false
      index => "public-ngx-alias"
    }
  }
}

如果某天我日志的格式发生了变化,同时某些字段的类型也发生了变化,我只需要新建一个index:

curl -XPUT 'es6-node1.t.com:9200/public-nginx-main-v2?pretty'

然后将旧的index从别名中移除,同时将新的index映射到别名中:

curl -XPOST 'es6-node1.t.com:9200/_aliases?pretty' -H 'Content-Type: application/json' -d'
{
    "actions" : [
        { "remove" : { "index" : "public-nginx-main-v1", "alias" : "public-ngx-alias" } },
        { "add" : { "index" : "public-nginx-main-v2", "alias" : "public-ngx-alias" } }
    ]
}
'

这样就可以实现elasticsearch数据的读写实现无缝对接。成功切换index后就可以进行reindex的操作:

curl -XPOST 'es6-node1.t.com:9200/_reindex?pretty' -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "public-nginx-main-v1"
  },
  "dest": {
    "index": "public-nginx-main-v2"
  }
}
'

当然,在kibana中也需要将别名添加到index pattern中,而不是实际的index名称:

别名还提供了其他更多的高级功能,具体请参考官方文档。

0x03 其他

还有一点需要注意的,elasticsearch的索引模板匹配规则请不要匹配上别名的名称。例如我nginx日志在elasticsearch中的索引模板如下:

{
  "public_nginx": {
    "order": 0,
    "index_patterns": [
      "public-nginx-*"
    ],
    "settings": {
      "index": {
        "number_of_shards": "5"
      }
    },
    "mappings": {
      "doc": {
        "properties": {
          "bytes": {
            "type": "long"
          },
          "client_ip": {
            "type": "ip"
          },
          "geoip": {
            "dynamic": true,
            "properties": {
              "location": {
                "type": "geo_point"
              }
            },
            "type": "object"
          },
          "request_time": {
            "type": "float"
          },
          "upstream_response_time": {
            "type": "float"
          }
        }
      }
    },
    "aliases": {}
  }
}

index_patterns字段为匹配规则,匹配一切传入public-nginx-*索引的数据,其中就包含public-nginx-main-v1与public-nginx-main-v2这两个索引,但不匹配public-ngx-alias这个别名名称。

如果把别名也匹配上,那么就算你怎样reindex也无法调整旧数据的字段类型。

请不要给别名设置索引模板,所有操作都在索引上操作即可。

0x04 结语

别名的操作起来并不复杂,只是reindex倒腾数据很耗时间而已。