ElasticSearch10-性能优化
1、硬件优化
(1)存储配置
- ElasticSearch 是基于Lucene 的,Lucene将数据存储在磁盘上,磁盘的IO就是 ElasticSearch 的瓶颈所在。
- Elasticsearch 默认的数据存储路径是在 Elasticsearch 安装目录下的
data
子目录中。不过,这个路径是可以配置的,具体的默认路径可能因操作系统和安装方式的不同而有所差异。
- 对于不同的操作系统,Elasticsearch 的默认数据路径通常是:
- Linux :
/usr/share/elasticsearch/data
- macOS :
/usr/local/var/lib/elasticsearch/data
- Windows :
C:\ProgramData\Elasticsearch\data
- **配置数据存储路径:**可以在
elasticsearch.yml
配置文件中设置 path.data
属性。例如:
yaml
复制代码
path.data: /var/lib/elasticsearch/data
- 注意事项
- Elasticsearch 允许你配置多个数据路径,以便于实现数据的冗余存储和负载均衡。这可以通过在
path.data
后面跟上多个路径实现,路径之间用逗号分隔。
- 确保 Elasticsearch 进程对该路径有读写权限。
- 建议不要将数据存储在系统盘上,以避免系统盘空间不足导致的问题。
(2)优化建议
- 使用 SSD,性能远高于机械磁盘。
- 使用 RAID 0,条带化 RAID 会提高磁盘 I/O,代价显然就是当一块硬盘故障时整个就故障了。不要使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。
- 使用多块硬盘,并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上面。
- 不要使用远程挂载的存储,比如 NFS 或者 SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰。
2、分片优化
(1)设置合理分片数量
- 数据规模:估算你存储的数据总量,并参考每个分片的最佳大小(通常在10GB到50GB之间)。这样可以确保分片既不会过大导致恢复时间过长,也不会过小导致资源开销增加。
- 并发量和负载分布:考虑查询的并发性,更多的分片可以分散查询负载。但是,分片数量过多会导致管理开销增加,每个搜索请求都会调度到索引的每个分片中,如果分片分散在不同的节点上问题不大,但如果分片开始竞争相同的硬件资源时,性能便会逐步下降。
- 硬件资源:每个节点上可以存储的分片数量与可用的堆内存大小成正比关系。一个经验法则是,确保对于节点上已配置的每个GB,将分片数量保持在20以下。例如,如果节点有30GB的堆内存,那么最多可以有600个分片。但是,从8.3版本开始,Elasticsearch减少了每个分片的堆使用量,因此这个经验法则也进行了更新,请根据实际情况调整。
- 数据增长趋势:考虑数据集的增长趋势,避免为未来可能的数据量做过多分配。如果你担心数据的快速增长,可以将分片最大容量限制为30GB,然后再对分片数量做合理估算。例如,如果你的数据能达到200GB,推荐最多分配7到8个分片。
- 查询性能:对于需要频繁更新或删除的数据,较小的分片(10GB-20GB)可能更合适,因为这样可以减少段合并的开销。对于静态数据或只增加不修改的数据,更大的分片(接近50GB)通常更有效。
- 集群扩展性:随着数据量的增加,可以通过增加分片数和机器数来扩展集群。Elasticsearch会自动迁移分片以重新平衡集群。
- 索引和分片的资源开销:每个索引和分片都会产生一定的资源开销。因此,合理规划分片数量和大小对于集群的性能至关重要。
- 综上所述,合理设置分片数量需要根据具体的业务需求、数据增长预测、集群资源和性能目标来综合考虑。通常,一个平衡的做法是保持每个分片在10GB到50GB之间,并根据节点的堆内存大小来合理配置分片数量,同时考虑到高可用性和吞吐量的需求。
(2)推迟分片分配
- 对于节点瞬时中断的问题,默认情况,集群会等待一分钟来查看节点是否会重新加入,如果这个节点在此期间重新加入,重新加入的节点会保持其现有的分片数据,不会触发新的分片分配。这样就可以减少 ES 在自动再平衡可用分片时所带来的极大开销。
- 通过修改参数 delayed_timeout,可以延长再均衡的时间,可以全局设置也可以在索引级别进行修改:
json
复制代码
PUT /_all/_settings
{
"settings": {
"index.unassigned.node_left.delayed_timeout": "5m"
}
}
(3)自适应副本选择
- **自适应副本选择(Adaptive Replica Selection,ARS):**是一个用于提高搜索性能的功能,它允许副本分片参与搜索请求,而不需要主分片的参与。ARS在7.0版本中引入默认开启,用于减少跨节点搜索的网络开销。
- 启用自适应副本选择 :自适应副本选择默认是启用的,但如果需要确认或启用该功能,可以在
elasticsearch.yml
配置文件中设置以下参数,这个设置允许Elasticsearch在执行搜索时考虑远程副本分片。
yaml
复制代码
search.remote_cluster_aware: true
- 配置集群名称 :为了使用自适应副本选择,需要确保所有参与的Elasticsearch集群都配置了相同的
cluster.name
。这可以在elasticsearch.yml
文件中设置:
yaml
复制代码
cluster.name: my-application
- 配置副本分配 :如果需要,可以配置副本分片的分配策略,以确保副本分片被分配到不同的节点或机架上,从而提高搜索的效率和可靠性。这个例子中,副本分片将被分配到具有
rack_id
为1或2的节点上。
json
复制代码
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.replicas.include.rack_id": "1,2"
}
}
3、路由优化
(1)路由参数原理
- **路由公式:**shard_num = hash(_routing) % num_primary_shards。
- 减少查询分片数:通过指定routing参数,查询可以被限制在特定的分片上执行,而不是遍历所有的分片。这样可以减少查询的分片数量,从而提高查询效率。
- 避免协调节点二次排序:在没有指定routing的情况下,查询请求会分发到所有分片,然后协调节点需要对所有分片返回的结果进行排序和聚合,这会增加额外的性能开销。而指定routing后,可以直接在目标分片上完成搜索,避免了协调节点的二次排序。
- 提高查询速度:使用Routing信息查找的效率很高,因为可以直接定位到目标分片,避免了多余的查询,从而加快了查询速度。
- 优化数据布局:通过合理地使用Routing,可以控制数据的物理布局,将相关的文档路由到相同的分片上,这样可以减少跨分片查询的需要,提高查询性能。
- 确保数据一致性:自定义路由可以确保对具有相同路由值的文档的读取和写入操作都在同一个分片上执行,从而减少数据不一致的风险。
- 提高查询效率:在设计Elasticsearch Mapping时,合理利用Routing信息可以提升查询的效率。例如,可以将城市ID作为Routing的条件,让同一个城市的数据落在相同的分片中,这样查询时可以直接指定Routing,提高查询效率。
(2)索引文档时指定路由值
- 当索引一个新文档时,可以在请求中包含
routing
参数来指定路由值。
- 通过指定
routing=user123
,告诉Elasticsearch将文档路由到与user123
哈希值对应的分片上。
- 如果以后需要检索或更新这个文档,也需要在请求中包含相同的路由值。
json
复制代码
# 创建索引
PUT my_index_2
# 创建文档
PUT /my_index_2/_doc/1?routing=user123
{
"user_id": "user123",
"title": "My first blog post"
}
# 返回
{
"_index" : "my_index_2",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
(3)查询时指定路由值
- 在执行查询时,也可以指定路由值来限制查询只在特定的分片上执行。
- 此搜索请求将仅在与"user1"和"user2"路由值关联的分片上执行。
json
复制代码
GET my_index_2/_search?routing=user1,user2
{
"query": {
"match": {
"title": "document"
}
}
}
(4)设置routing为必选参数
- 对于使用routing写入的文档,在进行GET、UPDATE或DELETE操作时如果不指定routing参数会出现异常。
- Elasticsearch提供了一个索引mapping级别的设置
_routing.required
,来强制用户在INDEX、GET、DELETE、UPDATE一个文档时必须使用routing参数。
json
复制代码
POST my_index_2/_doc
{
"mappings": {
"_routing": {
"required": true
}
}
}
4、写入优化
(1)数据批量处理
- **使用 Bulk API:**支持批量操作,提高写入效率。
- **批量提交数据量:**默认不超过 100M,单次批处理数据大小从 5MB 到 15MB 逐渐增加,直到性能不再提升。
(2)减少副本数量
- 减少副本数量:在大量写入过程中,减少副本数量可以提升写入性能,写入后再恢复原来的副本数量。
- 修改现有索引的副本数量:对于活动的索引库,副本数量可以随时修改。可以通过以下命令将副本数量设置为0
json
复制代码
PUT my_index/_settings
{
"index": {
"number_of_replicas": 0
}
}
json
复制代码
PUT /_all/_settings
{
"index": {
"number_of_replicas": 0
}
}
- 设置索引模板:如果希望之后创建的索引默认副本数量为0,可以设置一个索引模板。
json
复制代码
PUT /_template/default_template
{
"index_patterns": ["*"],
"settings": {
"number_of_replicas": 0
}
}
json
复制代码
PUT my_index
{
"settings": {
"index": {
"number_of_replicas": 0
}
}
}
(3)优化 flush 设置
- index.translog.flush_threshold_period
- 这个参数控制了Flush时间间隔。默认值是 30 m,加大此参数可以减少数据写入磁盘的频率,从而减少磁盘I/O频率。
json
复制代码
PUT /_cluster/settings
{
"persistent" : {
"index.translog.flush_threshold_period": "120m"
}
}
- index.translog.flush_threshold_size
- 这个参数控制了Translog达到多大时会触发flush操作。默认值通常是512MB。增加这个值可以减少flush操作的频率,从而可能提高写入性能。
json
复制代码
PUT /your_index/_settings
{
"index.translog.flush_threshold_size": "1gb"
}
- index.translog.sync_interval
- 这个参数控制了Translog多久同步一次到磁盘。默认是 5 秒。增加这个值可以减少磁盘I/O,从而可能提高写入性能。
json
复制代码
PUT /your_index/_settings
{
"index.translog.sync_interval": "30s"
}
- **注意:**调整这些参数可能会影响数据的安全性和查询性能。
(5)减少Refresh的次数
- 动态调整Refresh间隔
- Elasticsearch默认的Refresh间隔是1秒,这意味着每秒索引会刷新一次,使得新的文档可以被搜索到。在数据导入阶段,可以增加这个间隔,例如设置为30秒,以减少Refresh操作对性能的影响。
json
复制代码
PUT /my_index/_settings
{
"index.refresh_interval": "30s"
}
- 数据导入完成后,可以再将Refresh间隔调回原来的值,比如1秒:
json
复制代码
PUT /my_index/_settings
{
"index.refresh_interval": "1s"
}
- 临时禁用Refresh :
- 在进行大量数据写入时,可以暂时禁用自动刷新,待批量索引完成后再启用。这可以通过将Refresh间隔设置为-1来实现,表示不自动刷新:
json
复制代码
PUT /my_index/_settings
{
"index.refresh_interval": "-1"
}
- 完成批量索引后,再重新启用Refresh:
json
复制代码
PUT /my_index/_settings
{
"index.refresh_interval": "1s"
}
5、内存优化
(1)JVM堆内存设置
- **<font style="color:rgba(0, 0, 0, 0.9);">不超过物理内存的 50%:</font>**文件系统缓存用于处理I/O操作,建议至少将物理机一半的内存分配给文件系统缓存。例如,如果物理机内存为64GB,则至少分配32GB给文件系统缓存。
- **最大不超过32GB:**这是因为超过32GB后,JVM会启用压缩指针,导致性能下降。
- **初始堆内存和最大堆内存相同:**在`jvm.options`配置文件中设置Xms和Xmx参数,确保初始堆内存和最大堆内存相同,减少垃圾回收开销。
- **综上所述:**对于128GB内存的机器,建议配置两个Elasticsearch节点,每个节点的堆内存设置为31GB。
plain
复制代码
-Xms31g
-Xmx31g
(2)禁用Swap
- 确保操作系统不会将Elasticsearch进程swap出去,这会极大降低Elasticsearch的索引速度。可以通过执行
sudo swapoff -a
命令来禁用swap。
(3)调整索引缓存大小
- 确保每个索引分片能获得至少512M的缓存,即
indices.memory.index_buffer_size
设置为512M。超过512M没有更多提升效果。
(4)监控内存使用情况
- 使用Elasticsearch提供的API监控内存使用情况,例如
GET _cat/nodes?h=name,*heap*,*memory*,*Cache*&format=json
和GET _cat/indices/*?h=*memory*&format=json
。