书籍学习-一本书讲透Elasticsearch:原理、进阶和工程实践(三)

本文是个人学习书籍《一本书讲透Elasticsearch:原理、进阶和工程实践》过程中所记录的一些笔记,内容来源于书籍

Elasticsearch集群

  • 冷热集群架构

    • 热节点存储用户最为关注的数据,而温或冷节点则用于存放用户不太重要或优先级较低的数据

    • 可以提高查询性能、降低存储成本、优化集群性能、更好地管理数据和提高可扩展性

  • 索引生命周期管理

    • Rollover:滚动索引

      • 创建符合正则表达式规范(即中间是“-”字符并且后面是数字字符)的索引,并批量导入数据

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        
        PUT my-index-20240528-000001
        {
        "aliases": {
        	"my-alias": {
        	"is_write_index": true
        	}
        }
        }
        
        PUT my-alias/_bulk
        {"index": {"_id": 1}}
        {"title": "testing 01"}
        {"index": {"_id": 2}}
        {"title": "testing 02"}
        {"index": {"_id": 3}}
        {"title": "testing 03"}
        {"index": {"_id": 4}}
        {"title": "testing 04"}
        {"index": {"_id": 5}}
        {"title": "testing 05"}
        
      • 基于滚动条件配置实现索引的滚动

        • max_age:在索引层面,指从索引创建开始所经过的时间

        • max_docs:在索引层面,指最大文档数(不含副本分片中的文档)

        • max_size:在索引层面,指索引中所有分片的总存储空间(不含副本)

        • max_primary_shard_size:在分片层面,指索引中最大主分片的存储空间

        • max_primary_shard_docs:在分片层面,指索引中最大主分片的文档数

          1
          2
          3
          4
          5
          6
          7
          8
          
          POST my-alias/_rollover
          {
          "conditions": {
          	"max_age": "7d",
          	"max_docs": 5,
          	"max_size": "5gb"
          }
          }
          
    • Shrink:压缩索引

      • 3个必要条件

        • 副本数为0(”index.number_of_replicas”: 0)

        • 将分片数据都集中到一个独立的节点(”index.routing.allocation.include._tier_preference”: “data_hot”)

        • 索引数据只读(”index.blocks.write“: true)

    • 索引生命周期

      • 热(Hot)阶段

      • 温(Warm)阶段

      • 冷(Cold)阶段

      • 归档(Frozen)阶段

      • 删除(Delete)阶段

    • DSL命令行实战步骤

      • 创建生命周期policy

      • 创建索引模板,在模板中关联policy和别名

      • 创建符合模板的起始索引,并插入数据

      • 索引基于配置的ILM滚动

      • 验证结果是否达到预期

  • 跨机房、跨机架部署

    • 设置节点属性

      1
      2
      3
      4
      
      # 节点1设置
      node.attr.rack_id: rack_01
      # 节点2设置
      node.attr.rack_id: rack_02
      
    • 设置集群层面的分片分配策略

      1
      2
      3
      4
      5
      6
      7
      
      PUT _cluster/settings
      {
      	"persisent": {
      		"cluster.routing.allocation.awareness.attributes": "rack_id",
      		"cluster.routing.allocation.awareness.force.rack_id.values": "rack_01,rack_02"
      	}
      }
      
  • 索引/集群的备份与恢复

    • 常见方案

      • 使用Elasticsearch的快照和恢复功能进行备份和恢复。该方案适用于集群整体备份与迁移,包括全量、增量备份和恢复

      • 通过reindex操作在集群内或跨集群同步数据。该方案适用于相同集群但不同索引层面的迁移,或者跨集群的索引迁移

      • 使用elasticdump来迁移映射和数据。该方案适用于仅对索引层面进行数据或映射的迁移

    • Elasticsearch快照和恢复功能

      • 快照执行步骤

        • 配置快照存储路径

          1
          
          path.repo: ["path"]
          
        • 注册快照存储库

          1
          2
          3
          4
          5
          6
          7
          
          PUT /_snapshot/my_backup
          {
          	"type": "fs",
          	"settings": {
          		"location": "path"
          	}
          }
          
        • 拍摄快照

           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
          11
          12
          13
          
          # 集群快照
          PUT /_snapshot/my_backup/snapshot_cluster?wait_for_completion=true
          # 索引快照
          PUT /_snapshot/my_backup/snapshot_hamlet_index?wait_for_completion=true
          {
          	"indices": "hamlet_*",
          	"ignore_unavailable": true,
          	"include_global_state": false,
          	"metadata": {
          		"taken_by": "horin",
          		"taken_because": "backup before restart"
          	}
          }
          
        • 恢复索引快照

          1
          
          POST /_snapshot/my_backup/snapshot_hamlet_index/_restore
          
      • 快照常见操作

        • 查看所有快照库

          1
          
          GET /_snapshot/all
          
        • 查看快照状态

          1
          
          GET /_snapshot/my_backup/snapshot_hamlet_index/_status
          
        • 删除快照

          1
          
          DELETE /_snapshot/my_backup/snapshot_hamlet_index
          
      • 应用场景

        • 数据备份

        • 集群迁移

        • 复制生产数据

        • 数据恢复

        • 高可用性

  • 快照生命周期管理

  • 跨集群检索

