Linux最新Elasticsearch 最佳运维实践总结,2024年最新快醒醒吧

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以点击这里获取!

./bin/elasticsearch -Djna.tmpdir=/path/to/new/dir

Network 、Transport and HTTP 部分

network.bind_host
设置绑定的ip地址,可以是ipv4或ipv6的。

network.publish_host
设置其它节点和该节点交互的ip地址,如果不设置它会自动设置,值必须是个真实的ip地址。

network.host
同时设置bind_host和publish_host两个参数,值可以为网卡接口、127.0.0.1、私有地址以及公有地址。

http_port
接收http请求的绑定端口。可以为一个值或端口范围,如果是一个端口范围,节点将绑定到第一个可用端口。默认为:9200-9300。

transport.tcp.port
节点通信的绑定端口。可以为一个值或端口范围,如果是一个端口范围,节点将绑定到第一个可用端口。默认为:9300-9400。

transport.tcp.connect_timeout
套接字连接超时设置,默认为 30s。

transport.tcp.compress
设置为true启用节点之间传输的压缩(LZF),默认为false。

transport.ping_schedule
定时发送ping消息保持连接,默认transport客户端为5s,其他为-1(禁用)。

httpd.enabled
是否使用http协议提供服务。默认为:true(开启)。

http.max_content_length
最大http请求内容。默认为100MB。如果设置超过100MB,将会被MAX_VALUE重置为100MB。

http.max_initial_line_length
http的url的最大长度。默认为:4kb。

http.max_header_size
http中header的最大值。默认为8kb。

http.compression
支持压缩(Accept-Encoding)。默认为:false。

http.compression_level
定义压缩等级。默认为:6。

http.cors.enabled
启用或禁用跨域资源共享。默认为:false。

http.cors.allow-origin
启用跨域资源共享后,默认没有源站被允许。在//中填写域名支持正则,例如 /https?😕/localhost(:[0-9]+)?/。 * 是有效的值,但是开放任何域名的跨域请求被认为是有安全风险的elasticsearch实例。

http.cors.max-age
浏览器发送‘preflight’OPTIONS-request 来确定CORS设置。max-age 定义缓存的时间。默认为:1728000 (20天)。

http.cors.allow-methods
允许的http方法。默认为OPTIONS、HEAD、GET、POST、PUT、DELETE。

http.cors.allow-headers
允许的header。默认 X-Requested-With, Content-Type, Content-Length。

http.cors.allow-credentials
是否允许返回Access-Control-Allow-Credentials头部。默认为:false。

http.detailed_errors.enabled
启用或禁用输出详细的错误信息和堆栈跟踪响应输出。默认为:true。

http.pipelining
启用或禁用http管线化。默认为:true。

http.pipelining.max_events
一个http连接关闭之前最大内存中的时间队列。默认为:10000。

Discovery部分

discovery.zen.minimum_master_nodes: 3
预防脑裂(split brain)通过配置大多数节点(总节点数/2+1)。默认为3。

discovery.zen.ping.multicast.enabled: false
设置是否打开组播发现节点。默认false。

discovery.zen.ping.unicast.host
单播发现所使用的主机列表,可以设置一个属组,或者以逗号分隔。每个值格式为 host:port 或 host(端口默认为:9300)。默认为 127.0.0.1,[::1]。

discovery.zen.ping.timeout: 3s
设置集群中自动发现其它节点时ping连接超时时间,默认为3秒,对于比较差的网络环境可以高点的值来防止自动发现时出错。

discovery.zen.join_timeout
节点加入到集群中后,发送请求到master的超时时间,默认值为ping.timeout的20倍。

discovery.zen.master_election.filter_client:true
当值为true时,所有客户端节点(node.client:true或node.date,node.master值都为false)将不参加master选举。默认值为:true。

discovery.zen.master_election.filter_data:false
当值为true时,不合格的master节点(node.data:true和node.master:false)将不参加选举。默认值为:false。

discovery.zen.fd.ping_interval
发送ping监测的时间间隔。默认为:1s。

discovery.zen.fd.ping_timeout
ping的响应超时时间。默认为30s。

discovery.zen.fd.ping_retries
ping监测失败、超时的次数后,节点连接失败。默认为3。

discovery.zen.publish_timeout
通过集群api动态更新设置的超时时间,默认为30s。

discovery.zen.no_master_block
设置无master时,哪些操作将被拒绝。all 所有节点的读、写操作都将被拒绝。write 写操作将被拒绝,可以读取最后已知的集群配置。默认为:write。

Gateway部分

gateway.expected_nodes: 0
设置这个集群中节点的数量,默认为0,一旦这N个节点启动,就会立即进行数据恢复。

gateway.expected_master_nodes
设置这个集群中主节点的数量,默认为0,一旦这N个节点启动,就会立即进行数据恢复。

gateway.expected_data_nodes
设置这个集群中数据节点的数量,默认为0,一旦这N个节点启动,就会立即进行数据恢复。

gateway.recover_after_time: 5m
设置初始化数据恢复进程的超时时间,默认是5分钟。

gateway.recover_after_nodes
设置集群中N个节点启动时进行数据恢复。

gateway.recover_after_master_nodes
设置集群中N个主节点启动时进行数据恢复。

gateway.recover_after_data_nodes
设置集群中N个数据节点启动时进行数据恢复。

八.  Elasticsearch常用插件

elasticsearch-head 插件
一个elasticsearch的集群管理工具,它是完全由html5编写的独立网页程序,你可以通过插件把它集成到es。
项目地址:https://github.com/mobz/elasticsearch-head

插件安装方法1

elasticsearch/bin/plugin install mobz/elasticsearch-head
重启elasticsearch
打开http://localhost:9200/_plugin/head/

插件安装方法2

根据地址https://github.com/mobz/elasticsearch-head 下载zip解压
建立elasticsearch/plugins/head/_site文件
将解压后的elasticsearch-head-master文件夹下的文件copy到_site
重启elasticsearch
打开http://localhost:9200/_plugin/head/

bigdesk插件
elasticsearch的一个集群监控工具,可以通过它来查看es集群的各种状态,如:cpu、内存使用情况,索引数据、搜索情况,http连接数等。
项目地址: https://github.com/hlstudio/bigdesk

插件安装方法1

elasticsearch/bin/plugin install hlstudio/bigdesk
重启elasticsearch
打开http://localhost:9200/_plugin/bigdesk/ 

插件安装方法2

https://github.com/hlstudio/bigdesk下载zip 解压
建立elasticsearch-1.0.0\plugins\bigdesk\_site文件
将解压后的bigdesk-master文件夹下的文件copy到_site
重启elasticsearch
打开http://localhost:9200/_plugin/bigdesk/ 

Kopf 插件
一个ElasticSearch的管理工具,它也提供了对ES集群操作的API。
项目地址:https://github.com/lmenezes/elasticsearch-kopf

