业务侧的数据类型是uint64位,通过filebeat传输到logstash,然后输出到elasticsearch。运营QA等人员在kibana上查数据发现会有丢失查不到的情况发现es的日志有大量的报错如下:
Caused by: com.fasterxml.jackson.core.JsonParseException: Numeric value (18446744073709551615) out of range of long (-9223372036854775808 - 9223372036854775807)
和开发确认相关字段长度是uint64,但是es索引使用默认mapping的数据类型是long,导致业务数据id长度超过了mapping的字段长度没法储存。 解决方案
需要修改索引的mapping字段类型,但是es的索引一旦建立就不能修改了,只能重建索引和迁移数据搭建测试环境,还原现有索引和mapping docker 部署ELK(7.5.1),还原线上报错
安装elasticsearch
docker pull elasticsearch:7.5.1 docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 -v /data/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /data/es/data:/usr/share/elasticsearch/data --name ES 2bd69c322e98
其中es的配置如下
cat elasticsearch.yml |grep -v '^$' |grep -v '^#' path.data: /data/es/data path.logs: /data/es/log xpack.security.enabled: true indices.query.bool.max_clause_count: 4096 indices.fielddata.cache.size: 10% indices.breaker.fielddata.limit: 50% indices.breaker.request.limit: 50% xpack.monitoring.collection.enabled: true
安装kibana
docker pull kibana:7.5.1 docker run -d --name=kibana --link 0d1b2dfb511f:elasticsearch -p 5601:5601 kibana:7.5.1 #docker run --link可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。 #0d1b2dfb511f是es的容器id #elasticsearch是给es取得name #如果kibana中的配置有修改的,可以通过docker exec -it kibana /bin/bash进入容器修改完成,重启kibana
其中kibana的配置如下
cat kibana.yml |grep -v '^$' |grep -v '^#' server.name: kibana server.host: "0" elasticsearch.hosts: [ "http://localhost:9200" ] xpack.monitoring.ui.container.elasticsearch.enabled: true i18n.locale: "zh-CN"
安装logstash
docker pull logstash:7.5.1 docker run -p 5044:5044 --name logstash --link 0d1b2dfb511f:elasticsearch -d docker.elastic.co/logstash/logstash:7.5.1
其中logstash的配置如下
logstash.yml http.host: "0.0.0.0" xpack.monitoring.elasticsearch.hosts: [ "http://ES所在机器的IP:9200" ]
pipeline的配置如下
pipeline/logstash.conf
input {
beats {
port => "5044"
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => ["ES机器IP:9200"]
index => "ES索引名"
}
}
安装完ELK后,可以通过kibana界面进行配置和操作了
#考虑到要复现问题,先设置es的日志级别到debug
PUT /_cluster/settings
{
"transient":{
"logger._root":"DEBUG"
}
}
PUT test #创建索引
GET test/_settings #查看索引配置
PUT test/_settings #配置索引参数
{
"index.mapping.total_fields.limit":10000
}
POST /test/_mapping #提交索引映射,这个mapping是从正式环境copy来的,由于mapping很长,就截取关键部分(数据字段不匹配的部分)
{
"properties" : {
"@timestamp" : {
"type" : "date"
},
"@version" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"agent" : {
"properties" : {
"ephemeral_id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"test_user_id" : {
"type" : "long"
},
"test_id" : {
"type" : "long"
},
"tags" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"ts" : {
"type" : "float"
}
}
}
GET /test/_mapping #查看映射
去产生日志的业务机器起一个filebeat,向logstash发送日志文件,filebeat配置如下图(output中的hosts就是logstash的ip)
配置完成之后,logstash中的pipeline的output,修改index,然后进行重启,这样可以接收到日志数据了。这些做完后在ES中查看到和正式环境一样的报错了,字段长度超出mapping的long类型,如下
测试环境解决问题
新建索引,mapping字段类型修改,从long改为double(容纳的数据更长)
PUT test02 #创建索引
GET test02/_settings #查看索引配置
PUT test02/_settings #配置索引参数
{
"index.mapping.total_fields.limit":10000
}
POST /test02/_mapping #提交索引映射,这个mapping是从正式环境copy来的,由于mapping很长,就截取关键部分(数据字段不匹配的部分)
{
"properties" : {
"@timestamp" : {
"type" : "date"
},
"@version" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"agent" : {
"properties" : {
"ephemeral_id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"test_user_id" : {
"type" : "double"
},
"test_id" : {
"type" : "double"
},
"tags" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"ts" : {
"type" : "float"
}
}
}
GET /test02/_mapping #查看映射
数据迁移,从旧索引迁移到新索引(最好停掉log进行迁移)
POST _reindex
{
"source": {"index": "test"},
"dest": {"index": "test02"}
}
等待迁移完成,然后logstash中的pipeline修改output,把index从test改为test02,重启logstash
input {
beats {
port => "5044"
}
}
filter {
json {
source => "message"
}
}
output {
elasticsearch {
hosts => ["ES的ip:9200"]
index => "test02"
}
}
可以在kibana中查看有文档数了
kibana的setting中创建对应的索引
在Discover中查询对应的数据,发现可以查到id为18446744073709551615这么大的结果了
ES相关概念
集群(cluster)
代表一个集群,集群中有多个节点(node),其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。 索引(index)
ElasticSearch将它的数据存储在一个或多个索引(index)中。用SQL领域的术语来类比,索引就像数据库,可以向索引写入文档或者从索引中读取文档,并通过ElasticSearch内部使用Lucene将数据写入索引或从索引中检索数据。 文档(document)
文档(document)是ElasticSearch中的主要实体。对所有使用ElasticSearch的案例来说,他们最终都可以归结为对文档的搜索。文档由字段构成。比如每一条商品信息,就是一个文档。 映射(mapping)
所有文档写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤,这种行为叫做映射(mapping)。一般由用户自己定义规则。字段的数据类型、属性、是否索引、是否存储等特性。 类型(type)
每个文档都有与之对应的类型(type)定义。这允许用户在一个索引中存储多种文档类型,并为不同文档提供类型提供不同的映射。类型是模拟mysql中的table概念,一个索引库下可以有不同类型的索引,比如商品索引,订单索引,其数据格式不同。不过这会导致索引库混乱,因此未来版本中会移除这个概念。 分片(shards)
代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。5.X默认不能通过配置文件定义分片。 副本(replicas)
代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当个某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。