Elasticsearch安全

  • 从6.8版本(尤其是7.1及以上版本)开始,Elasticsearch的基础级别安全功能永久免费,在Elasticsearch 8.X版本之后,安全功能不再是可选项,而是必须项

  • Elasticsearch的安全机制

    • 认证和授权:Elasticsearch支持基于用户名和密码的认证及授权机制

    • 传输加密:Elasticsearch可以使用TLS(传输层安全)协议来加密网络传输

    • 数据加密:Elasticsearch支持字段级别的加密(付费功能)

    • 安全插件:Elasticsearch提供了一些安全插件(付费功能)

  • 安全使用Elasticsearch脚本

    • 脚本类型细分

      • stored类型脚本:stored类型的脚本是先定义好脚本,将其存储起来,后续既可以使用,也可以不使用

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        
        	# 定义脚本
        POST _scripts/sum_score_script
        {
        	"script": {
        		"lang": "painless",
        		"source": "ctx._source.total_score = ctx._source.math_score + ctx._source.english_score"
        	}
        }
        # 使用脚本
        POST my_index/_update_by_query
        {
        	"script": {
        		"id": "sum_score_script"
        	},
        	"query": {
        		"match_all": {}
        	}
        }
        
      • inline类型脚本:inline类型脚本就是在使用时直接指定脚本,而不提前创建脚本

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        
        POST my_index/_update_by_query
        {
        	"script": {
        		"lang": "painless",
        		"source": "ctx._source.total_score = ctx._source.math_score + ctx._source.english_score"
        	},
        	"query": {
        		"match_all": {}
        	}
        }
        
    • 脚本限制配置(在elasticsearch.yml中设置)

      • 脚本分级限制(script.allowed_types):默认配置为both,即不做任何限制;将配置修改为inlinestored则表示限制只能执行指定类型的脚本;将配置修改为none,则表示完全禁止执行脚本

      • 脚本可用范围(script.allowed_contexts):默认为none,即不做任务限制;可以配置下选项有下面几种,如果需要同时允许多种选项,则可以用英文逗号进行分隔

        • scoring:计算评分

        • update:更新

        • ingest processor:管道预处理

        • reindex:索引迁移

        • sort:排序

        • metric aggregation map:指标聚合

        • ……