插件安装方法

elasticsearch/bin/plugin install lmenezes/elasticsearch-kopf
重启elasticsearch
打开http://localhost:9200/_plugin/kopf/

九、Elasticsearch 的fielddata内存控制、预加载以及circuit breaker断路器

fielddata核心原理
fielddata加载到内存的过程是lazy加载的,对一个analzyed field执行聚合时,才会加载,而且是field-level加载的一个index的一个field,所有doc都会被加载,而不是少数doc不是index-time创建,是query-time创建

fielddata内存限制
elasticsearch.yml: indices.fielddata.cache.size: 20%,超出限制,清除内存已有fielddata数据fielddata占用的内存超出了这个比例的限制,那么就清除掉内存中已有的fielddata数据默认无限制,限制内存使用,但是会导致频繁evict和reload,大量IO性能损耗,以及内存碎片和gc

监控fielddata内存使用

#各个分片、索引的fielddata在内存中的占用情况
[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_stats/fielddata?fields=*'     

#每个node的fielddata在内存中的占用情况
[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_nodes/stats/indices/fielddata?fields=*'

#每个node中的每个索引的fielddata在内存中的占用情况
[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_nodes/stats/indices/fielddata?level=indices&fields=*'

circuit breaker断路由
如果一次query load的feilddata超过总内存,就会oom --> 内存溢出;
circuit breaker会估算query要加载的fielddata大小,如果超出总内存,就短路,query直接失败;
在elasticsearch.yml文件中配置如下内容:
indices.breaker.fielddata.limit: fielddata的内存限制,默认60%
indices.breaker.request.limit:  执行聚合的内存限制,默认40%
indices.breaker.total.limit:       综合上面两个,限制在70%以内

限制内存使用 (Elasticsearch聚合限制内存使用)

通常为了让聚合(或者任何需要访问字段值的请求)能够快点,访问fielddata一定会快点, 这就是为什么加载到内存的原因。但是加载太多的数据到内存会导致垃圾回收(gc)缓慢, 因为JVM试着发现堆里面的额外空间,甚至导致OutOfMemory (即OOM)异常。

然而让人吃惊的发现, Elaticsearch不是只把符合你的查询的值加载到fielddata. 而是把index里的所document都加载到内存,甚至是不同的 _type 的document。逻辑是这样的,如果你在这个查询需要访问documents X,Y和Z, 你可能在下一次查询就需要访问别documents。而一次把所有的值都加载并保存在内存 , 比每次查询都去扫描倒排索引要更方便。

JVM堆是一个有限制的资源需要聪明的使用。有许多现成的机制去限制fielddata对堆内存使用的影响。这些限制非常重要,因为滥用堆将会导致节点的不稳定(多亏缓慢的垃圾回收)或者甚至节点死亡(因为OutOfMemory异常);但是垃圾回收时间过长,在垃圾回收期间,ES节点的性能就会大打折扣,查询就会非常缓慢,直到最后超时。

如何设置堆大小
对于环境变量 $ES_HEAP_SIZE 在设置Elasticsearch堆大小的时候有2个法则可以运用:

  1. 不超过RAM的50%
    Lucene很好的利用了文件系统cache,文件系统cache是由内核管理的。如果没有足够的文件系统cache空间,性能就会变差;

  2. 不超过32G
    如果堆小于32GB,JVM能够使用压缩的指针,这会节省许多内存:每个指针就会使用4字节而不是8字节。把对内存从32GB增加到34GB将意味着你将有更少的内存可用,因为所有的指针占用了双倍的空间。同样,更大的堆,垃圾回收变得代价更大并且可能导致节点不稳定;这个限制主要是大内存对fielddata影响比较大。

Fielddata大小
参数 indices.fielddata.cache.size 控制有多少堆内存是分配给fielddata。当你执行一个查询需要访问新的字段值的时候,将会把值加载到内存,然后试着把它们加入到fielddata。如果结果的fielddata大小超过指定的大小 ,为了腾出空间,别的值就会被驱逐出去。默认情况下,这个参数设置的是无限制 — Elasticsearch将永远不会把数据从fielddata里替换出去。

这个默认值是故意选择的:fielddata不是临时的cache。它是一个在内存里为了快速执行必须能被访问的数据结构,而且构建它代价非常昂贵。如果你每个请求都要重新加载数据,性能就会很差。

一个有限的大小强迫数据结构去替换数据。下面来看看什么时候去设置下面的值,首先看一个警告: 这个设置是一个保护措施,而不是一个内存不足的解决方案!

如果你没有足够的内存区保存你的fielddata到内存里,Elasticsearch将会经常性的从磁盘重新加载数据,并且驱逐别的数据区腾出空间。这种数据的驱逐会导致严重的磁盘I/O,并且在内存里产生大量的垃圾,这个会在后面被垃圾回收。

假设你在索引日志,每天使用给一个新的索引。通常情况下你只会对过去1天或者2天的数据感兴趣。即使你把老的索引数据保留着,你也很少查询它们。尽管如此,使用默认的设置, 来自老索引的fielddata也不会被清除出去!fielddata会一直增长直到它触发fielddata circuit breaker --参考
断路器–它将阻止你继续加载fielddata。在那个时候你被卡住了。即使你仍然能够执行访问老的索引里的fielddata的查询, 你再也不能加载任何新的值了。相反,我们应该把老的值清除出去给新的值腾出空间。为了防止这种情景,通过在elasticsearch.yml文件里加上如下的配置给fielddata 设置一个上限:
indices.fielddata.cache.size:  40%
   ,
可以设置成堆大小的百分比,也可以是一个具体的值,比如 8gb;通过适当设置这个值,最近被访问的fielddata将被清除出去,给新加载数据腾出空间。

在网上可能还会看到另外一个设置参数:
indices.fielddata.cache.expire
千万不要使用这个设置!这个设置高版本已经废弃!!!
这个设置告诉Elasticsearch把比过期时间老的数据从fielddata里驱逐出去,而不管这个值是否被用到。这对性能是非常可怕的 。驱逐数据是有代价的,并且这个有目的的高效的安排驱逐数据并没有任何真正的收获。**没有任何理由去使用这个设置!!!**我们一点也不能从理论上制造一个假设的有用的情景。现阶段存 在只是为了向后兼容。我们在这个书里提到这个设置是因为这个设置曾经在网络上的各种文章里 被作为一个 ``性能小窍门’’ 被推荐过。记住永远不要使用它!!!

监控fielddata (上面提到了)
监控fielddata使用了多少内存以及是否有数据被驱逐是非常重要的。大量的数据被驱逐会导致严重的资源问题以及不好的性能。

Fielddata使用可以通过下面的方式来监控:
对于单个索引使用 {ref}indices-stats.html[indices-stats API]:

[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_stats/fielddata?fields=

对于单个节点使用 {ref}cluster-nodes-stats.html[nodes-stats API]:

[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_nodes/stats/indices/fielddata?fields=*'

或者甚至单个节点单个索引

[root@elk-node03 ~]# curl -X GET 'http://10.0.8.47:9200/_nodes/stats/indices/fielddata?level=indices&fields=*'

通过设置 ?fields=* 内存使用按照每个字段分解了.

断路器(breaker)
fielddata的大小是在数据被加载之后才校验的。如果一个查询尝试加载到fielddata的数据比可用的内存大会发生什么情况?答案是不客观的:你将会获得一个OutOfMemory异常。

Elasticsearch包含了一个 fielddata断路器 ,这个就是设计来处理这种情况的。断路器通过检查涉及的字段(它们的类型,基数,大小等等)来估计查询需要的内存。然后检查加 载需要的fielddata会不会导致总的fielddata大小超过设置的堆的百分比。

如果估计的查询大小超过限制,断路器就会触发并且查询会被抛弃返回一个异常。这个发生在数据被加载之前,这就意味着你不会遇到OutOfMemory异常。

Elasticsearch拥有一系列的断路器,所有的这些都是用来保证内存限制不会被突破:
indices.breaker.fielddata.limit
这个 fielddata 断路器限制fielddata的大小为堆大小的60%,默认情况下。

indices.breaker.request.limit
这个 request 断路器估算完成查询的其他部分要求的结构的大小,比如创建一个聚集通, 以及限制它们到堆大小的40%,默认情况下。

indices.breaker.total.limit
这个total断路器封装了 request 和 fielddata 断路器去确保默认情况下这2个 使用的总内存不超过堆大小的70%。

断路器限制可以通过文件 config/elasticsearch.yml 指定,也可以在集群上动态更新:

curl -PUT 'http://10.0.8.47:9200/_cluster/settings{
"persistent" : {
"indices.breaker.fielddata.limit" : 40% (1)
}
}

这个限制设置的是堆的百分比。

最好把断路器设置成一个相对保守的值。记住fielddata需要和堆共享 request 断路器, 索引内存缓冲区,过滤器缓存,打开的索引的Lucene数据结构,以及各种各样别的临时数据 结构。所以默认为相对保守的60%。过分乐观的设置可能会导致潜在的OOM异常,从而导致整 个节点挂掉。从另一方面来说,一个过分保守的值将会简单的返回一个查询异常,这个异常会被应用处理。 异常总比挂掉好。这些异常也会促使你重新评估你的查询:为什么单个的查询需要超过60%的 堆空间。

断路器和Fielddata大小
在 Fielddata大小部分我们谈到了要给fielddata大小增加一个限制去保证老的不使用 的fielddata被驱逐出去。indices.fielddata.cache.size 和 indices.breaker.fielddata.limit 的关系是非常重要的。如果断路器限制比缓冲区大小要小,就会没有数据会被驱逐。为了能够 让它正确的工作,断路器限制必须比缓冲区大小要大。

我们注意到断路器是和总共的堆大小对比查询大小,而不是和真正已经使用的堆内存区比较。 这样做是有一系列技术原因的(比如,堆可能看起来是满的,但是实际上可能正在等待垃圾 回收,这个很难准确的估算)。但是作为终端用户,这意味着设置必须是保守的,因为它是 和整个堆大小比较,而不是空闲的堆比较。

十、Elasticserach索引详解

-   分词器集成
1. 获取 ES-IKAnalyzer插件:
地址: https://github.com/medcl/elasticsearch-analysis-ik/releases
一定要获取匹配的版本

**2.**安装插件
将 ik 的压缩包解压到 ES安装目录的plugins/目录下(最好把解出的目录名改一下,防止安装别的插件时同名冲突),然后重启ES。
**3.**扩展词库
修改配置文件config/IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
  <comment>IK Analyzer 扩展配置</comment>
  <!--用户可以在这里配置自己的扩展字典-->
  <entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
   <!--用户可以在这里配置自己的扩展停止词字典-->
  <entry key="ext_stopwords">custom/ext_stopword.dic</entry>
   <!--用户可以在这里配置远程扩展字典-->
  <entry key="remote_ext_dict">location</entry>
   <!--用户可以在这里配置远程扩展停止词字典-->
  <entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>

**4.**测试 IK
**5.**创建一个索引

curl -XPUT http://localhost:9200/index

**6.**创建一个映射mapping

# curl -XPOST http://localhost:9200/index/fulltext/_mapping -H 'Content-Type:application/json' -d'
{
        "properties": {
            "content": {
                "type": "text",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word"
            }
        }
}'

**7.**索引一些文档

# curl -XPOST http://localhost:9200/index/fulltext/1 -H 'Content-Type:application/json' -d'
{"content":"美国留给伊拉克的是个烂摊子吗"}'
 
# curl -XPOST http://localhost:9200/index/fulltext/2 -H 'Content-Type:application/json' -d'
{"content":"公安部:各地校车将享最高路权"}'
 
# curl -XPOST http://localhost:9200/index/fulltext/3 -H 'Content-Type:application/json' -d'
{"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}'

**8.**搜索

# curl -XPOST http://localhost:9200/index/fulltext/_search  -H 'Content-Type:application/json' -d'
{
    "query" : { "match" : { "content" : "中国" }},
    "highlight" : {
        "pre_tags" : ["<tag1>", "<tag2>"],
        "post_tags" : ["</tag1>", "</tag2>"],
        "fields" : {
            "content" : {}
        }
    }
}'

-   索引收缩
索引的分片数是不可更改的,如要减少分片数可以通过收缩方式收缩为一个新的索引。新索引分片数必须是原分片数的因子值,如原分片数是8,则新索引分片数可以为4、2、1 。

收缩流程

  • 先把所有主分片都转移到一台主机上;
  • 在这台主机上创建一个新索引,分片数较小,其他设置和原索引一致;
  • 把原索引的所有分片,复制(或硬链接)到新索引的目录下;
  • 对新索引进行打开操作恢复分片数据;(可选)重新把新索引的分片均衡到其他节点上。

a) 收缩前准备工作
将原索引设置为只读;将原索引各分片的一个副本重分配到同一个节点上,并且要是健康绿色状态。

PUT /my_source_index/_settings
{
"settings": {
    "index.routing.allocation.require._name": "shrink_node_name",
    "index.blocks.write": true
  }
}

b) 进行收缩

POST my_source_index/_shrink/my_target_index
{
"settings": {
    "index.number_of_replicas": 1,
    "index.number_of_shards": 1,
    "index.codec": "best_compression"
}}

c) 监控收缩过程

GET _cat/recovery?v
GET _cluster/health

-   Split Index 拆分索引
当索引的分片容量过大时,可以通过拆分操作将索引拆分为一个倍数分片数的新索引。能拆分为几倍由创建索引时指定的index.number_of_routing_shards 路由分片数决定。这个路由分片数决定了根据一致性hash路由文档到分片的散列空间。如index.number_of_routing_shards = 30 ,指定的分片数是5,则可按如下倍数方式进行拆分:
5 → 10 → 30 (split by 2, then by 3)
5 → 15 → 30 (split by 3, then by 2)
5 → 30 (split by 6)
**注意:**只有在创建时指定了index.number_of_routing_shards 的索引才可以进行拆分,ES7开始将不再有这个限制。
a) 准备一个索引来做拆分

PUT my_source_index
{
    "settings": {
        "index.number_of_shards" : 1,
        "index.number_of_routing_shards": 2  
    }
}

b) 设置索引只读

PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
  }
}

c) 监控拆分过程

GET _cat/recovery?v
GET _cluster/health

-   别名滚动
对于有时效性的索引数据,如日志,过一定时间后,老的索引数据就没有用了。我们可以像数据库中根据时间创建表来存放不同时段的数据一样,在ES中也可用建多个索引的方式来分开存放不同时段的数据。比数据库中更方便的是ES中可以通过别名滚动指向最新的索引的方式,让你通过别名来操作时总是操作的最新的索引。

ES的rollover index API 让我们可以根据满足指定的条件(时间、文档数量、索引大小)创建新的索引,并把别名滚动指向新的索引。
-  Rollover Index 示例
-  创建一个名字为logs-0000001 、别名为logs_write 的索引

PUT /logs-000001
{
    "aliases": {
        "logs_write": {}
    }
}

-  如果别名logs_write指向的索引是7天前(含)创建的或索引的文档数>=1000或索引的大小>= 5gb,则会创建一个新索引 logs-000002,并把别名logs_writer指向新创建的logs-000002索引

# Add > 1000 documents to logs-000001
 
POST /logs_write/_rollover
{
    "conditions": {
        "max_age":  "7d",
        "max_docs":  1000, 
        "max_size": "5gb"
    }
}

-  Rollover Index 新建索引的命名规则
如果索引的名称是-数字结尾,如logs-000001,则新建索引的名称也会是这个模式,数值增1。
如果索引的名称不是-数值结尾,则在请求rollover api时需指定新索引的名称:

