重生之我们在ES顶端相遇第 21 章 - 你应该了解的 ES 读写优化技巧(进阶)

0. 前言

有关读写大部分的内容,前面的章节已经介绍完毕。
该章节会着重介绍日常开发过程中,如何优化我们的读写操作。

1. 写优化

1.1 使用 bulk API

不同的 ES 集群配置,批量写入的性能不同,应在单个分片的单个节点上运行基准测试。先尝试 100 个文档,然后是 200 个,依次类推。

1.2 提高索引的 refresh_interval 间隔

适当的增加索引的 refresh_interval 可以提高写入速度。
默认情况下,ES 每秒刷新 1 次。
该值决定了,写入的数据多少秒后可被搜索到。

PUT test21_refresh_interval
{
  "settings": {
    "index": {
      "refresh_interval": "30s"
    }
  }
}
1.3 禁用内存交换

修改 elasticsearch.yml

bootstrap.memory_lock: true
1.4 至少一半的内存留给机器

文件系统缓存用于缓冲 I/O 操作。将运行 ES 机器至少一半内存分配给文件系统缓存

1.5 ID 自动生成

当显示声明 ID 时,ES 需要检查其他分片上是否存在相同的 ID 字段。随着文档数量的增多,该操作成本会变高。
自动生成 ID,ES 可以跳过该操作。

例如,以下为自动生成ID

POST test21_auto_id/_doc
{
  "name": "elasticsearch"
}

以下为显示声明ID

PUT test21_auto_id/_doc/1
{
   "name": "hello"
}
1.6 使用更快的硬件

如果可以,尽可能使用 SSD,或者其他更快的硬件

1.7 禁用你不用的功能

如果你确定该字段不需要排序、聚合,那么可以禁掉 doc_values
例如

PUT test_doc_value
{
  "mappings": {
    "properties": {
      "name": { 
        "type": "keyword",
        "doc_values": false
      }
    }
  }
}

如果你确定该字段不需要被搜索,那么可以禁掉 index
例如

PUT test_index
{
  "mappings": {
    "properties": {
      "age": {
        "type": "integer" ,
        "index": false
      }
    }
  }
}

如果你确定你的对象字段,仅需要被存储,可以禁掉 enabled
例如

PUT test_enable
{
  "mappings": {
    "properties": {
      "relation": {
        "type": "object",
        "enabled": false
      }
    }
  }
}
1.8 字符串不要使用动态映射

默认情况下,string 会同时生成 text
keyword 2 个字段。
你需要确认该字段是否需要被全文搜索。如果不需要,则将该字段类型设置为 keyword

2. 读优化

2.1 至少一半的内存留给机器

文件系统缓存用于缓冲 I/O 操作。将运行 ES 机器至少一半内存分配给文件系统缓存

2.2 使用更快的硬件

如果可以,尽可能使用 SSD。或者其他更快的硬件

2.3 恰当的文档模型

文档在建模时,尽可能的将所有的字段都放在一个索引上。即可能的冗余,以提高查询的性能。

2.4 搜索字段尽可能的少

常见的是使用 multi_match 搜索多个字段,搜索的字段越多,花费的时间也就越长。
如果这多个字段在权重上没有要求,可以考虑使用 copy_to 到一个字段上,搜索 copy_to 后的新字段。
例如

PUT test20_copyto
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "last_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "full_name": {
        "type": "text"
      }
    }
  }
}

GET test20_copyto/_search
{
  "query": {
    "match": {
      "full_name": "hello"
    }
  }
}
2.5 仅返回你所需要的字段

仅返回你所需要的字段,来节约传输的带宽,加快访问速度。
例如

GET test21/_search
{
  "query": {
    "match_all": {}
  },
  "_source": {
    "includes": ["name", "age"]
  }
}
2.6 避免返回大结果集

不要一次性返回大量的结果集。例如 from + size 特别大。这种情况下,应该要考虑使用 search_after(PIT) 或者 scroll API。

2.7 使用 keyword

如果数值类型的字段不需要范围查询,那么可以将其修改为 keyword 字段,以加快查询性能。

2.8 避免使用脚本

尽可能避免使用脚本查询。如果可以,尽可能在写入时将字段处理好,使其在搜索时不需要使用脚本

2.9 日期搜索四舍五入

在前面的章节,我们有提到过,不需要算分的字段可以使用 filter,这样可以加速查询。
但是如果查询对象是日期的话,那么缓存效果会很差,因为日期会一直变化。
我们可以通过查询四舍五入的日期,来优化该操作

例如

PUT test21_date/_doc/1
{
  "my_date": "2024-10-06T16:30:55.328Z"
}

GET test21_date/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h",
            "lte": "now"
          }
        }
      }
    }
  }
}

上述的查询,我们可以转换为以下查询,使得可以缓存近 1 分钟内相同的查询请求

GET test21_date/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h/m",
            "lte": "now/m"
          }
        }
      }
    }
  }
}
2.10 选择合适的副本数

假如 ES 集群有 num_nodes 个节点,总共有 num_primaries 个主分片,并且希望能够一次处理 max_failures 个节点故障。则合适的副本数量为:

max(max_failures, ceil(num_nodes / num_primaries) - 1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值