Elasticsearch运维

  • Elasticsearch集群监控的维度及指标

    • 5个重要监控维度

      • 集群健康维度:分片和节点

        • 通过GET _cluster/health监视集群

          • status:集群的状态,其中“红色”是指部分主分片未分配成功,“黄色”是指部分副本分片未分配成功,“绿色”是指所有分片均分配成功

          • active_primary_shards:集群中活动主分片的数量

          • relocating_shards:重定位分片数,指由于节点丢失而移动的分片计数

          • initializing_shards:初始化分片数,指由于添加索引而初始化的分片计数

          • unassigned_shards:未分配的分片数

      • 搜索性能维度:请求率和延迟

        • 通过GET index_a/_stats查看对应目标索引状态

          • query_current:集群当前正在处理的查询操作的计数

          • fetch_current:集群中正在进行的取回操作的计数

          • query_total:集群处理的所有查询的总数

          • query_time_in_millis:所有查询消耗的总时间

          • fetch_total:集群处理的所有取回操作的总数

          • fetch_time_in_millis:所有取回操作消耗的总时间

      • 索引性能维度:刷新和合并时间

        • 通过GET _nodes/stats获取索引性能指标

          • refresh.total:总刷新计数

          • refresh.total_time_in_millis:刷新总时间

          • merges.current_docs:当前的合并文档数

          • merges.total_docs:合并的总文档数

          • merges.total_stopped_time_in_millis:合并操作所消耗的总时间

      • 节点运行状况维度:内存、磁盘和CPU指标

        • 通过GET _cat/nodes?v&h=id,disk.total,disk.used,disk.avail,disk.used_percent,ram.current,ram.percent,ram.max,cpu获取节点运行指标

          • disk.total:存储容量

          • disk.used:存储空间使用量

          • disk.avail:可用存储空间总量

          • disk.used_percent:已使用的存储空间的百分比

          • ram.current:当前内存使用量

          • ram.percent:当前内存使用百分比

          • ram.max:内存总量

          • cpu:CPU使用百分比

      • JVM运行状况维度:GC和堆内存使用率

        • 通过GET /_nodes/stats命令检索JVM度量标准

          • jvm.mem:内存使用情况

          • jvm.threads:当前使用的线程数和最大线程数

          • jvm.gc:垃圾收集相关指标

  • 集群故障排查及修复指南

    • 如何定位红色或黄色的索引

      • 确定我们所能知道的主要问题

      • 确定哪些索引有问题,多少索引有问题

        1
        
        GET _cat/indices?v&health=yellow
        
      • 查看有问题的分片及其原因

        • v:显示表头

        • h:指定要在结果中显示的列

        • s:指定对结果进行排序的列

          1
          
          GET _cat/shards?v&h=n,index,shard,prirep,state,sto,sc,unassigned.reason,unassigned.details&s=sto,index
          
      • 进一步定位未分配的原因

        1
        2
        3
        4
        5
        6
        
        GET _cluster/allocation/explain
        {
        "index": "my_index",
        "shard": 0,
        "primary": false
        }
        
      • 对症下药,解决问题

  • 运维及故障诊断的常用命令

    • 集群节点下线:保证集群颜色绿色的前提下,使某个节点优雅下线

      1
      2
      3
      4
      5
      6
      
      PUT _cluster/settings
      {
      	"transient": {
      		"cluster.routing.allocation.exclude_ip": "127.0.0.1"
      	}
      }
      
    • 强制刷新:刷新索引可以确保当前仅存储在事务日志中的所有数据也永久存储在Lucene索引中

      1
      
      POST _flush
      
    • 更改并发分片的数量以平衡集群:控制在集群范围内有多少并发分片,以达到重新平衡,默认值为2

      1
      2
      3
      4
      5
      6
      
      PUT _cluster/settings
      {
      	"transient": {
      		"cluster.routing.allocation.cluster_concurrent_rebalance": 2
      	}
      }
      
    • 更改每个节点同时恢复的分片数量:如果节点已从集群断开连接,则其所有分片都将变为未分配状态。经过一定的延迟后,分片将被分配到其他位置。每个节点要恢复的并发分片数由该设置确定

      1
      2
      3
      4
      5
      6
      
      PUT _cluster/settings
      {
      	"transient": {
      		"cluster.routing.allocation.node_concurrent_recoveries": 6
      	}
      }
      
    • 调整恢复速度:为了避免集群过载,Elasticsearch限制了恢复速度

      1
      2
      3
      4
      5
      6
      
      PUT _cluster/settings
      {
      	"transient": {
      		"indices.recovery.max_byte_per_sec": "80mb"
      	}
      }
      
    • 清除节点上的缓存:如果节点达到较高的堆内存值,则可以在节点级别上调用如下API以使Elasticsearch清理缓存。这会降低性能,但可以摆脱内存不足引发的OOM的困扰

      1
      
      POST _cache/clear
      
    • 调整断路器:为了避免Elasticsearch OOM,可以调整断路器上的设置。这将限制搜索所占用的内存,并舍弃所有估计消耗内存会超出阈值的搜索请求

      1
      2
      3
      4
      5
      6
      
      PUT _cluster/settings
      {
      	"transient": {
      		"indices.breaker.total.limit": "40%"
      	}
      }
      
    • 集群迁移:集群数据迁移、索引数据迁移等

      • 方案一:针对索引部分或者全部数据执行reindex指令

      • 借助第三方工具(如elasticdump和elasticsearch-migration)迁移索引或者集群,本质上是一种“scroll+bulk”方案的实现

    • 集群数据备份和恢复:对于高可用业务场景,定期增量、全量数据备份

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      
      # 索引快照
      PUT /_snapshot/my_backup/snapshot_hamlet_index?wait_for_completion=true
      {
      	"indices": "hamlet_*",
      	"ignore_unavailable": true,
      	"include_global_state": false,
      	"metadata": {
      		"taken_by": "horin",
      		"taken_because": "backup before restart"
      	}
      }
      # 恢复索引
      POST /_snapshot/my_backup/snapshot_hamlet_index/_restore
      
  • Elasticsearch日志

    • 作用是什么?进行集群状态监测和故障诊断

    • 默认路径是什么?$ES_HOME/logs

    • 基于什么组件实现的?Log4j2

    • 配置文件是什么?log4j2.properties

    • 配置内容主要是什么?命名规范、日志随日期滚动策略(日志大小等条件设置)等

    • 日志的级别如何划分?TRACE→DEBUG→INFO→WARN→ERROR→FATAL

    • 日志级别调整方式有什么?

      • 方式一:支持动态更新,无须重启

        1
        2
        3
        4
        5
        6
        
        PUT _cluster/settings
        {
        	"persistent": {
        		"logger.org.elasticsearch.discovery": "DEBUG"
        	}
        }
        
      • 方式二:elasticsearch.yml配置(静态配置方式,重启后生效)

        1
        
        logger.org.elasticsearch.discovery: DEBUG
        
      • 方式三:log4j2.properties配置(静态配置方式,重启后生效)

        1
        2
        
        logger.discovery.name = org.elasticsearch.discovery
        logger.discovery.level = DEBUG
        
    • slowlog:指慢日志,又可以分为慢检索日志和慢写入日志