POST /my_alias/_rollover/my_new_index_name
{
    "conditions": {
        "max_age":  "7d",
        "max_docs":  1000,
        "max_size": "5gb"
    }
}

-  在名称中使用Date math(时间表达式)
如果你希望生成的索引名称中带有日期,如logstash-2016.02.03-1 ,则可以在创建索引时采用时间表达式来命名:

# PUT /<logs-{now/d}-1> with URI
encoding:
 
PUT /%3Clogs-%7Bnow%2Fd%7D-1%3E
{
"aliases": {
    "logs_write": {}
  }
}
 
PUT logs_write/_doc/1
{
    "message": "a dummy log"
}
POST logs_write/_refresh
 
 
# Wait for a day to pass
POST /logs_write/_rollover
{
    "conditions": { 
        "max_docs":  "1"
    }
}

**注意:**rollover是你请求它才会进行操作,并不是自动在后台进行的。你可以周期性地去请求它。

-   路由
1. 集群组成

集群元信息
Cluster-name:ess
Nodes:
     node1   10.0.1.11   master
     node2   10.0.1.12
     node3   10.0.1.13 
Indics:
    s0:
          shard0:
                 primay: 10.0.1.11
                 rep:10.0.1.13
    ……

2. 创建索引的流程

PUT s1
{
    "settings" : {
        "index" : {
                "number_of_shards": 3,
                "number_of_replicas": 1    
        }
    }
}

1. 请求node3创建索引
2. node3请求转发给master节点
3. 选择节点存放分片、副本,记录元信息
4. 通知给参与存放索引分片、副本的节点从节点,创建分片、副本
5. 参与节点向主节点反馈结果
6. 等待时间到了,master向node3反馈结果信息,node3响应请求。
7. 主节点将元信息广播给所有从节点。

3. 节点故障

集群元信息
Cluster-name:ess
Nodes:
     node1  10.0.1.11   master 故障
     node2   10.0.1.12   master
     node3   10.0.1.13  
Indics:
    s0:
          shard0:
                 primay:10.0.1.12
                 rep:10.0.1.13
……

节点数据自动重新分配

4. 索引文档
索引文档的步骤:
1. node2计算文档的路由值得到文档存放的分片(假定路由选定的是分片0)。
2. 将文档转发给分片0的主分片节点 node1。
**3.**node1索引文档,同步给副本节点node3索引文档。
4. node1向node2反馈结果
5. node2作出响应

5. 搜索
1. node2解析查询。
2. node2将查询发给索引s1的分片/副本(R1,R2,R0)节点
3. 各节点执行查询,将结果发给Node2
4. Node2合并结果,作出响应。

6. 文档如何路由
1. 文档该存到哪个分片上?
决定文档存放到哪个分片上就是文档路由。ES中通过下面的计算得到每个文档的存放分片:
shard = hash(routing) % number_of_primary_shards
routing 是用来进行hash计算的路由值,默认是使用文档id值。我们可以在索引文档时通过routing参数指定别的路由值,在索引、删除、更新、查询中都可以使用routing参数(可多值)指定操作的分片。

