本章内容
如何选择正确的目录实现,使得ElasticSearch能够以高效的方式访问底层I/O系统。
如何配置发现模块来避免潜在的问题。
如何配置网关模块以适应我们的需求。
恢复模块能带来什么,以及如何更改它的配置。
如何查看段信息。
ElasticSearch的缓存是什么样的,它的职责是什么,如何使用以及更改它的配置。
5.1 选择正确的目录实现-存储模块
存储模块是一个在配置集群时容易被忽视的模块,然而它非常重要。该模块允许用户控制索引的存储方式,例如,可以持久化存储(存储在磁盘上)或非持久化存储(存储在内存中)。
存储类型
ElasticSearch提供了4种可用的存储类型。通过index.store.type属性进行设置:
- 简单文件系统存储(simplefs)
最简单的目录类的实现,它使用一个随机读写文件(Java RandomAccessFile)进行文件操作,并与Apache Lucene的SimpleFSDirectory类对应。对于简单的应用来说它是够用的,但瓶颈主要是在多线程访问上,即性能非常差。 - 新I/O文件系统存储(niofs)
该存储类型使用基于java.nio.FileChannel 的目录实现,与Apache Lucene的NIOFSDirectory类对应。该实现允许多个线程在不降低性能的前提下访问同一个文件。如果想使用这个存储类型,需要将index.store.type属性设为niofs - MMap文件系统存储(mmapfs)
该存储类型使用了Apache Lucene的MMapDirectory 实现。它使用mmap系统命令来读取和随机写人文件,并从进程的虚拟地址空间的可用部分中分出与被映射文件大小相同的空间,用于装载被映射文件。它没有任何锁机制,因此非常适合多线程访问。
需要注意的是,MM ap文件系统存储在64位环境下工作最佳,对于32位系统,只有你确信索引足够小,且虚拟地址空间足够大时才可以使用。 -
内存存储(memory)
内存存储是唯一一个不是基于Apache Lucene目录的存储类型,它允许我们把全部索引都保存在内存中,因此文件并没有存储在硬盘上。
当使用内存存储类型(memory)时,我们也能在一定程度上控制缓存,这一点非常重要。注意以下设置都是节点级别的:
cache.memory.direct:定义内存存储是否应该被分配到Java虚拟机堆内存之外,默认为true。一般情况下应该保持为默认值,从而能避免堆内存过载。
cache.memory.small_buffer_size:定义小缓冲区的大小,默认值是1KB。小缓冲区是用来容纳段(segment )信息和已删除文档信息的内部内存结构。
cache.memory.large_buffer_size:定义大缓冲区的大小,默认值是1MB。大缓冲区是用来容纳除段信息和已删除文档信息外的索引文件的内部内存结构。
cache.mernory.small_cache_size:定义小缓存的大小,默认值是10MB。小缓存是用来缓存段信息和已删除文档信息的内部内存结构。
cache.memory.large_cahce_size:定义大缓存的大小,默认值是500MB。大缓存是用来缓存除段信息和已删除文档信息外的索引文件的内部内存结构。为为知笔记建立本地索引,使用内存存储是很不错的选择。
-
默认存储类型
ElasticSearch默认使用基于文件系统的存储类型。虽然针对不同的操作系统往往会选择不同的存储类型,但终究都使用了基于文件系统的存储类型。例如,ElasticSearch在32位的Windows系统上使用simplefs类型,在Solaris和64位的Windows系统上使用mmapfs,其他系统则使用niofs。
5.2 发现模块的配置
5.2.1 Zen发现
Zen发现(Zen discovery)是ElasticSearch自带的默认发现机制。Zen发现默认使用 多播来发现其他的节点。
有时多播会由于各种原因而失效,或者在一个大型集群中使用多播发现会产生大量不 必要的流量,这可能都是不想使用多播的合理理由。在这些情况下,Zen发现使用了第二种发现方法:单播模式。
多播
前面提到过,多播(Multicast)这是ElasticSearch的默认模式。当节点还没有加人任何集群时(如节点刚刚启动或重启),它会发出一个多播的ping请求,这相当于通知所有可见的节点和集群,它已经可用并准备好加入集群了。
Zen发现模块的多播部分有如下设置:
- discovery.zen.ping.multicast.address:通信接口,可赋值为地址或接口名。默认值是 所有可用接口。
- discovery.zen.ping.multicast.port:通信端口,默认为54328。
- discovery.zen.ping.multicast.group:代表发送多播消息的地址,默认为224.2.2.4。
- discovery.zen.ping.multicast.buffer_size:缓冲区大小,默认为2048
- discovery.zen.ping.multicast.ttl:定义多播消息的生存期,默认是3。每次包通过路 由时,TTL就会递减。这样可以限制广播接收的范围。请注意,路由数的阈值设置可参考TTL的值,但要确保TTL的值不能恰好等于数据包经过的路由数。
- discovery.zen.ping.multicast.enabled;默认是true。如果你打算使用单播方式而需要 关闭多播时,可将其设置为false。
单播
像前面描述的那样关闭了多播后,你就可以安全地使用单播(Unicast)了。当节点不是集群中的一部分时(如刚刚重启,启动或由于某些故障脱离集群),它会发送一个ping请求给配置文件所指定的那些地址,通知所有的节点它准备好要加人集群了。
单播的配置非常简单,如下所示:
- discovery.zen.ping.unictas.hosts:代表集群中的初始节点列表,可称之为一个列表或主 机数组。每个主机可以指定一个名称(或者IP地址),还可以追加一个端口或端口范 围。例如,属性值可以是这样:["master1", "master2:8181", "master3[80000-81000]"]。
一般来说,单播发现的主机列表不需要是集群中所有ElasticSearch节点的完整列 表,因为新节点一旦与列表中任何一个节点相连,就会知晓组成集群的其他全部节点的信息。
- discovery.zen.ping.unicast.concurrent_connects:定义单播发现使用的最大并发连接 数。默认是10个。
最小主节点数
对发现模块来说,一个最重要的属性是discovery.zen.minimum_master_nodes属性。它 允许我们设置构建集群所需的最小主节点(master node)候选节点数。这让我们避免了由于某些错误(如网络问题)而出现令人头疼的局面(即多个集群同名)。
- discovery.zen. minimum_master_nodes:设置为大于等于集群节点数的一半加1
Zen发现错误检测
ElasticSearch在工作中执行两个检测流程。第一个流程是由主节点向集群中其他节点 发送ping请求来检测它们是否工作正常。第二个流程刚好相反,由每个节点向主节点发送请求来验证主节点是否正在运行并能履行其职责。然而,如果网络速度很慢,或者节点部署在不同的地点,那么默认的配置也许就不合适了。
因此ElasticSearch的发现模块提供了以下可以修改的设置:
- discovery.zen.fd.ping_interval:设置节点向目标节点发送ping请求的频率,默认1秒。
- discovery.zen.fd.ping_timeout:设置节点等待ping请求响应的时长,默认30秒。如 果节点使用率达到100%或者网速很慢,可以考虑增大该属性值。
- discovery.zen.fd.ping_retries:设置当目标节点被认为不可用之前ping请求的重试次 数,默认为3次。如果网络丢包比较严重,可以考虑增大该属性值,或者修复你的网络。
5.2.2 亚马逊EC2发现
可配置的属性
ElasticSearch 的节点可以扮演不同的角色,它们可以作为数据节点(存储数据的节点),也可以作为主节点,其中主节点(一个集群中只有一个)除了处理查询请求外,还负责集群管理。当然节点也可以配置为既不是主节点也不是数据节点,在这种情形下,该节点将只作为执行用户查询的聚合节点。ElasticSearch默认每个节点都是数据节点和候选主节点,但是这是可以改变的。为了取消某节点的主节点候选资格,你需要在elasticsearch.yml文件中将node.master属性设为false。为了让某节点成为非数据节点,你需要在elasticsearch.yml文件中将node.data属性设为false。
除此之外,ElasticSearch还允许我们使用下面的属性来控制网关模块的行为:
- gateway.recover_after_nodes:该属性为整数类型,表示要启动恢复过程集群中所需 要的节点数。例如,当该属性值为5时,如果要启动恢复过程,集群中就至少要有5个节点(无论它们是候选主节点还是数据节点)存在。
- gateway.recover_after_data_nodes:该属性允许我们设置当恢复过程启动时,集群中 需要存在的数据节点数。
- gateway.recover_after_master_nodes:该属性允许我们设置当恢复过程启动时,集群 中需要存在的候选主节点数。
- gateway.recover_after_time:该属性允许我们设置在条件满足后,启动恢复过程前 需要等待的时间。 (如果我们希望延迟恢复过程直到所有数据节点处于可用状态后至少3分钟才开始 )
5.2.3 本地网关
随着Elasticsearch 0.2。版(以及0.19的某些版本)的发布,除了默认的本地类型,其他类型的网关都已弃用,并建议不再使用,因为在新版的Elasticsearch中,它们都会被移除。如果要避免重新索引全部数据,那么你应当使用本地网关类型,这也是为什么我们不讨论其他网关类型的原因。
本地网关类型使用节点上可用的本地存储
来保存元数据、映射和索引。为了使用本地网关,需要有充足的磁盘空间来容纳数据(数据全部写人磁盘,而非保存在内存缓存中)。
本地网关的持久化不同于其他当前存在(但是已经弃用)的网关类型。向本地网关的写操作是以同步的方式
进行的,以确保在写人过程中没有数据丢失。
默认
gateway.type=local
备份本地网关
例如当升级集群时,希望出错后能够进行回滚。为了实现这个目的,你需要执行下面的操作:
- 停止向ElasticSearch集群索引数据(这意味着停止:fiver或其他向ElasticSearch发 送数据的外部应用)。
- 使用清空(Flush ) API清空所有尚未索引的数据。
- 为分配在集群中的每个分片创建至少一个备份,这至少可以保证一旦发生问题能找 回数据。然而,如果你希望操作能尽可能的简单,那么可以拷贝集群中每个数据节点上的完整数据目录。
5.2.4 恢复配置
集群级的恢复配置
恢复配置大多针对的是集群级别,它允许我们设置恢复模块使用的通用规则,可设置 以下属性:
- indices.recovery.concurrent_streams:这个属性指定了从分片源恢复分片时允许打开 的并发流的数量,默认是3。较大的值会给网络层带来更大的压力,但恢复过程会更快,这依赖于网络的使用情况和吞吐量。
- indices.recovery.max_bytes_per_sec:这个属性指定了在分片恢复过程中每秒传输 数据的最大值,默认是20MB。如果想取消数据传输限制,需要把这个属性设为0。与并发流属性类似,该属性允许我们控制恢复过程中网络的使用。把它设为较大的值会带来较高的网络利用率,而且恢复过程会更快。
- indices.recovery.compress:这个属性默认为true,用来指定ElasticSearch是否在恢 复过程中压缩传输的数据。设为false可以降低CPU的压力,但同样会导致更多的网络数据传输。
- indices.recovery.file_chunk_size:这个属性指定从源分片向目标分片拷贝数据时数 据块(chunk)的大小。默认值为512KB而如果将indices.recovery.compress属性设为true的话,该值也会被压缩。
- indices.recovery.translog_ops:这个属性值默认为1000,指定在恢复过程中分片间 传输数据时,单个请求里最多可以传输多少行事务日志。
- indices.recovery.translog_size:这个属性指定从源分片拷贝事务日志时使用的数据 块的大小。默认值为512KB,且如果indices.recovery.compress属性设为true的话, 该值还会被压缩。
Note
所有前面提到过的设置都可以通过集群的更新API来更新,或者在elasticsearch.yml文 件里设置。
5.3 索引段统计
5.3.1 segments API简介
为了深人观察Lucene索引段,ElasticSearch提供了segments API,我们可以通过向 _segments REST端点发送HTTP GET请求来访问它。例如,要查看集群中所有索引的所有段信息,应当执行下面的命令:
curl -XGET 'localhoat:9200/_segments'
- 指定特定索引mastering
curl -XGET 'localhoat:9200/mastering/_segments'
- 响应示例
5.4 理解ElasticSearch缓存
在本节中,我们将重点了解过滤器缓存和字段数据缓存 。
5.4.1 过滤器缓存
过滤器缓存是负责缓存查询中使用的过滤器
的执行结果的。 如以下查询:
过滤器缓存的种类
在ElasticSearch中有两种类型的过滤器缓存:索引级和节点级,即我们可以选择配置索引级或节点级(默认选项)的过滤器缓存。
不建议索引级过滤器缓存
由于我们不一定能预知给定索引会分配到哪里 (实际上是指索引的分片和副本),进而无法预测内存的使用,所以不建议使用索引级的过滤器缓存。
索引级过滤器缓存的配置
ElasticSearch允许我们使用下面的属性来配置索引级过滤器缓存的行为:
- index.cache.filter.type:这个属性设置缓存的类型,我们可以使用resident , soft , weak或node(默认值)。在resident缓存中的记录不能被JVM移除,除非我们想移除它们(通过使用API,设置最大缓存值,或者设置过期时间),并且也是因为这个原因而推荐使用它(填充过滤器缓存代价很高)。内存吃紧时,JVM可以清除soft和weak类型的缓存,区别是在清理内存时,JVM会优先清除weak引用对象,然后才是soft引用对象。最后的node属性代表缓存将在节点级控制(参阅5.4.1节的 第3小节)。
- index.cache.filter.max_size:这个属性指定能存储到缓存中的最大记录数(默认 是-1,代表无限制)。需要注意这个设置不是应用在整个索引上,而是应用于指定索引的某个分片的某个索引段上,所以内存的使用量会因索引的分片数和副本数以及索引中段数的不同而不同。通常来说,结合soft类型,使用默认无限制的过滤器缓存就足够了。谨记慎用某些查询以保证缓存的可重用性。
- index.cache.filter.expire:这个属性指定过滤器缓存中记录的过期时间,默认是-1, 代表永不过期。如果我们希望对过滤器缓存设置超时时长,那么可以设置最大空闲时间。例如,希望缓存在最后一次访问后再过60分钟过期,就应当设置该属性值为60m。
节点级的过滤器缓存配置
节点级过滤器缓存是默认的缓存类型
,它应用于分配到给定节点上的所有分片(设置 index.cache.filter.type属性为node,或者不设置这个属性)。ElasticSearch允许我们使用indices.cache.filter.sixe属性来配置这个缓存的大小,既可以使用百分数。
节点级过滤器缓存是LRU类型(最近最少使用)缓存,这意味着为了给新记录腾出空 间,在删除缓存记录时,使用次数最少的那些会被删除。
5.4.2 字段数据缓存
字段数据缓存在我们的查询涉及切面计算
或基于字段数据排序
时使用。ElasticSearch所做的是加载相关字段的全部数据到内存中,从而使ElasticSearch能够快速地基于文档访问这些值。需要注意的是,从硬件资源的角度来看,构建字段数据缓存代价通常很高,因为字段的所有数据都需要加载到内存中,这需要消耗I/O操作和CPU资源。特别注意高基数的字段(拥有大量不同词项的字段)。
索引级字段数据缓存配置
- index.fielddata.cache.type:属性为resident或soft ,node(默认),跟我们在描述过滤器缓存时讨论过的情形类似 。
不建议使用索引级字段数据缓存
与索引级过滤器缓存类似,我们并不建 议使用它。原因就是很难预测哪个分片或索引会分配到哪个节点上,因此我们无法预估缓存每个索引需要的内存大小,而这会带来内存使用方面的问题。
节点级字段数据缓存配置
- index.fielddata.cache.size:这个属性指定了字段数据缓存的最大值,既可以是一个 百分比的值,如20%,也可以是一个绝对的内存大小,如10GB。
- index.fielddata.cache.expire:这个属性指定字段数据缓存中记录的过期时间,默认 值为-1,表示缓存中的记录永不过期。
过滤
除了前面提到的配置项以外,ElasticSearch还允许我们选择性地将某些字段值加载到 字段数据缓存中。这在某些情况下非常有用,尤其是在做基于字段数据排序或切面计算时。 ElasticSearch支持两种类型三种形式的字段数据过滤,即基于词频、基于正则表达式,以及基于两者的组合。
为了引人字段数据缓存过滤信息,需要在映射文件的字段定义部分额外添加两个对象: fielddata对象及其子对象filter。
基于词频过滤
- min/max: 基于词频过滤的结果是只加载那些频率高于指定最小值且低于指定最大值的词项,其 中词频最小值和最大值分别由min和max参数指定。词项的频率范围不是针对整个索引的。
- min_segment_size: 这个属性指定了在构建字段数据缓存时,索引段应满足的最小文档数,小于该文档数的索引段不会被考虑。
例如,只想保存来自容量不小于100的索引段,且词频在段中介于1%和20%之间的 词项到字段数据缓存中,那么可以进行如下字段映射:
{
"book":{
"properties":{
"tag":{
"type":"string",
"index":"not_analyzed",
"fielddata":{
"filter":{
"frequency":{
"min":0.01,
"max":0.2,
"min_segment_size":100
}
}
}
}
}
}
}
基于正则表达式过滤
除了基于词频的过滤,也可以基于正则表达式过滤。这时只有匹配特定正则表达式的 词项会加载到字段数据缓存中。
{
"book":{
"properties":{
"tag":{
"type":"string",
"index":"not_analyzed",
"fielddata":{
"filter":{
"regex":"^#.*"
}
}
}
}
}
}
基于词频过滤和基于正则表达式过滤同时使用
这是一种and的关系。同时符合这两种情况的词项才会被缓存。注意,没有被缓存的词项,在涉及切面计算
或基于字段数据排序
时是查不到的!要特别注意!
查询期间重建字段数据缓存
字段数据缓存虽然不是在索引期间构建的,但却可以在查询期间重建,于是我们可 以在运行时改变过滤行为,并具体通过使用映射API更新fielddata配置节来实现。 然而,需谨记在改变字段数据缓存过滤设置后清空缓存,这可以通过使用清理缓存 API来实现,详情可参考5.4.3节。
5.4.3 清除缓存(_cache端点)
前面已经提到,在改变字段数据过滤以后需要清除缓存,这点很关键。
单一索引缓存、多索引缓存和全部缓存的清除
清空全部缓存的最简单的做法是执行下面的命令:
curl -XPOST 'localhoat:9200/_cache/clear'
- 针对特定索引
curl -XPOST 'localhoat:9200/mastering/_cache/clear'
清除特定缓存
清除缓存除了前面提到的方法,我们也可以只清除一种指定类型的缓存。下面列出的 就是可以被单独清除的缓存类型:
- filter:这类缓存可以通过设置filter参数为true来清除。反之为了避免清除缓存, 需要设置filter参数为false。
- field_data:这类缓存可以通过设置field data参数为true来清除。反之为了避免清 除这种缓存,需要设置field data参数为false。
- bloom:为了清除bloom缓存(如果某种倒排索引格式中使用了Bloom_filter,则可 能会使用这种缓存,参考3.3节),bloom参数需要设置为true。反之为了避免清除这种缓存,需要设置bloom参数为false。
例如,要清除mastering索引的字段数据缓存,并保留filter缓存和bloom缓存,则可 以执行下面的命令:
curl -XPOST 'localhost:9200/mastering/_cache/clear?field_data=true&filter=false&bloom=false'
清除字段相关的缓存
除了清除全部或特定的缓存,我们还可以清除指定字段的缓存。为了实现这个,我 们需要的请求中增加fields参数,参数值为所要清除缓存的相关字段名,多个字段名用逗号分隔。例如,要清除mastering索引里title和price字段的缓存:
curl -XPOST 'localhost:9200/mastering/_cache/clear?fields=title,price'