注:
- 非原创,个人读书笔记
- 备忘,比纸质书方便查阅
参数类型
从影响范围来可以分为集群级别、索引级别参数等类型。
- 集群级别参数
- cluster.maxs_shards_per_nod前缀是cluster.*,针对集群生效
- indices.query.bool.max_clause_count,需要在elasticsearch.yaml文件中配置,重启方可生效
- 索引级别参数
- index.number_of_shards,前缀是index.*,修改针对索引生效
从灵活性来可以分为动态参数、静态参数。
- 静态参数,如主分片个数index.number_of_shards,索引创建之后不能修改,除非重建索引。
- 动态参数,副本个数index.number_of_replicas,允许任何时候进行动态调整,可以通过update api进行修改。
六个集群参数关键默认值
Boolean类型支持最大子句个数
静态参数:indices.query.bool.max_clause_count,需要在elasticsearch.yaml中配置,默认最大1024,这是为了防止搜索子句过多而占用过多的CPU和内存,导致集群性能下降。
数据节点支持的分片个数
对应参数:cluster.max_shards_per_node,默认最大值为1000(7.0版本后)
该参数适用于大数据量的集群分片选型场景。
首先对于大规模集群,每个节点可以存储的分片数量和可用的堆内存大小之间存在正相关关系。根据ES官方建议,堆内存与分片数量应该维持大约1:20的比例。例如一个拥有30G堆内存的节点,理想情况下应最多分配600个分片。
其次需要注意的是分片的分配必须合理,分片过多会导致写入放大,可能引发批量队列(Bulk Queue)满载,从而增加请求被拒绝的风险。反之,如果处理大量数据时分片过少,那么多节点资源可能无法得到充分利用,进而导致机器资源分布不均衡。因此针对ES集群的优化,需要在分片数配置和机器资源使用之间寻求平衡。
堆内索引缓冲区比例
均为静态参数:
- indices.memory.index_buffer_size默认值10%
- indices.memory.min_index_buffer_size默认值48MB
- indices.memory.max_index_buffer_size
需要在elasticsearch.yaml中配置。
参数适用于在堆内存的索引缓冲区中存储新索引的文档。填满后,缓冲区中的文档将写入磁盘上的某个段。这些参数所设置的缓冲区大小将在节点上的所有分片之间进行划分。
在使用上建议将这些参数在集群中的每个数据节点上进行配置。作为写入优化的首选参数,它们对于提高写入性能和稳定性具有重要作用,因此妥善配置这些参数是提高ES集群效率的关键。
磁盘使用率
均为集群动态参数:
- cluster.routing.allocation.disk.watermark.low默认值85%
- cluster.routing.allocation.disk.watermark.high默认值90%
- cluster.routing.allocation.disk.watermark.flood_stage默认值95%
这些参数可用于基于磁盘分配分片时控制磁盘使用率低警戒水位线。
使用上提供如下建议:当磁盘占用达到85%时,应考虑禁止新的写入操作,以防止磁盘过载;若磁盘占用进一步达到90%,则应将索引分片迁移到其他可用节点,以优化资源分配并防止节点失败;如果磁盘占用高达95%,则应将索引设置为只读,以防止可能的数据丢失或损坏。
GC方式
默认参数:
- -XX:+UseConcMarkSweepGC
- -XX:+CMSInitiatingOccupancyFraction=75
- -XX:+UseCMSInitiatingOccupancyOnly
适用于需精细化控制Java内存管理和垃圾回收的场景。
在ES使用中,GC的选择对集群性能具有显著影响。虽然官方建议CMS作为大多数部署的首选,但自6.5.0版本开始,在JDK11或者更高版本上运行同时支持G1垃圾收集器。
配置GC选项需在jvm.options文件中进行。提供一个参考性的配置优化建议:
-XX:+UseG1GC
-XX:MaxGcPauseMillis = 50
其中-XX:MaxGcPauseMillis用于控制预期最大GC停顿时间,默认200ms,若业务对停顿十分敏感可以适当降低此值,但需注意,设置过小可能会导致CPU消耗增加。
优化G1的停顿时间在集群正常运行时,可以有效减少时延。然而,如果是由于GC问题导致的集群卡顿,那么仅仅更换G1可能无法彻底解决,此时还可能需要对集群的数据模型或查询进行优化。
笔者注:G1收集器的停顿预测模型是以衰减均值(DecayingAverage)为理论基础来实现的,MaxGCPauseMillis参数指定的停顿时间只意味着垃圾收集发生之前的期望值。
设置不同的期望停顿时间,使得G1在不同应用场景中取得关注吞吐量和关注延迟之间的最佳平衡。不过,这里设置的"期望值"必须是符合实际的,不能异想天开,毕竟G1是要冻结用户线程来复制对象的,这个停顿时间再怎么低也得有个限度。它默认的停顿目标为两百毫秒,一般来说,回收阶段占到几十到一百甚至接近两百毫秒都很正常,但如果我们把停顿时间调得非常低,譬如设置为二十毫秒,很可能出现的结果就是由于停顿目标时间太短,导致每次选出来的回收集只占堆内存很小的一部分,收集器收集的速度逐渐跟不上分配器分配的速度,导致垃圾慢慢堆积。
与CMS中的"Concurrent Mode Failure"失败会导致FullGC类似,如果内存回收的速度赶不上内存分配的速度,G1收集器也要被迫冻结用户线程执行,导致Full GC而产生长时间"Stop The World",得不偿失。
七个索引级别的关键参数
主分片大小
静态参数:index.number_of_shards,默认值为1(从ES7.x版本开始,早期默认为5);单索引支持的最大分片数为1024。
使用ES时,一些关键参数设置对保证集群的稳定性和性能具有重要意义。例如,索引的最大分片数在创建索引就应确认,并且一旦设定无法更改。默认1024的最大分片个数是一种安全限制,旨在防止过度分配资源导致集群稳定性受损。尽管这是一个安全措施,但必要情况下,用户可以打破该限制,具体方法就是在每个节点上指定export ES_JAVA_OPTS="-Des.index.max.number_of_shards=128"。这一操作必须谨慎,过度分片可能导致资源消耗过大,影响集群性能。
压缩算法
静态参数:index.codec,默认值为LZ4,用于数据写入压缩。
使用哪种压缩算法需要权衡压缩率和性能,LZ4是比较均衡的存在。如果存储空间成本较高可以考虑更换为best_compression,该设置使用DEFLATE算法以实现更高的压缩比,因为需要更多的CPU资源来压缩和解压数据,因此最适合那些对磁盘空间优化有较高要求,而对性能影响相对较少关注的场景
副本分片个数
动态参数:index.number_of_replicas,默认值为1,该参数确保业务数据的可用性。 建议根据业务需求来合理设置副本。基于数据安全性考虑,建议副本至少设置为1。
刷新频率
动态参数:index.refresh_interval,默认最小值为1s,控制数据写入到可以搜索最小时间间隔。对于实时性要求不高且想要优化写入的业务场景,建议根据实际情况调大。
笔者注:本人实践中得到的经验是,默认值就是绝大场景下最合适的值,不用修改。
terms支持最大长度
动态参数:index.max_terms_count,默认值为65536,实际使用一般不超过此值,大多数场景都相距甚远,笔者的职业生涯中只见过美团的搜索业务达到这个量级。
返回的最大结果数
动态参数:index.max_result_windows,默认值10000。
该参数与深度分页相关。分页机制就决定了越往后越慢,所以除非有不得已的理由,不建议修改此值,参考Google和百度的搜索,试试可不可以从产品的角度绕过这种需求。对于全部数据遍历,推荐使用scroll api ,针对仅向后翻页则推荐search_after api。
预处理管道
动态参数:index.default_pipeline,默认自定义管道。
某些场景,索引写入需要进行额外的预处理步骤,例如字段标准化、数据的清洗和转化等,这些预处理步骤统称为ETL操作,索引默认管道对需要ETL的场景具有重要作用。
四个Mapping级别关键参数
支持的最大字段数
动态参数:index.mapping.total_fields.limit,默认最大值1000,不建议修改。该参数可防止用户无意中或恶意地创建过多字段,导致映射爆炸(mapping explosion),进而影响集群的性能和稳定性。
Mapping字段默认的最大深度
动态参数:index.mapping.depth.limit,默认最大值为20,不建议修改。它的主要作用是防止用户定义过于复杂的嵌套结构,从而避免映射过于复杂、元数据膨胀以及可能引发的性能问题。
笔者的个人经验是三层足够了。
Nested类型相关
均为动态参数:
- index.mapping.mested_fields.limit表示一个索引时所支持的最大Nested类型个数,默认值为50
- index.mapping.mested_objexts.limit表示一个Nested类型所支持的最大对象数,默认值为10000
两个参数适用于Nested类型。Nested类型潜在的性能问题不容小觑。Nested本质是每个嵌套对象都被索引为一个单独的Lucene文档。如果为包含100个对象的单个文档建立索引,则将创建101个Lucene文档。此外Nested与Join类型父子文档不同,如果子文档更新频繁则建议使用父子文档,如果子文档更新不频繁,查询频繁则建议采用Nested类型。
动态映射下匹配字符串类型
字符串类型默认为"text + keyword"类型,适用于不提前设置Mapping精准字段的场景。建议结合业务场景,提前精准设置Mapping并优化数据建模。
四个其他关键参数
评分机制
默认BM25,除非业务需要,通常不建议修改。
ES Keyword类型支持的字符数
ES 5.x版本后,Keyword类型支持的最大长度为32766个UTF-8字符,text类型没有限制。设置ignore_above后,超过给定长度的数据将不被索引,无法通过term检索返回结果。
节点角色属性
对候选主节点,数据节点,ingest节点,协调节点,机器学习节点等角色,达到一定规模后,一定要设置专有的主节点,协调节点,数据节点,使得角色划分清晰,各司其职。
ES堆内存大小
ES 8.x版本默认的堆内存大小是4GB,若修改此值一定要结合实际硬件能力,并且建议独立部署,不与Logstash,Haddoop,Redis等服务共享资源,以及建议将JVM设置为机器内存的一半大小,但不建议超过32G(也有文章指出是30.5G)。 A Heap of Trouble: Managing Elasticsearch's Managed Heap Heap: Sizing and Swapping