POST twitter/_doc?routing=kimchy
{
    "user" : "kimchy", 
    "post_date": "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
强制要求给定路由值
PUT my_index2
{
    "mappings": {
        "_doc": {
            "_routing": {
                    "required": true  
            }
        }
    }
}

2. 关系型数据库中有分区表,通过选定分区,可以降低操作的数据量,提高效率。在ES的索引中能不能这样做?
可以:通过指定路由值,让一个分片上存放一个区的数据。如按部门存放数据,则可指定路由值为部门值。

十一、Elasticserach性能优化

1.  硬件选择
目前公司的物理机机型在CPU和内存方面都满足需求,建议使用SSD机型。原因在于,可以快速把 Lucene 的索引文件加载入内存(这在宕机恢复的情况下尤为明显),减少 IO 负载和 IO wait以便CPU不总是在等待IO中断。建议使用多裸盘而非raid,因为 ElasticSearch 本身就支持多目录,raid 要么牺牲空间要么牺牲可用性。

2. 系统配置
ElasticSearch 理论上必须单独部署,并且会独占几乎所有系统资源,因此需要对系统进行配置,以保证运行 ElasticSearch 的用户可以使用足够多的资源。生产集群需要调整的配置如下:
1. 设置 JVM 堆大小;
2. 关闭 swap;
3. 增加文件描述符;
4. 保证足够的虚存;
5. 保证足够的线程;
6. 暂时不建议使用G1GC;

3. 设置 JVM 堆大小
ElasticSearch 需要有足够的 JVM 堆支撑索引数据的加载,对于公司的机型来说,因为都是大于 128GB 的,所以推荐的配置是 32GB(如果 JVM 以不等的初始和最大堆大小启动,则在系统使用过程中可能会因为 JVM 堆的大小调整而容易中断。 为了避免这些调整大小的暂停,最好使用初始堆大小等于最大堆大小的 JVM 来启动),预留足够的 IO Cache 给 Lucene(官方建议超过一半的内存需要预留)。

4. 关闭 swap & 禁用交换
必须要关闭 swap,因为在物理内存不足时,如果发生 FGC,在回收虚拟内存的时候会造成长时间的 stop-the-world,最严重的后果是造成集群雪崩。公司的默认模板是关闭的,但是要巡检一遍,避免有些机器存在问题。设置方法:

Step1. root 用户临时关闭
# swapoff -a
# sysctl vm.swappiness=0

Step2. 修改 /etc/fstab,注释掉 swap 这行
Step3. 修改 /etc/sysctl.conf,添加:
vm.swappiness = 0

Step4. 确认是否生效
# sysctl vm.swappiness

也可以通过修改 yml 配置文件的方式从 ElasticSearch 层面禁止物理内存和交换区之间交换内存,修改 ${PATH_TO_ES_HOME}/config/elasticsearch.yml,添加:
bootstrap.memory_lock: true

====小提示=
Linux 把它的物理 RAM 分成多个内存块,称之为分页。内存交换(swapping)是这样一个过程,它把内存分页复制到预先设定的叫做交换区的硬盘空间上,以此释放内存分页。物理内存和交换区加起来的大小就是虚拟内存的可用额度。

内存交换有个缺点,跟内存比起来硬盘非常慢。内存的读写速度以纳秒来计算,而硬盘是以毫秒来计算,所以访问硬盘比访问内存要慢几万倍。交换次数越多,进程就越慢,所以应该不惜一切代价避免内存交换的发生。

ElasticSearch 的 memory_lock 属性允许 Elasticsearch 节点不交换内存。(注意只有Linux/Unix系统可设置。)这个属性可以在yml文件中设置。

5. 增加文件描述符
单个用户可用的最大进程数量(软限制)&单个用户可用的最大进程数量(硬限制),超过软限制会有警告,但是无法超过硬限制。 ElasticSearch 会使用大量的文件句柄,如果超过限制可能会造成宕机或者数据缺失。

文件描述符是用于跟踪打开“文件”的 Unix 结构体。在Unix中,一切都皆文件。 例如,“文件”可以是物理文件,虚拟文件(例如/proc/loadavg)或网络套接字。 ElasticSearch 需要大量的文件描述符(例如,每个 shard 由多个 segment 和其他文件组成,以及到其他节点的 socket 连接等)。

设置方法(假设是 admin 用户启动的 ElasticSearch 进程):

# Step1. 修改 /etc/security/limits.conf,添加:
admin soft nofile 65536
admin hard nofile 65536

# Step2. 确认是否生效
su - admin
ulimit -n

# Step3. 通过 rest 确认是否生效
GET /_nodes/stats/process?filter_path=**.max_file_descriptors

6. 保证足够的虚存
单进程最多可以占用的内存区域,默认为 65536。Elasticsearch 默认会使用 mmapfs 去存储 indices,默认的 65536 过少,会造成 OOM 异常。设置方法:

# Step1. root 用户修改临时参数
sudo sysctl -w vm.max_map_count=262144

# Step2. 修改 /etc/sysctl.conf,在文末添加:
vm.max_map_count = 262144

# Step3. 确认是否生效
sudo sysctl vm.max_map_count

7. 保证足够的线程
Elasticsearch 通过将请求分成几个阶段,并交给不同的线程池执行(Elasticsearch 中有各种不同的线程池执行器)。 因此,Elasticsearch 需要创建大量线程的能力。进程可创建线程的最大数量确保 Elasticsearch 进程有权在正常使用情况下创建足够的线程。 这可以通过/etc/security/limits.conf 使用 nproc 设置来完成。设置方法:

修改 /etc/security/limits.d/90-nproc.conf,添加:
admin soft nproc 2048

8. 暂时不建议使用G1GC
已知 JDK 8 附带的 HotSpot JVM 的早期版本在启用 G1GC 收集器时会导致索引损坏。受影响的版本是早于 JDK 8u40 附带的HotSpot 的版本,出于稳定性的考虑暂时不建议使用。

十二、Elasticserach内存优化

ElasticSearch 自身对内存管理进行了大量优化,但对于持续增长的业务仍需进行一定程度的内存优化(而不是纯粹的添加节点和扩展物理内存),以防止 OOM 发生。ElasticSearch 使用的 JVM 堆中主要包括以下几类内存使用:
1. Segment Memory;
2. Filter Cache;
3. Field Data Cache;
4. Bulk Queue;
5. Indexing Buffer;
6. Cluster State Buffer;
7. 超大搜索聚合结果集的 fetch;

1. 减少 Segment Memory
-  删除无用的历史索引。删除办法,使用 rest API

# 删除指定某个索引
DELETE /${INDEX_NAME}

# 删除符合 pattern 的某些索引
DELETE /${INDEX_PATTERN}

-  关闭无需实时查询的历史索引,文件仍然存在于磁盘,只是释放掉内存,需要的时候可以重新打开。关闭办法,使用 rest API

# 关闭指定某个索引
POST /${INDEX_NAME}/_close

# 关闭符合 pattern 的某些索引
POST /${INDEX_PATTERN}/_close

-  定期对不再更新的索引做 force merge(会占用大量 IO,建议业务低峰期触发)force merge 办法,使用 rest API

# Step1. 在合并前需要对合并速度进行合理限制,默认是 20mb,SSD可以适当放宽到 80mb:
PUT /_cluster/settings -d '
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "20mb"
    }
}'
 
# Step2. 强制合并 API,示例表示的是最终合并为一个 segment file:
# 对某个索引做合并
POST /${INDEX_NAME}/_forcemerge?max_num_segments=1
# 对某些索引做合并
POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1

2. Filter Cache
默认的 10% heap 设置工作得够好,如果实际使用中 heap 没什么压力的情况下,才考虑加大这个设置。

3. Field Data Cache
对需要排序的字段不进行 analyzed,尽量使用 doc values(5.X版本天然支持,不需要特别设置)。对于不参与搜索的字段 ( fields ),将其 index 方法设置为 no,如果对分词没有需求,对参与搜索的字段,其 index 方法设置为 not_analyzed。

4. Bulk Queue
一般来说官方默认的 thread pool 设置已经能很好的工作了,建议不要随意去调优相关的设置,很多时候都是适得其反的效果。