Elasticsearch核心工作原理

  • Elasticsearch文档版本冲突(本质:老版本覆盖掉了新版本)

    • 创建场景的版本冲突

      1
      2
      3
      4
      5
      
      # 重复执行create会出现冲突
      POST my_index_1501/_create/1
      {
      "title": "hello"
      }
      
    • 批量更新场景的版本冲突

    • 批量删除场景的版本冲突

  • 如何解决或避免Elasticsearch文档版本冲突

    • 利用external对版本号进行外部控制

      1
      2
      3
      4
      
      POST my_index_1501/_doc/1?version=2&version_type=external
      {
      "title": "hello2"
      }
      
    • 利用if_seq_no和if_primary_term作为唯一标识来避免版本冲突

      1
      2
      3
      4
      5
      6
      7
      8
      
      # 查看_seq_no和_primary_term
      GET my_index_1501/_doc/1
      
      # 基于获取到的_seq_no和_primary_term进行更新
      POST my_index_1501/_doc/1?if_seq_no=2&if_primary_term=1
      {
      "title": "hello2"
      }
      
    • 批量更新和批量删除中通过proceed忽略冲突

      1
      2
      3
      4
      
      POST my_index_1501/_update_by_query?conflicts=proceed
      {
      	...
      }
      
  • Elasticsearch文档更新/删除的原理

    • 更新/删除操作时文档版本号的变化

      • 更新、删除操作实际是在原来文档的版本号基础上加1,且每执行一次,版本号进行一次加1操作

      • 原来老版本的文档被标记为“已删除”状态

    • 文档删除、索引删除和文档更新的本质

      • 文档删除的本质:本质上是逻辑删除而非物理删除,文档被删除时,文档版本+1且标识为“已删除”,等到段合并时才会从磁盘上删除这些文档

        1
        2
        
        # 强制执行段合并,only_expunge_deletes**表示**只清除已标记为“已删除”的文档
        POST my_index/_forcemerge?only_expunge_deletes
        
      • 索引删除的本质:本质上是物理删除,索引删除包含两个步骤:更新集群、将分片从磁盘删除

      • 文档更新的本质:本质上是“delete+add”操作,将旧文档标记为“已删除”,并增加一个全新的文档

  • Elasticsearch写入的原理

    • 核心概念

      • 分段:在Elasticsearch中,段是由一些倒排索引和一些元数据组成的。分段是将索引分成多个小段的过程,每个分段包含一部分索引数据

        1
        
        GET my_index/_segments
        
      • 事务日志文件:一个文档被索引之后,Elasticsearch就会将其添加到内存缓冲区,并且同时写入事务日志文件(translog)中。translog的作用是保证数据的可靠性和一致性

      • 倒排索引是不可变的:已写入磁盘的倒排索引永远不会改变

      • 段是不可变的:段一旦被创建,就不能被修改,任何对索引的更改都会生成新的段

    • 写入的实现流程

      • 客户端向主节点发送写数据请求,主节点充当协调节点的角色

      • 主节点使用文档ID确认文档所属分片,将请求转发到主分片所属的节点

      • 在主分片上面执行写入操作,如果写入成功,将请求并行转发到副本分片上,并向协调节点报告写入成功

      • 协调节点向客户端报告写入结果

    • refresh和flush操作

      • refresh操作

        • 将文档插入Elasticsearch时,文档会被写入内存缓冲区中,然后通过refresh(刷新)操作定期从该缓冲区刷新到内存段中。刷新频率由refresh_interval参数控制,默认1s。

          1
          2
          3
          4
          5
          6
          7
          8
          
          PUT my_index
          {
          	"settings": {
          		"index": {
          			"refresh_interval": "60s"
          		}
          	}
          }
          
        • refresh操作在本质上是将写入数据由内存缓冲区写入内存段中,以保证搜索可见

      • flush操作

        • 当新的文档写入后,写入索引缓冲区(index buffer)的同时会写入事务日志,当flush操作后事务日志才可清空

        • flush操作将文件系统缓存(filesystem cache)写入磁盘,以达到持久化的目的

  • Elasticsearch段合并的原理

    • 段的基础知识

      • 一个集群包含一个或多个节点

      • 一个节点包含一个或多个索引

      • 一个索引由一个或多个分片组成

      • 一个分片对应一个Lucene索引

      • 一个分片包含多个段,每个段是一个倒排索引,查询时会把所有段的查询结果汇总,并将其作为最终分片的查询结果,每个段时磁盘中的单个文件

    • 段合并

      • 将一些大小相似的段合并成更大的段,段合并的时候会将那些旧的已删除文档从文件系统中清除

      • 作用

        • 提高搜索效率:合并后的大段可以减少查询时需要扫描的段的数量,从而提高搜索效率

        • 释放空间:合并后的段可以减少占用的磁盘空间,从而释放空间,减少硬盘的IO开销

        • 优化索引结构:段合并后可以优化索引结构,减少冗余数据,从而进一步提高搜索效率

      • 潜在问题

        • 资源消耗率高:段合并操作需要占用系统资源,例如CPU、内存、磁盘资源等

        • 磁盘碎片增多:段合并操作可能导致磁盘碎片,因为合并后的段可能不是连续的,而是由多个不连续的片段组成的

        • 写入或检索延迟大:如果进行段合并操作时需要合并的段数量过多,可能会导致合并操作的时间较长,从而延迟写入操作和搜索操作

        • 极端情况下索引不可用:如果段合并操作失败或被中断,则可能会导致索引不可用,需要进行恢复操作

      • 段合并问题的优化建议

        • 在非业务密集时间段实施段合并操作

        • 如果对数据的实时性要求并不严格,建议将refresh_interval参数设置为30s或更长

        • 根据CPU核心数量调整index.merge.scheduler.max_thread_count参数

  • Elasticsearch检索的原理

    • 核心步骤

      • 客户端发起请求

      • 在主节点或协调节点中,需要验证查询主体

      • 选择要在查询中使用的索引,根据路由机制选择待检索的分片(主分片或者副本分片)

      • 在数据节点中执行查询操作,以收集精准匹配结果或者满足条件的结果

      • 接收第四步的结果,在协调节点做结果整合,并计算相关性评分

      • 将结果返回给用户

