本篇博文主要内容:
-
批量处理、多条获取和多条搜索API接口
-
刷新、冲刷、合并和存储
-
过滤器缓存和过滤器调优
-
调优脚本
-
查询预热器
-
均衡JVM堆大小和操作系统缓存
前言
Elastaticsearch 在进行做进行索引,搜索和抽取统计数值的聚集操作时,通常被认为是很快的。“快”是个模糊的概念。我们不免要问“到底有多快?”,对任何实例,“有多快”取决于具体用例、硬件和配置。
本篇博文中,老夫也会配置Elastaticsearch的最佳实践,从而让系统在应用场景下表现良好。当然,每一次性能的提升,是需要有其他东西的牺牲的。
- 应用复杂性——在第一节中,老夫将展示如何在一个Http访问中合并多个请求,如 index/update/delete/get/search . 应用程序对于这种合并需要保持谨慎(因为这会增加应用程序的复杂性)。但是它可以大幅度的提升系统的整体性能。基本可以这么想,由于更少的网络传输,索引能快20-30倍,是不是很激动;
- 牺牲索引速度换区搜索速度还是反之——第二节中,我们需要理解Elastaticsearch是如何处理Lucene分段的:刷新、冲刷、合并策略,以及存储设置是如何运作的,又是如何影响索引和搜索的性能的。调优索引的性能常常会对搜索产生负面影响,反之亦然;
- 内存——影响Elastaticsearch速度的一个因素就是缓存。我们需要深入过滤器缓存的细节,理解充分最好的利用过滤器。还会涉及到分片查询换存,以及为Elastaticsearch的堆充分预留空间的同时,如何为操作系统保留足够的空间让其缓存索引。如果在冷启动的缓存上运行搜索时慢的让人无法忍受,那么你可以使用索引预热器在后台运行查询,来为缓存热身。
- 以上所有——根据具体的使用场景,在索引阶段你分析文本的方式,以及使用的查询类型可能越来越复杂,这将拖慢其他操作。或者消耗更多内存。
合并请求
为了获得更快的索引速度,所能做的优化是通过bulk批量API。一次发送多篇文档进行索引。这个操作将节省网络来回的开销,并产生更大的吞吐量。一个单独的批量可以接受任何的索引操作。例如,可以创建或者重写文档。也可以将update/delete操作加入批量,不限于索引操作。
如果应用需要一次发送多条get或search操作,也有对应的批量处理:多条获取和多条搜索API。
批量索引、更新和删除
使用批量的索引
request_file=/opt/datas/es/test_bulk
echo '{"index":{"_index":"get-togther","_type":"group","_id":"10"}}
{"name":"es buchtest"}
{"index":{"_index":"get-togther","_type":"group","_id":"11"}}
{"name":"es bigdata buchtest"}'>$request_file
curl -H "Content-Type: application/json" -XPOST hadoop101:9200/_bulk --data-binary @$request_file
这里牵扯到程序代码的问题了,就不多说了。
优化Lucene分段的处理
一旦Elastaticsearch接收到应用所发送的文档,它会将其索引到内存中称为分段(segments)的倒排索引。这些分段会不时的写入到磁盘,且是不可变的,只能被删除(这是为了操作系统更好的缓存他们)。另外,较大的分段会定期从较小的分段创建而来,用于优化倒排索引,使搜索更快。
有很多的调节方式来影响每一个环节中Elastaticsearch对于这些分段的处理,根据你的使用场景来配置这些,常常会带来意义重大的性能提升。一般可分为三类:
刷新(refresh)和冲刷(flush)频率
刷新,会让ES重新打开索引,让新建的文档可用于搜索。冲刷是将索引的数据从内存写入到磁盘。这两者都挺消耗资源的。
合并的策略
Lucene将数据存储在不可变的一组文件中,也就是所谓的分段中。随着索引的数量的增加,系统会创建更多的分段。由于在过多的分段中搜索是很慢的,因此在后台小的分段中会被合并成大的分段,保持分段的数量可控。不过,合并也是十分消耗性能的。
存储和存储限流
ES调节每秒写入的字节数,来限制合并对I/O系统的影响。根据硬件和应用,我们可以调整这个限制。
刷新和冲刷的阈值
我们先看一下这个 setting/ , 这是我其中一篇文档的setting
{
"flink-ci123" : {
"settings" : {
"index" : {
"refresh_interval" : "1s",
"number_of_shards" : "5",
"provided_name" : "flink-ci123",
"creation_date" : "1576485954822",
"number_of_replicas" : "1",
"uuid" : "3jQg9oB8TW-i06MwuWIMmQ",
"version" : {
"created" : "6060099"
}
}
}
}
}
何时刷新
默认的行为是每秒自动的刷新每份索引,可以修改时间间隔,这个可以是在运行时完成的。
PUT flink-ci123/_settings
{
"index.refresh_interval":"1024s"
}
小贴士: 为了确定修改生效了,可以运行如下命令来获取全部的索引设置:
GET flink-ci123/_settings?pretty
当增加’refresh_interval’值时,将获得更大的索引吞吐,因此花费在刷新上的系统资源就减少了
或者也可以将’refresh_interval’设置为 -1 , 彻底关闭自动刷新并依赖手动刷新。这对于索引只是定期批量变化的引用非常有效,如 产品和库存每晚更新的零售供应链。索引的吞吐量是非常重要的
因为想着总是快速更新,但是数据刷新并不是最重要的,因为无论如何都不可能获得完全的实时更新,所以每晚可以关闭自动刷新,进行批量bulk索引和更新,完成后在进行手动刷新。
为了实现手动刷新,访问带刷新索引的_refresh端点.
GET flink-ci123/_refresh
何时冲刷
重点: 不要认为:当刷新发生的时候,所有的数据(内存中)都已经完成了索引,因为最近一次的刷新也会将其写入磁盘。
重点: 对于ES,刷新的过程和内存分段写入磁盘的过程是独立的。
实际上,内存先索引到内存中,经过一次刷新后,ES也会搜索相应的内存分段(在内存中的搜索会快很多,因此,有的书中称这个过程为开心的)。将内存中的分段提交到磁盘上的Lucene索引过程,被称为冲刷(flush)、,无论分段是否能被搜到,冲刷都会发生。
为了确保某个节点宕机或分片移动位置的时候,内存数据不会丢失,ES将使用事务日志来跟踪尚未冲刷的索引操作。除了将内存分段提交到磁盘,冲刷还会清理事务日志,如图所示:
冲刷操作将分段从内存中移动到磁盘上,并清除事务日志
如下所示,满足下列条件之一就会触发冲刷操作:
- 内存缓冲区已满
- 自上次冲刷后超过了一定的时间
- 事务日志达到了一定的阈值
为了控制冲刷发生的频率,不要调整这3个条件的设置。
内存缓冲区的大小在 elastaticsearch.yml 配置文件中定义,通过 indices.memory,index_buffer_size
来设置。这个设置控制了整个节点的缓冲区。