5. Indexing Buffer
这个参数的默认值是10% heap size。根据经验,这个默认值也能够很好的工作,应对很大的索引吞吐量。 但有些用户认为这个 buffer 越大吞吐量越高,因此见过有用户将其设置为 40% 的。到了极端的情况,写入速度很高的时候,40%都被占用,导致OOM。

6. Cluster State Buffer
在超大规模集群的情况下,可以考虑分集群并通过 tribe node 连接做到对用户透明,这样可以保证每个集群里的 state 信息不会膨胀得过大。在单集群情况下,缩减 cluster state buffer 的方法就是减少 shard 数量,shard 数量的确定有以下几条规则:
1.  避免有非常大的分片,因为大分片可能会对集群从故障中恢复的能力产生负面影响。 对于多大的分片没有固定限制,但分片大小为 50GB 通常被界定为适用于各种用例的限制;
2.  尽可能使用基于时间的索引来管理数据。根据保留期(retention period,可以理解成有效期)将数据分组。基于时间的索引还可以轻松地随时间改变主分片和副本分片的数量(以为要生成的下一个索引进行更改)。这简化了适应不断变化的数据量和需求;(周期性的通过删除或者关闭历史索引以减少分片)
3.  小分片会导致小分段(segment),从而增加开销。目的是保持平均分片大小在几GB和几十GB之间。对于具有基于时间数据的用例,通常看到大小在 20GB 和 40GB 之间的分片;
4.  由于每个分片的开销取决于分段数和大小,通过强制操作迫使较小的段合并成较大的段可以减少开销并提高查询性能。一旦没有更多的数据被写入索引,这应该是理想的。请注意,这是一个消耗资源的(昂贵的)操作,较为理想的处理时段应该在非高峰时段执行;(对应使用 force meger 以减少 segment 数量的优化,目的是降低 segment memory 占用)
5.  可以在集群节点上保存的分片数量与可用的堆内存大小成正比,但这在 Elasticsearch 中没有的固定限制。 一个很好的经验法则是:确保每个节点的分片数量保持在低于每 1GB 堆内存对应集群的分片在 20-25 之间。 因此,具有 32GB 堆内存的节点最多可以有 600-750 个分片;
6.  对于单索引的主分片数,有这么 2 个公式:节点数 <= 主分片数 *(副本数 + 1) 以及 (同一索引 shard 数量 * (1 + 副本数)) < 3 * 数据节点数,比如有 3 个节点全是数据节点,1 个副本,那么主分片数大于等于 1.5,同时同一索引总分片数需要小于 4.5,因为副本数为 1,所以单节点主分片最适为 2,索引总分片数最适为 6,这样每个节点的总分片为 4;
7.  单分片小于 20GB 的情况下,采用单分片较为合适,请求不存在网络抖动的顾虑;

**小结:**分片不超 20GB,且单节点总分片不超 600。比如互联网区域,每天新建索引(lw-greenbay-online) 1 个分片 1 个副本,3 个月前的历史索引都关闭,3 节点总共需要扛 90 * 2 = 180 个分片,每个分片大约 6 GB,可谓比较健康的状态。

7. 超大搜索聚合结果集的 fetch
避免用户 fetch 超大搜索聚合结果集,确实需要大量拉取数据可以采用 scan & scroll API 来实现。在 ElasticSearch 上搜索数据时,默认只会返回10条文档,当我们想获取更多结果,或者只要结果中的一个区间的数据时,可以通过 size 和 from 来指定。

GET /_search?size=3&from=20

如上的查询语句,会返回排序后的结果中第 20 到第 22 条数据。ElasticSearch 在收到这样的一个请求之后,每一个分片都会返回一个 top22 的搜索结果,然后将这些结果汇总排序,再选出 top22 ,最后取第 20 到第 22 条数据作为结果返回。这样会带来一个问题,当我们搜索的时候,如果想取出第 10001 条数据,那么就相当于每个一分片都要对数据进行排序,取出前 10001 条文档,然后 ElasticSearch 再将这些结果汇总再次排序,之后取出第 10001 条数据。这样对于 ElasticSearch 来说就会产生相当大的资源和性能开销。如果我们不要求 ElasticSearch 对结果进行排序,那么就会消耗很少的资源,所以针对此种情况,ElasticSearch 提供了scan & scroll的搜索方式。

GET /old_index/_search?search_type=scan&scroll=1m 
{
    "query": { "match_all": {}},
    "size":  1000
}

我们可以首先通过如上的请求发起一个搜索,但是这个请求不会返回任何文档,它会返回一个 _scroll_id ,接下来我们再通过这个 id 来从 ElasticSearch 中读取数据:

GET /_search/scroll?scroll=1m 
c2Nhbjs1OzExODpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExOTpRNV9aY1VyUVM4U0 NMd2pjWlJ3YWlBOzExNjpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExNzpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzEyMDpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzE7dG90YWxfaGl0czoxOw==

此时除了会返回搜索结果以外,还会再次返回一个 _scroll_id,当我们下次继续取数据时,需要用最新的 id。

十三、Elasticserach存储优化

1. 关闭不需要的功能
默认情况下 ElasticSearch 会将 indexs 和 doc values 添加到大多数字段中,以便可以搜索和聚合它们。 例如,如果有一个名为 foo 的数字字段,需要运行 histograms 但不需要 filter,则可以安全地禁用映射中此字段的索引:

PUT ${INDEX_NAME}
{
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "integer",
          "index": false
        }
      }
    }
  }
}

text 字段在索引中存储规范化因子以便能够对文档进行评分。 如果只需要在 text 字段上使用 matching 功能,但不关心生成的 score,则可以命令 ElasticSearch 配置为不将规范写入索引:

PUT ${INDEX_NAME}
{
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "text",
          "norms": false
        }
      }
    }
  }
}

text 字段也默认存储索引中的频率和位置。 频率用于计算分数,位置用于运行短语查询(phrase queries)。 如果不需要运行短语查询,可以告诉 ElasticSearch 不要索引位置:

PUT ${INDEX_NAME}
{
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "text",
          "index_options": "freqs"
        }
      }
    }
  }
}

此外,如果不关心计分,则可以配置 ElasticSearch 以仅索引每个 term 的匹配文档。 这样做仍然可以在此字段上进行搜索(search),但是短语查询会引发错误,评分将假定 term 在每个文档中只出现一次。

PUT ${INDEX_NAME}
{
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "text",
          "norms": false,
          "index_options": "freqs"
        }
      }
    }
  }
}

