本文主要介绍了Elasticsearch的索引优化和索引的settings、mappings,而且举例说明了在什么场景下应该使用什么参数来实现更细致的优化。
上篇文章回顾: Mac OS下用Homebrew安装本身写的开源工具
Elasticsearch(下面简称ES)自己的搜索性能已经很是优秀,默认参数也适用于大部分场景;但为了更高效地利用计算资源,或者防止出现一个请求消耗掉集群全部的资源状况,咱们会对一些参数进行调优和限制。node
有关于集群级别的优化,网上已经有不少相关的文章能够借鉴,而索引级别的优化则相对较少。ES的集群优化一般是通用性的优化,而索引优化则更加贴近于业务,更有针对性。本文主要将介绍索引的settings、mappings,举例说明什么场景下使用什么参数来实现更细致的优化。算法
经常使用的参数,默认使用LZ4压缩算法,优势是压缩速度很是快,对于写入速度要求比较高,有充裕的存储空间和读写速度的存储介质的场景使用。
将该设置改成best_compression可以使用DEFLATE算法来得到更高的压缩率,但会使用更多的CPU资源和时间来压缩/解压。一般都将该参数设为best_compression,除非写入时CPU成为瓶颈。
该设置可在索引建立时或者处于Close状态的索引上指定,新的压缩算法将在下一次merge后生效。bash
另外一个经常使用的参数,增长索引分片数可提升搜索的并发度。当一个Query分发到不一样分片上时,ES会将充分利用多核心CPU的优点,每一个分片使用不一样的核心来处理搜索请求;一般来讲,分配到一个节点上的主副分片之和等于CPU核心数将得到最大的CPU利用率和最短的搜索耗时。但分片数过多也会在合并搜索结果时带来额外的计算量,同时若其余的索引也在进行搜索的会形成上下文切换,所以搜索耗时不会随着分片数增加而线性减小。并发
在知足搜索延迟的前提下,设置最小的分片数是最佳的选择(暂时不考虑分片大小)。app
也一个经常使用的参数,用于调整写入时的刷新间隔,刷新(refresh)既是将内存中的数据写到文件系统缓冲中;写入的数据在刷新后才能被搜索,这也是ES被称为近实时搜索的缘由。其本质是Segment的生成间隔。增大刷新间隔能够减小Segment的生成,同时也能减小搜索耗时。一般将该值设为"30s",对实时性要求较高的索引可适当减小刷新间隔。运维
由于Segment没法作到实时生成,若是在两次refresh间隔中节点宕掉,会致使数据丢失。Translog的存在则是为了解决这个问题。Translog中记录了每一次对ES的操做,默认是每一个请求(bulk, delete, upadte, etc)完成后,或者达到同步间隔(sync_interval,默认5s)都会将日志持久化(fsync)到磁盘中,当主副分片都确认持久化完成后,客户端才会受到请求成功的响应;若节点出现异常,能够重放translog中在最后一次刷新后发生的变动操做来恢复数据。
可是每次执行fsync会带来少量的性能损失,若能够接受几秒钟的数据损失,能够将该参数设为"async",使用异步fsync来减少translog带来的影响。异步
当某个节点离线后,默认状况下1m后就会执行重建副本。当咱们预知短期内离线的节点可以从新加入集群,能够延长重建副本的延时,来避免没必要要的分片拷贝。
可以使用PUT /_all/_settings来对集群中现有的全部索引应用该参数,该参数值视节点重启的时间而定,一般可设为"5m"。async
ES默认会使用max(1, min(4, CPU核心数 / 2))的线程数来进行merge操做,这会下降机械硬盘的读写效率,若是索引保存在机械硬盘上,可将该值固定为"1"。工具
动态映射一方面下降了用户的使用成本,另外一方面也对集群管理形成了不便——因为不规范的稀疏的数据致使索引中的字段数大幅增加而影响搜索性能。若是对一份数据规范性要求比较高,能够经过将该参数设为"false"来关闭自动生成字段映射的特性。性能
以咱们线上使用的经验来看,ES5.x(6.x的状况有待观察)的分片分配机制不够完善。当某个节点新加入集群的时候,会优先把大索引的分片和当天正在写入的索引的大部分分片分配到该节点上,致使该节点的负载飙高。经过设置该参数可限制索引在该节点上的最大分片数,必定程度上避免这种状况的发生。
可是这个参数不能恰好设置为( pri_shard_num + rep_shard_num) / data_node_num,若是刚好设置成这个值,可能会出现最后一个分配的副本和主分片在同一节点上,致使分配不上去。
若您大部分的搜索请求是基于必定顺序取TopN,例如看最近的10条日志,耗时最长的100个请求,或者交易最频繁的5个用户等等,ES默认状况下会扫描所有数据后在返回结果。在ES6.x中加入了一个特性,可以大幅下降这类搜索的耗时:Index Sorting。若启用该特性,ES在写入时候就会按照必定顺序排列数据,例如按时间倒叙,这样在搜索的时候就不要扫描全量数据,只要得到每一个Segment前TopN的数据便可返回结果。该特性须要在索引建立的时候启用,方法以下:
PUT log
{ "settings" : {
"index" : {
"sort.field" : "timestamp",
"sort.order" : "desc"
}
},
...
}复制代码
注意,启用该特性会下降写入速度,所以须要在写入和搜索之间进行权衡。
ES之因此具备不须要事先定义schema是由于dynamic mapping功能的存在,它大大下降了用户使用成本。
默认ES对字符串类型的字段会自动映射成text类型,同时再生成一个名为字段名.keyword的keyword类型的子字段。若大部分字段不须要对字段进行分词,可将默认的字符串类型映射为keyword来下降写入时的额外资源开销:
"mappings": {
"doc": {
"dynamic_templates": [
{ "strings_as_keywords": {
"match_mapping_type": "string",
"mapping": { "type": "keyword" }
}
}
]
}
}复制代码
效果同索引级别的"mapper.dynamic",可针对某个字段或者整个Type设置,经过将该参数设为"false"来关闭自动生成字段的特性,新添加的字段将被忽略;或者设为"strict",若是遇到新字段抛出异常。
对于keyword类型的字段,若是咱们只须要对该字段进行搜索,不须要进行聚合、排序或是使用脚本操做,能够将doc_value设为false,可大幅降节省磁盘空间,必定程度上提高索引速度。
若是咱们只须要对某个字段进行聚合、排序或是使用脚本操做,不须要搜索该字段(一般是keyword或者numeric类型的字段),能够将index设为false,可释放该字段倒排索引占用的常驻内存。
索引的倒排索引占用的内存可经过GET /<INDEX_NAME>/_stats?human=true中的segments.terms_memory查看。
norms参数对搜索评分颇有用,若咱们不须要计算字段的评分,将该参数设为false,特别是该字段仅用于过滤或聚合。若索引中存在某个字段启用了norms,不管文档中是否存在该字段,全部文档都会占用N bytes(N为文档数)磁盘空间,所以禁用norms能够释放大量的磁盘空间。
norms能够经过如下API禁用,将在生成新的Segment时生效,但不能被从新启用。
PUT my_index/_mapping/_doc
{ "properties": {
"title": {
"type": "text",
"norms": false
}
}
}复制代码
在一些状况下,咱们只须要保存某个字段,经过搜索其余的字段来定位到这条记录查看这个字段的内容,不须要对该字段进行搜索、排序、聚合等操做,能够将该字段的"enabled"设为false,同时节省大量内存和磁盘的空间。
咱们常常碰到一些内容不规范或者格式不对的数据,例如某个IP字段的里出现"UNKNOWN",某个数字字段出现"-"。若是在这些字段上已经设置了明确的类型,好比"ip"或者"float",字段中出现了非该类型的值,ES会抛出异常并丢弃整条数据。
咱们能够在该字段上设置"ignore_malformed": ture来忽略这个字段并保留该文档中的其余字段。
该字段属于索引的元数据,其中存储了文档原始的JSON内容,会被存储但不会被索引,用于执行fetch请求时返回原始数据。
当咱们不须要得到任何原始数据,只须要对数据进行排序,聚合等计算,或者写入时文档id是手动指定的,经过搜索取到文档id来进一步处理,能够将"_source"设为false来节约大量的磁盘空间。
注意,禁用"_source"后会致使没法使用update,update_by_query,reindex等须要获取原始文档的API,也没法使用高亮功能。
一些比较经常使用的针对索引级别的设置就介绍到这里,某些在ES6.x以上的版本已被弃用的参数将再也不赘述。经过灵活地配置参数可将ES的性能发挥到更高的水平。
本文首发于公众号“小米运维”,点击查看原文