Elasticsearch性能优化

  • Elasticsearch性能指标

    • 硬件性能指标:包括CPU使用率、内存使用率、磁盘IO读写速度、网络带宽等

    • Elasticsearch内部指标:包括响应时间、吞吐量、并发数、负载等

      • 响应时间:指从客户端发出请求到Elasticsearch返回结果所需的时间

      • 吞吐量:指在一段时间内Elasticsearch处理的请求数量

      • 并发数:指同时连接到Elasticsearch的客户端数量

      • 负载:指Elasticsearch系统中正在处理的请求数量,包括正在进行的搜索、索引、聚合和删除数据等操作

    • 网络指标:包括网络延迟、带宽、吞吐量等

  • Elasticsearch通用的性能优化建议

    • 版本选型:考虑当下,兼顾未来

      • 功能要求

      • 稳定性和性能

      • 兼容性

      • 安全性

    • 确保集群健康状态

    • 硬件资源匹配到位

      • 足够内存

      • SSD

      • 多核CPU

    • 合理进行集群配置

      • 各节点尽量不要和其他业务功能共用一台机器

      • 若集群节点数小于或者等于3个,则建议采用默认节点角色;若集群节点数多于3个,则建议根据业务场景需要逐步独立出主节点角色、数据节点角色和协调节点角色

      • 调整分片和副本数

      • 调整索引刷新频率

      • 合理使用缓存

    • 集群安全为第一要务

      • 防火墙

      • 认证授权

      • TLS/SSL加密

      • 安全补丁更新

    • 务必提前做好集群监控

      • 监控硬件资源

      • 监控Elasticsearch集群状态

      • 监控日志

      • 监控性能指标

      • 监控异常情况

    • 用Elasticsearch处理匹配场景下的合理需求

      • 文本搜索和聚合

      • 倒排索引

      • 分布式架构

      • 写入前预处理

  • Elasticsearch写入优化

    • 写入优化建议

      • 写入时先将副本分片数置为0,完成写入后再将其复原

      • 优先使用系统自动生成ID的方式(手动指定ID的方式会多一次查询)

      • 合理调整刷新频率

      • 合理调整堆内存中的索引缓冲区大小(index.index_buffer_size,默认值为堆内存的10%)

      • 给堆外的内存留够空间

      • 批量写入而非单个文档写入

      • 多线程并发写入

      • 合理设置线程池和队列大小

      • 设置合理的映射

      • 合理使用分词器

      • 必要时使用SSD

      • 合理设置集群节点角色

      • 推荐使用官方客户端的API

    • 写入过程监控

      • 索引率:索引率是指每秒写入Elasticsearch的文档数,是衡量集群写入性能的关键指标

      • 查询速率:查询速率表示每秒的查询次数,反映了Elasticsearch集群的读取性能

  • Elasticsearch检索优化

    • 全量数据和大文档处理的优化建议

      • 不要返回全量或近全量数据

      • 避免使用大文档

    • 数据建模层面的优化建议

      • 文档结构务必规范、一致

      • 设置合理的分片数和副本数

        • 主分片一般建议设置为数据节点的1~3倍

        • 对于一般的非高可用场景,一个副本基本足够

      • 多使用写入前预处理操作

      • 合理使用边写入边排序机制

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        
        # 创建索引时指定排序顺序
        PUT my_index
        {
        	"settings": {
        		"index": {
        			"sort.field": "date",
        			"sort.order": "desc"
        		}
        	},
        	"mappings": {
        		"properties": {
        			"date": {
        				"type": "date"
        			}
        		}
        	}
        }
        
      • 多表关联按需选型

    • 检索方法层面的优化建议

      • 尽可能减少检索字段数目

      • 合理设置size值

      • 尽量使用keyword字段类型

      • 尽量避免使用脚本

      • 有效使用filter缓存

      • 对历史索引数据不定期进行段合并(不要对正在写入数据的索引进行段合并)

      • 预热文件系统缓存

        1
        2
        3
        4
        5
        6
        
        PUT my_index
        {
        	"settings": {
        		"index.store.preload": ["nvd", "dvd"]
        	}
        }
        
      • 通过perference优化缓存利用率

      • 避免使用wildcard检索(推荐在前期使用预处理Ngram分词,以空间换时间来解决问题)

      • 尽量避免使用正则匹配检索

      • 谨慎使用全量聚合和多重嵌套聚合

    • 性能优化的DSL命令行

      • 未分配分片查看

        1
        
        GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state:asc
        
      • 动态调整副本数

        1
        2
        3
        4
        
        PUT my_index/_settings
        {
        	"number_of_replicas": 0
        }
        
      • 重新打开分片分配策略

        1
        2
        3
        4
        5
        
        # 开启Elasticsearch集群的分片分配策略,允许分片在节点间重新分配
        PUT _cluster/settings
        {
        	"cluster.routing.allocation.enable": "all"
        }
        
      • 手动移动未分配的分片

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        
        POST _cluster/reroute
        {
        	"commands": [
        		{
        			"move": {
        				"index": "my_index",
        				"shard": 0,
        				"from_node": "node1",
        				"to_node": "node2"
        			}
        		},
        		{
        			"allocate_replica": {
        				"index": "my_index",
        				"shard": 1,
        				"node": "node3"
        			}
        		}
        	]
        }
        
      • 查看磁盘使用率

        1
        
        GET _cat/allocation?v
        
      • 查看各个节点的版本号

        1
        
        GET _cat/nodes?v&h=host,name,version
        
      • 检索优化实战

        • 慢日志设置

           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
          11
          12
          
          PUT my_index/_settings
          {
          	"index.search.slowlog.threshold.query.warn": "10s",
          	"index.search.slowlog.threshold.query.info": "5s",
          	"index.search.slowlog.threshold.query.debug": "2s",
          	"index.search.slowlog.threshold.query.trace": "500ms",
          	"index.search.slowlog.threshold.fetch.warn": "1s",
          	"index.search.slowlog.threshold.fetch.info": "800ms",
          	"index.search.slowlog.threshold.fetch.debug": "500ms",
          	"index.search.slowlog.threshold.fetch.trace": "200ms",
          	"index.search.slowlog.level": "info"
          }
          
        • 段合并

          1
          
          POST my_index/_forcemerge
          
      • 写入优化实战

        • 批量写入

          1
          2
          3
          
          PUT _bulk
          {"index": {"_index": "my_index"}}
          {"field": "value"}
          
        • 提高刷新频率

          1
          2
          3
          4
          5
          6
          
          PUT my_index/_settings
          {
          	"index": {
          		"refresh_interval": "30s"
          	}
          }
          
        • 将副本数设置为0

          1
          2
          3
          4
          
          PUT my_index/_settings
          {
          	"number_of_replicas": 0
          }
          
        • 通过translog命令进行异步刷盘

          1
          2
          3
          4
          5
          6
          7
          8
          
          PUT my_index/_settings
          {
          	"index": {
          		"translog": {
          			"durability": "async"
          		}
          	}
          }
          