2. 强制清除已标记删除的数据
Elasticsearch 是建立在 Apache Lucene 基础上的实时分布式搜索引擎,Lucene 为了提高搜索的实时性,采用不可再修改(immutable)方式将文档存储在一个个 segment 中。也就是说,一个 segment 在写入到存储系统之后,将不可以再修改。那么 Lucene 是如何从一个 segment 中删除一个被索引的文档呢?简单的讲,当用户发出命令删除一个被索引的文档#ABC 时,该文档并不会被马上从相应的存储它的 segment 中删除掉,而是通过一个特殊的文件来标记该文档已被删除。当用户再次搜索到 #ABC 时,Elasticsearch 在 segment 中仍能找到 #ABC,但由于 #ABC 文档已经被标记为删除,所以Lucene 会从发回给用户的搜索结果中剔除 #ABC,所以给用户感觉的是 #ABC 已经被删除了。

Elasticseach 会有后台线程根据 Lucene 的合并规则定期进行 segment merging 合并操作,一般不需要用户担心或者采取任何行动。被删除的文档在 segment 合并时,才会被真正删除掉。在此之前,它仍然会占用着JVM heap和操作系统的文件cach 等资源。在某些情况下,需要强制 Elasticsearch 进行 segment merging,已释放其占用的大量系统资源。

POST /${INDEX_NAME}/_forcemerge?max_num_segments=1&only_expunge_deletes=true&wait_for_completion=true
POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1&only_expunge_deletes=true&wait_for_completion=true

Force Merge 命令可强制进行 segment 合并,并删除所有标记为删除的文档。Segment merging 要消耗 CPU,以及大量的 I/O 资源,所以一定要在 ElasticSearch 集群处于维护窗口期间,并且有足够的 I/O 空间的(如:SSD)的条件下进行;否则很可能造成集群崩溃和数据丢失。

3. 减少副本数
最直接的存储优化手段是调整副本数,默认 ElasticSearch 是有 1 个副本的,假设对可用性要求不高,允许磁盘损坏情况下可能的数据缺失,可以把副本数调整为0,操作如下:

PUT  /_template/${TEMPLATE_NAME}
{
 
  "template":"${TEMPLATE_PATTERN}",
  "settings" : {
    "number_of_replicas" : 0
  },
  "version"  : 1
}

其中 T E M P L A T E _ N A M E 表示模板名称,可以是不存在的,系统会新建。 {TEMPLATE\_NAME} 表示模板名称,可以是不存在的,系统会新建。 TEMPLATE_NAME表示模板名称,可以是不存在的,系统会新建。{TEMPLATE_PATTERN} 是用于匹配索引的表达式,比如 lw-greenbay-online-*。

与此相关的一个系统参数为:index.merge.scheduler.max_thread_count,默认值为 Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),这个值在 SSD 上工作没问题,但是 SATA 盘上还是使用 1 个线程为好,因为太多也来不及完成。

# SATA 请设置 merge 线程为 1
PUT  /_template/${TEMPLATE_NAME}
{
  "template":"${TEMPLATE_PATTERN}",
  "settings" : {
    "index.merge.scheduler.max_thread_count": 1
  },
  "version"  : 1
}

4. 请勿使用默认的动态字符串映射
默认的动态字符串映射会将字符串字段索引为文本(text)和关键字(keyword)。 如果只需要其中的一个,这样做无疑是浪费的。 通常情况下,一个 id 字段只需要被索引为一个 keyword,而一个 body 字段只需要被索引为一个 text 字段。可以通过在字符串字段上配置显式映射或设置将字符串字段映射为文本(text)或关键字(keyword)的动态模板来禁用此功能。例如下面的模板,可以用来将 strings 字段映射为关键字:

PUT ${INDEX_NAME}
{
  "mappings": {
    "type": {
      "dynamic_templates": [
        {
          "strings": {
            "match_mapping_type": "string",
            "mapping": {
              "type": "keyword"
            }
          }
        }
      ]
    }
  }
}

5. 禁用 _all 字段
_all 字段是由所有字段拼接成的超级字段,如果在查询中已知需要查询的字段,就可以考虑禁用它。

PUT /_template/${TEMPLATE_NAME}
{
  "template": "${TEMPLATE_PATTERN}",
  "settings" : {...},
  "mappings": {
    "type_1": {
      "_all": {
         "enabled": false
       },
      "properties": {...}
   }
  },
  "version"  : 1
}

6. 使用 best_compression
_source 字段和 stored fields 会占用大量存储,可以考虑使用 best_compression 进行压缩。默认的压缩方式为 LZ4,但需要更高压缩比的话,可以通过 inex.codec 进行设置,修改为 DEFLATE,在 force merge 后生效:

# Step1. 修改压缩算法为 best_compression
PUT  /_template/${TEMPLATE_NAME}
{
 
  "template":"${TEMPLATE_PATTERN}",
  "settings" : {
    "index.codec" : "best_compression"
  },
  "version"  : 1
}

# Step2. force merge
POST /${INDEX_NAME}/_forcemerge?max_num_segments=1&wait_for_completion=true
POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1&wait_for_completion=true

7. 使用最优数据格式
我们为数字数据选择的类型可能会对磁盘使用量产生重大影响。 首先,应使用整数类型(byte,short,integer或long)来存储整数,浮点数应该存储在 scaled_float 中,或者存储在适合用例的最小类型中:使用 float 而不是 double,使用 half_float 而不是 float。

PUT /_template/${TEMPLATE_NAME}
{
  "template": "${TEMPLATE_PATTERN}",
  "settings" : {...},
  "mappings": {
    "type_1": {
      "${FIELD_NAME}": {
         "type": "integer"
       },
      "properties": {...}
   }
  },
  "version"  : 1
}

十四、Elasticserach搜索速度优化

1. 避免Join和Parent-Child
Join会使查询慢数倍、 Parent-Child会使查询慢数百倍,请在进行 query 语句编写的时候尽量避免。

2. 映射
某些数据本身是数字,但并不意味着它应该总是被映射为一个数字字段。 通常存储着标识符的字段(如ISBN)或来自另一个数据库的数字型记录,可能映射为 keyword 而不是 integer 或者 long 会更好些。

3. 避免使用 Scripts
之前 Groovy 脚本曝出了很大的漏洞,总的来说是需要避免使用的。如果必须要使用,尽量用 5.X 以上版本自带的 painless 和 expressions 引擎。

4. 根据四舍五入的日期进行查询
根据 timestamp 字段进行的查询通常不可缓存,因为匹配的范围始终在变化。 但就用户体验而言,以四舍五入对日期进行转换通常是可接受的,这样可以有效利用系统缓存。举例说明,有以下查询:

PUT index/type/1
{
  "my_date": "2016-05-11T16:30:55.328Z"
}
 
GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h",
            "lte": "now"
          }
        }
      }
    }
  }
}

可以对时间范围进行替换:

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

在这种情况下,我们四舍五入到分钟,所以如果当前时间是 16:31:29 ,范围查询将匹配 my_date 字段的值在 15:31:00 和16:31:59 之间的所有内容。 如果多个用户在同一分钟内运行包含这个范围的查询,查询缓存可以帮助加快速度。 用于四舍五入的时间间隔越长,查询缓存可以提供的帮助就越多,但要注意过于积极的舍入也可能会伤害用户体验。

