近期一直在负责es这块,就想着和大家分享一些使用经验,我们从存储、查询、优化、备份、运维等几个方面来做分享。今天咱们先看下如何更加合理的存储数据。
记得刚接触es还是18年那会,项目上线后因一些原因导致日志这部分的开发未完成,导致日志这块只能通过linux命令查询,及其不方便。
于是老大让我自己搞定这块,当时是由兄弟团队负责开发这块,所以我们的日志都只是写到了日志文件上,项目刚上线各种问题还经常需要通过日志查询,瞬间涌上心头,于是先搞个脚本把各个服务日志定时搜集到一台服务器上,避免丢失。
接下来一路趟坑便就开始了,为了快速搞起来,优先百度各种方案,提到最多的就是elk这个词,于是按照网上的方案快速搭建起来了。
但是那会只是换了方式查询,通过kibana各种维度查询,语法边百度边查询,随着时间推移日志量越来越大,慢慢的查询性能大大降低,一但出了事自己也不知道怎么运维es。
于是痛下决心开始学习官网文档,全方位了解es。首先发现存储就不对,各个字段几乎都是text格式,大大浪费了磁盘空间。于是首个模板就这么出来了。我们展示其中一段:
"properties":{
"id":{
"type":"keyword"
},
"relativeJobId":{
"type":"keyword"
},
"reqDate":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"operDate":{
"type":"date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"title":{
"type":"text",
"norms": false
}
}
建立好模板后再晚上业务低峰期对索引逐个进行reindex操作后发现查询能力大大提升,磁盘空间也下降很多。
但是运行一段时间后问题出来了,我们需要扩展日志字段,并且是精确匹配,那该怎么办呢?我们可以通过动态模板的方式实现,我们看下索引模板变成了这样:
"properties":{
"id":{
"type":"keyword"
},
"relativeJobId":{
"type":"keyword"
},
"reqDate":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"operDate":{
"type":"date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"title":{
"type":"text",
"norms": false
}
},
"dynamic_templates": [
{
"longs": {
"match_mapping_type": "long",
"mapping": {
"type": "long"
}
}
},
{
"boolean": {
"match_mapping_type": "boolean",
"mapping": {
"type": "boolean"
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
},{
"date": {
"match_mapping_type": "date",
"mapping": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
]
}
这样一来如果新增的字段是String类型,es就会采用keyword的方式进行存储,如果是时间字段就会按照这种格式存储等等。
看似一切都解决了,但是运行一段时间后发现我们又需要增加支持模糊查询的字段,这又改怎么办呢?于是我们的索引模板就发展成了这样:
"properties":{
"id":{
"type":"keyword"
},
"relativeJobId":{
"type":"keyword"
},
"reqDate":{
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"operDate":{
"type":"date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"title":{
"type":"text",
"norms": false
}
},
"dynamic_templates": [
{
"longs": {
"match_mapping_type": "long",
"mapping": {
"type": "long"
}
}
},
{
"boolean": {
"match_mapping_type": "boolean",
"mapping": {
"type": "boolean"
}
}
},
{
"strings_as_text": {
"match_mapping_type": "string",
"match": "text_*",
"mapping": {
"type": "text",
"norms": false
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
},{
"date": {
"match_mapping_type": "date",
"mapping": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
]
}
如果是test—开头的字段并且是String类型,es就会采用text的方式进行存储,我们可以看到有个norms的属性,我们设置了false,它是啥意思呢?我们细心点可以发现通过query查询的时候你会发现结果集中每条数据都有会有个相关度分数,这个不仅会消耗cpu还会占用一定的磁盘性能,如果我们不需要根据相关度分数进行高亮或者排序之类的,完全可以把这部分给屏蔽掉,节省磁盘空间。
其实我们还可以通过ignore_above的方式设置字段一旦超过多大后就不再支持搜索,比如你的字段是一段1mb的String字符串用它来做匹配就太过消耗性能了(单说filter查询时会通过bitset缓存,此项就会大大降低性能。),完全可以通过其附属字段进行匹配。
通过上述模板升级后,我们的模板就已经足够支持各种变化了,也就不用担心动态增加字段的问题了
要想深入了解一个技术还是官方文档啊,毕竟只有官方最了解自己的产品。希望接下来一段时间我们一起跟着官方文档深入学习es。