Elasticsearch实战“避坑”指南

  • 分片及副本设置建议

    • 分片数和节点数应该相对平衡

    • 设置total_shards_per_node,将索引压力分摊至多个节点

    • 尽量保证每个分片大小一致

    • 主分片设置参考准则

      • 设置合理的主分片数目。建议设置为节点数目的1倍到3倍(结合业务场景和集群规模),以确保每个节点都有分片

      • 避免将主分片数目设置得太高或太低

      • 监控主分片的状态和性能,使用Elasticsearch监控工具来及时发现和解决问题

      • 考虑主分片的恢复时间,避免主分片过大导致恢复时间过长,从而影响索引的可靠性

    • 副本分片设置参考准则

      • 设置合理的副本分片数目。建议至少设置1个副本

      • 避免在节点数目较少的情况下设置过多的副本分片

  • 25个核心Elasticsearch默认值

    • 参数类型

      • 集群级别参数

        • 举例1:cluster.max_shards_per_node,前缀是cluster.*,修改针对集群生效

        • 举例2:indices.query.bool.max_clause_count,需要在elasticsearch.yml配置文件中设置,重启Elasticsearch后生效

      • 索引级别参数

        • 举例:index.number_of_shards,前缀是index.*,修改针对索引生效
    • 区分静态参数和动态参数

      • 静态参数,如主分片数index.number_of_shards,在索引创建之后就不能更改,除非重建索引

      • 动态参数,如副本分片数index.number_of_replicas,允许在任何时候进行动态调整,可以通过update API进行操作

    • 6个Elasticsearch集群级别参数的关键默认值

      • boolean类型默认支持的最大子句个数

        • 对应参数为indices.query.bool.max_clause_count,为静态参数(需要在elasticsearch. yml中设置),默认最大为1024
      • 数据节点支持的默认分片个数

        • 对应参数为cluster.max_shards_per_node,默认最大为1000(7.X版本后)
      • 堆内存中索引缓冲区的默认比例

        • 对应参数为indices.memory.index_buffer_sizeindices.memory.min_index_buffer_sizeindices.memory.max_index_buffer_size,均为静态参数(需要在elasticsearch.yml中设置)。indices.memory.index_buffer_size的默认值为10%,indices.memory.min_index_buffer_size的默认值为48 MB
      • 默认磁盘使用率

        • 对应参数为cluster.routing.allocation.disk.watermark.low/high/flood_stage,为集群动态参数。cluster.routing.allocation.disk.watermark.low默认为85%,cluster.routing.allocation.disk.watermark.high默认为90%,cluster.routing.allocation.disk.watermark.flood_stage默认为95%
      • 默认GC方式

        • 对应参数为-XX:+UseConcMarkSweepGC-XX:CMSInitiatingOccupancyFraction=75-XX:+UseCMSInitiatingOccupancyOnly
    • 7个Elasticsearch索引级别参数的关键默认值

      • 默认主分片的大小

        • 对应参数为index.number_of_shards,为静态参数,默认值为1;单索引支持最大分片数为1024
      • 默认的压缩算法

        • 对应参数为index.codec,为静态参数,默认值为LZ4
      • 默认副本分片个数

        • 对应参数为index.number_of_replicas,为动态参数,默认值为1
      • 默认刷新频率

        • 对应参数为index.refresh_interval,为动态参数,默认最小值为1s
      • terms默认支持最大长度

        • 对应参数为index.max_terms_count,为动态参数,默认最大值为65536
      • 默认返回的最大搜索结果数

        • 对应参数为index.max_result_window,为动态参数,默认最大值为10000
      • 默认预处理管道

        • 对应参数为index.default_pipeline,为动态参数,默认自定义管道
    • 4个Elasticsearch映射级别参数的关键默认值

      • 默认支持的最大字段数

        • 对应参数为index.mapping.total_fields.limit,为动态参数,默认最大值为1000
      • Mapping字段默认的最大深度

        • 对应参数为index.mapping.depth.limit,为动态参数,默认最大值为20
      • 默认支持的Nested类型个数

        • 对应参数为index.mapping.nested_fields.limit,表示一个索引所支持的最大Nested类型个数,默认值为50;以及index.mapping.nested_objects.limit,表示一个Nested类型所支持的最大对象数,默认值为10000

        • 如果子文档频繁更新,则建议使用父子文档。如果子文档不频繁更新但查询频繁,则建议采用Nested类型

      • 动态映射条件下默认匹配的字符串类型

        • 字符串类型默认为“text+keyword”类型
    • 8个其他关键默认值

      • Elasticsearch默认的评分机制

        • 默认为BM25
      • Elasticsearch keyword类型默认支持的字符数

        • keyword类型支持的最大长度为32766个UTF-8字符,而text类型对字符长度没有限制。设置ignore_above后,超过给定长度的数据将不被索引,无法通过term检索返回结果
      • Elasticsearch集群节点默认属性值

      • Elasticsearch客户端默认请求节点

        • 如果不明确指定协调节点,则由默认请求的节点充当协调节点的角色。每个节点都是一个隐式的协调节点
      • Elasticsearch默认分词器

        • 在不明确指定分词器的场景,默认采用标准分词器(standard)
      • Elasticsearch聚合默认UTC时间

      • Elasticsearch默认堆内存大小

        • Elasticsearch 8.X版本的默认堆内存大小是4GB
      • Elasticsearch默认集成JDK

  • Elasticsearch线程池和队列

    • 查看线程池全貌

      1
      
      GET _cat/thread_pool?v&h=id,name,active,rejected,completed,size,type&pretty&s=type
      
    • Elasticsearch根据在每个节点中检测到的线程数(即number of processors)自动配置线程池参。如果检测失败,则应在elasticsearch.yml中显式设置硬件中可用的线程数

    • 线程池实战问题及注意事项

      • 修改线程池和队列需要更改配置文件elasticsearch.yml

      • 集群拒绝请求的原因可能有多种

      • 写入批量值的递进步长调优

  • Elasticsearch热点线程

    1
    2
    
    GET _nodes/hot_threads
    GET _nodes/<node_id>/hot_threads
    
  • 规划Elasticsearch集群规模和容量(略)

  • Elasticsearch Java客户端选型(略)

  • Elasticsearch缓存

    • 节点查询缓存(node query cache)

      • 应用场景和缓存条件

        • 适用于term检索和filter检索

        • 在Elasticsearch中,对于一个分片内的特定段,只有当该段至少含有10000个文档且段中的文档数量超过了该分片总文档数的3%时,它才会被纳入缓存中

      • 缓存配置

        • indices.queries.cache.size:该配置用于控制filter缓存的堆内存大小,可以是百分比值(例如5%)或精确值(例如512MB),默认为10%,该配置为静态配置,需要在集群的每个数据节点进行配置

        • ndex.queries.cache.enabled:该配置用于控制是否启用节点查询缓存,只能在创建索引或者关闭索引时进行设置,默认为true,该配置为静态配置

    • 分片请求缓存(shard request cache)

      • 应用场景和缓存条件

        • 适用于日志用例场景,在这种情况下,数据不会在旧索引上更新

        • 默认情况下,分片请求缓存仅缓存size=0的搜索请求的结果

      • 缓存配置

        • index.requests.cache.size:该配置用于控制分片缓存的堆内存大小,默认为1%,该配置为静态配置,需要在集群的每个数据节点进行配置
    • 字段缓存

  • Elasticsearch数据建模

    • 基于业务建模

    • 基于数据量建模

    • 基于设置层面建模

    • 基于映射层面建模

      • 字段命名要规范

      • 字段类型要合理

      • 分词器要灵活

      • 多字段类型灵活使用

    • 基于复杂索引关联建模

  • 利用JMeter进行Elasticsearch性能测试(略)