为了能够利用查询缓存,建议将范围分割成大的可缓存部分和更小的不可缓存的部分,如下所示:

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {
              "range": {
                "my_date": {
                  "gte": "now-1h",
                  "lte": "now-1h/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gt": "now-1h/m",
                  "lt": "now/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gte": "now/m",
                  "lte": "now"
                }
              }
            }
          ]
        }
      }
    }
  }
}

然而,这种做法可能会使查询在某些情况下运行速度较慢,因为由 bool 查询引入的开销可能会因更好地利用查询缓存而失败。

5. 对只读 indices 进行 force merge
建议将只读索引被合并到一个单独的分段中。 基于时间的索引通常就是这种情况:只有当前时间索引会写入数据,而旧索引是只读索引。

6. 预热 global ordinals
全局序号(global ordinals)是用于在关键字(keyword)字段上运行 terms aggregations 的数据结构。 由于 ElasticSearch 不知道聚合使用哪些字段、哪些字段不使用,所以它们在内存中被加载得很慢。 我们可以通过下面的 API 来告诉 ElasticSearch 通过配置映射来在 refresh 的时候加载全局序号:

PUT index
{
  "mappings": {
    "type": {
      "properties": {
        "foo": {
          "type": "keyword",
          "eager_global_ordinals": true
        }
      }
    }
  }
}

十五、Elasticserach写入性能优化

之前描述了 ElasticSearch 在内存管理方面的优化,接下来梳理下如何对写入性能进行优化,写入性能的优化也和 HBase 类似,无非就是增加吞吐,而增加吞吐的方法就是增大刷写间隔、合理设置线程数量、开启异步刷写(允许数据丢失的情况下)。

1. 增大刷写间隔
通过修改主配置文件 elasticsearch.yml 或者 Rest API 都可以对 index.refresh_interval进行修改,增大该属性可以提升写入吞吐。

PUT  /_template/{TEMPLATE_NAME}
{
  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.refresh_interval" : "30s"
  }
}
 
PUT {INDEX_PAATERN}/_settings
{
    "index.refresh_interval" : "30s"
}

2. 合理设置线程数量
调整 elasticsearch.yml ,对 bulk/flush 线程池进行调优,根据本机实际配置:

threadpool.bulk.type:fixed
threadpool.bulk.size:8 #(CPU核数)
threadpool.flush.type:fixed
threadpool.flush.size:8 #(CPU核数)

3. 开启异步刷写
如果允许数据丢失,可以对特定 index 开启异步刷写:

PUT  /_template/{TEMPLATE_NAME}
{
  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.translog.durability": "async"
  }
}
 
PUT  {INDEX_PAATERN}/_settings
{
  "index.translog.durability": "async"
}

十六、Elasticserach审计优化

1. 开启慢查询日志
不论是数据库还是搜索引擎,对于问题的排查,开启慢查询日志是十分必要的,ElasticSearch 开启慢查询的方式有多种,但是最常用的是调用模板 API 进行全局设置:

PUT  /_template/{TEMPLATE_NAME}
{
 
  "template":"{INDEX_PATTERN}",
  "settings" : {
    "index.indexing.slowlog.level": "INFO",
    "index.indexing.slowlog.threshold.index.warn": "10s",
    "index.indexing.slowlog.threshold.index.info": "5s",
    "index.indexing.slowlog.threshold.index.debug": "2s",
    "index.indexing.slowlog.threshold.index.trace": "500ms",
    "index.indexing.slowlog.source": "1000",
    "index.search.slowlog.level": "INFO",
    "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"
  },
  "version"  : 1
}

对于已经存在的 index 使用 settings API:

PUT {INDEX_PAATERN}/_settings
{
    "index.indexing.slowlog.level": "INFO",
    "index.indexing.slowlog.threshold.index.warn": "10s",
    "index.indexing.slowlog.threshold.index.info": "5s",
    "index.indexing.slowlog.threshold.index.debug": "2s",
    "index.indexing.slowlog.threshold.index.trace": "500ms",
    "index.indexing.slowlog.source": "1000",
    "index.search.slowlog.level": "INFO",
    "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"
}

这样,在日志目录下的慢查询日志就会有输出记录必要的信息了。

十七、ElasticSearch运维手册

在管理es集群时,我们可以直接向es安装所在服务器9200端口(默认端口)发送请求查看查询结果。也可使用Cerebro可视化管理工具对es进行管理。

1. ElasticSearch管理工具
通过 GET 请求发送 cat 命名可以列出所有可用的cat API,我们可以使用postman或者浏览器发送请求到es的9200端口。

查询结果如下,请求返回了所有可用的cat API

又或者可以使用Cerebro可视化管理工具对es进行管理。比如我的管理工具访问地址http://172.16.60.14:9002/#/connect

如下图所示,进入到可视化管理界面以后,选择顶部导航菜单more,在下拉选项框中选择cat apis。

进入cat api查询页面

2. 常用cat API介绍

最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

资料预览

给大家整理的视频资料:

给大家整理的电子书资料:

如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

owlog.source": “1000”,
“index.search.slowlog.level”: “INFO”,
“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”
}



这样,在日志目录下的慢查询日志就会有输出记录必要的信息了。


**十七、ElasticSearch运维手册**


在管理es集群时,我们可以直接向es安装所在服务器9200端口(默认端口)发送请求查看查询结果。也可使用Cerebro可视化管理工具对es进行管理。


**1. ElasticSearch管理工具**  
通过 GET 请求发送 cat 命名可以列出所有可用的cat API,我们可以使用postman或者浏览器发送请求到es的9200端口。


[外链图片转存中...(img-Sldi6JQ5-1715334510473)]


查询结果如下,请求返回了所有可用的cat API


[外链图片转存中...(img-zfNqS5XI-1715334510473)]


又或者可以使用**Cerebro可视化管理工具**对es进行管理。比如我的管理工具访问地址http://172.16.60.14:9002/#/connect


[外链图片转存中...(img-3NoSYvgQ-1715334510474)]


如下图所示,进入到可视化管理界面以后,选择顶部导航菜单more,在下拉选项框中选择cat apis。


[外链图片转存中...(img-5kPg7b7d-1715334510474)]


进入cat api查询页面


[外链图片转存中...(img-kbvDHm0K-1715334510474)]


[外链图片转存中...(img-10Jq6yNX-1715334510474)]


**2. 常用cat API介绍**


### 最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

### 资料预览

给大家整理的视频资料:

[外链图片转存中...(img-GA5Nb387-1715334510475)]

给大家整理的电子书资料:

  

[外链图片转存中...(img-7hOXeLoE-1715334510475)]



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 14
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值