专业的编程技术博客社区

网站首页 > 博客文章 正文

elasticsearch 提高写入性能的方法

baijin 2025-03-01 12:47:20 博客文章 14 ℃ 0 评论

写性能优化的目标:增大写吞吐量(Events Per Second),越高越好

客户端:多线程,批量写

  • 可以通过性能测试,确定最佳文档数量
  • 多线程:需要观察是否有HTTP 429返回,实现Retry以及线程数量的自动调节

服务端:单个性能的问题,往往是多个因素造成的。需要先分解问题,在单个节点上进行跳转并且结合测试,尽可能压榨硬件资源,以达到最高吞吐量

  • 使用更好的硬件。观察CPU /IO Block
  • 线程切换/堆栈状况
  • 降低IO操作:使用ES自动生成的文档ID/一些相关的ES配置,如:Refresh Interval
  • 降低CPU和存储开销:减少不必要的分词/避免不需要的doc_values/文档的字段尽量保证相同的顺序,可以提高文档的压缩率
  • 尽可能做到写入和分片的均衡负载,实现水平扩展:shard Fitering/Write Load Balancer
  • 调整Bulk线程池和队列
  • ES的默认设置,已经综合考虑了数据的可靠性,搜索的实时性,写入速度,一般不需要盲目修改
  • 一切优化,都需要级域高质量的数据建模

关闭无关的功能:

  • 只需要聚合不需要搜索,index设置成false
  • 不需要算分,Norms设置成false
  • 不要对字符串使用默认的dynamic mapping。字段数量过多,会对性能产生比较大的影响

设置mapping的时候dynamic可以限制陌生字段,

true:遇到陌生字段,就进行dynamic mapping
false:遇到陌生字段,就忽略
strict:遇到陌生字段,就报错

index_options控制在创建倒排索引时,哪些内容会被添加到倒排索引中。优化这些设置,一定程度可以节约CPU\

关闭_source,减少IO操作;(适合指标型数据)

可以将需要的字段保存在_all中,然后使用IK分词以备查询,其余的字段,则不存储.
{  
    "mappings": {  
        "sod_song_ksc": {  
            "dynamic_templates": [  
                {  
                    "all_field": {  
                        "mapping": {  
                            "index": "no",   
                            "store": "yes",   
                            "type": "{dynamic_type}",   
                            "include_in_all": false  
                        },   
                        "match": "*"  
                    }  
                }  
            ],   
            "_source": {  
                "enabled": false  //关闭_source
            },   
            "_all": {  
                "enabled": true,   
                "analyzer": "ik"  
            },   
            "properties": {  
                "SongID": {  
                    "type": "long",   
                    "store": "yes",   
                    "index": "not_analyzed",   
                    "include_in_all": true  //保存在_all中
                }               
            }  
        }  
    }  
}  


针对性能的取舍:

Refresh

将文档先保存在Index buffer中,以refresh_interval为间隔时间,定期清空buffer,生成segment,借助文件系统缓存的特性,先将segment放在文件系统缓存中,并开放查询,以提升搜索的实时性

Translog

Segment没有写入磁盘,即便发生了宕机,重启后,数据也能恢复,默认配置是每次请求都会洛盘

Flush

删除旧的translog文件

生成Segment并写入磁盘/更新commit point 并写入磁盘。ES自动完成


Refresh interval:

降低Refresh的频率:

增加refresh_interval的数值。默认为1s,如果设置成-1,会禁止自动refresh

  • 避免过于频繁的refresh而生成过多的segment文件
  • 但是会降低搜索的实时性

增大静态配置参数
indices.memory.index_buffer_size

  • 默认是10%,会导致触发refresh


Translog:

从6.0开始每次写入都会进行translog落盘的操作。

降低写磁盘的频率,但是会降低容灾的能力

  • index.translog.durability:默认是request,每个请求都会落盘。设置成async,异步写入
  • index.translog.sync_interval设置为60s,每分钟执行一次
  • index.translog.flush_threshod_size:默认512Mb,可以适当调大。当translog超过该值,会触发flush


分片设定:

副本在写入时设置为0,完成后再增加

合理设置主分片数,确保均匀分配再所有数据节点上

  • index.routing.allocation.total_share_per_node:限定每个索引再每个节点上可分配的主分片数
  • 5个节点的集群。索引有5个主分配,1个副本,应该如何设置?
  • (5+5)/5 =2 index.routing.allocation.total_share_per_node:2
  • 生产环境可适当调大这个数字,避免有节点下线时候分片无法正常迁移


Bulk,线程池和队列大小

客户端

  • 单个bulk请求体的数据量不要太大,官方建议5-15mb
  • 写入端的bulk请求超时要足够长,建议60s以上
  • 写入端尽量将数据轮询打到不同节点

服务端

  • 索引创建属于计算密集型任务,应该使用固定大小的线程池来配置。来不及处理的放入队列,线程数配置成cpu核心数+1,避免过多的上下文切换
  • 队列大小可以适当增加,不要过大,否则占用的内存会成为GC的负担


一个索引设定的例子:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表