1. 提前规划indices, shards和cluster state的增长趋势
在ES中创建indices和shards非常简单, 但需要记住的是每个indiex和shard都有相应的资源开销。如果有太多的indices和shards, 单单是管理上的开销就可能大大降低ES集群性能, 甚至极端场景下使服务不可用。
管理系统开销影响最大的因素是cluster state,包含了集群中每个索引的mappings
信息,如果信息过大,会出现集群虽然存活,但是已处于不可用的状态的情况。
下面我们通过一些数据来感受下其中发生的事情。
假设有一个索引,,其mappings
大小为50K(大约有700个字段).。如果每小时生成一个索引,,那么一天下来将会有24 x 50K的cluster state数据增量,,大约是1.2MB。 如果系统中保存了1年的数据,,cluster state信息将达到438MB(8760个indices, 53800个shards).。如果每天一个索引的话,cluster state信息会减少到18.25MB(365个indices, 1825个shards)。 可以看到,每小时一个索引会置于一个完全不同的处境。
如果系统中有实时索引数据的需求,,最好先做些规划,,并清楚的意识到系统中会存储多少cluster state信息以及将包含多少indices和shards。 在部署到生产环境之前,,应该先多做些测试和演练, 避免在凌晨3点因集群不可用而被叫起。
在集群配置方面,,为避免把自己置于险境,,需要对系统中能容纳的indices和shards数量有全面的掌控。
2. 配置之前,先认识集群拓扑结构
设置节点为master或data节点由以下两个参数的值来决定:
Master node: node.master:true node.data:false
Data node: node.master:false node.data:true
Client node: node.master:false node.data:false
上面的部分比较简单,下面开始介绍一些需要着重注意的高级属性.。对于大部分系统来说,,ES的默认配置已经足够,,但如果使用场景正如我们经常看到的日志类系统, 请继续向下看。
3. 设置mlockall是提升性能的最有效手段
Linux把它的物理内存划分为很多块,称为页。 而Swapping则是把内存中的一页复制到磁盘上预定义空间的过程, 以释放更多的内存页,,而磁盘上的这部分空间称为交换区。 物理内存和交换区空间的总和称为虚拟内存空间。
交换区并不是在所有情况下都是有用的, 因为和内存相比, 磁盘总是慢太多。 通常内存的存储速度在纳秒级,,而磁盘却要毫秒级别。所以磁盘的访问速度比直接访问内存要慢很多, 使用的交换空间越多, 系统越慢,所以要避免交换区的使用。
mlockall
参数允许设置ES节点不换出内存页(只有Linux/Unix系统才有此设置)。 在yaml文件中, 可通过如下方式设置:
bootstrap.mlockall:true
在5.x版本中, 该参数被bootstrap.memory_lock:true
所代替。
默认mlockall
的值为false
, 意味着ES节点的内存被允许换出.。设置该属性值后,需要重启ES节点才能生效.。可以通过如下访问进行验证设置是否成功:
curl http://localhost:9200/_nodes/process?pretty
同时要注意,如果设置了mlockall
为true
, 要确认通过-DXmx
或ES_HEAP_SIZE
给ES设置了足够的堆空间。
4. 通过discovery.zen控制ES的节点发现管理
Zen discovery
是ES集群中节点发现连接的默认机制,另外还有一些其他的发现机制,如Azure, EC2和GCE。 Zen discovery
通过discovery.zen.*
的一系列参数进行设置和控制。
首先,需要通过discovery.zen.ping.unicast.hosts
参数指定一组用于发现和连接节点的hosts。 为了简单, 可以为集群中的每个节点设置相同的值。
discovery.zen.minimum_master_nodes
参数用于控制最小的合理master
节点数,使得集群中其他节点可被发现和操作.。通常, 在多于2个节点的集群中建议该参数设置的值不小于2。另外一种计算方式是(master节点数/2 + 1)。
Data节点和master节点之前有两种检测方式:
- master向所有其他节点发起ping请求,以确认该节点是否存活;
- 其他的节点向master节点发现ping请求,以确认master是否存活,并决定是否需要开始新一轮的选举;
节点检测过程由discovery.zen.fd.ping_timeout
参数设置, 默认值为30s,决定了一个发起ping请求的节点的响应等待时间。 如果集群带宽不足或网络拥堵,则需要合理的重新调整该参数。如果网络较差,该参数要相应的设置大一些, 值越大,节点发现的失败的风险也就越低。
5. 提防"DELETE_all"
ES的DELETE API允许通过一个请求(使用通配符或_all)删除所有的索引数据,如下:
curl -XDELETE 'http://localhost:9200/*/'
curl -XDELETE 'http://localhost:9200/_all'
虽然这个功能很强大,却也极为危险,特别是在生产环境。 推荐在集群中,通过action.destructive_requires_name:true
参数禁用了该删除功能。
6. 使用Doc Values
在ES2.0及以上版本中,Doc Values
是默认使用的。Doc Values
通过少量额外的索引和磁盘开销,提供了比在normal
字段上更高效的排序和聚合操作。本质上, Doc Values
通过把ES转变为列式存储, 进而使得ES大量的分词特性比预想的更高效。
为了深入理解Doc Values
带来的好处,下面将把Doc Values
与normal
字段进行对比。
当在normal
字段上进行排序或聚合操作时,将导致大量的fielddata cache
。因为当字段第一次被缓存时,ES需要为该字段每个可能的取值分配大量的堆空间,并从每个文档中获取字段值数据。因为这个过程可能需要从磁盘中读取数据,将会十分耗时。一旦数据缓存完成,以后再对该字段值的使用都会使用先前缓存的数据,所以速度也会更快。但当有过多的字段被载入到缓存中时,就会触发缓存淘汰机制,一些字段将被汰出, 相应的再次使用被汰出的字段时,就是又一次的耗时载入过程。为了高效,尽可能减少或降低缓存汰,这意味着要减少或限制将被缓存的字段数量。
与之不同,Doc Values
使用基于磁盘的数据结构,并映射到进程的内存空间,从而减少对堆空间的占用,并具有与fielddata cache
相匹敌的性能。虽然在数据第一次从硬盘读取并载入时依然会有起始开销,然而这些都由操作系统的文件系统缓存进行处理,所以只有真正需要的数据才会被读入。
简而言之,Doc Values
减少了堆空间使用(相应的降低了GC影响),并通过文件系统缓存减少读取的数据,从而提高了整体性能。
7. ES shard分配相关的参数设置
shard分配就是把shard分散到不同节点的过程,可以发生在初始化备份阶段,副本分配阶段或者节点再平衡过程中。也就是说它发生在任何节点增加或移除的过程中。
参数cluster.routing.allocation.cluster_concurrent_rebalance
决定了在shard再平衡过程中允许并发的shard数。合适的设置由使用的硬件性能决定,如集群节点使用的CPU核数,IO性能等。如果参数设置的不合理,将会对ES索引过程的性能带来一定的影响。
cluster.routing.allocation.cluster_concurrent_rebalance:2
ES默认设置的值为2,也就是说在任何时候最多只允许同时移动2个shards的数据。设置一个不太高的合理数值,虽然shard再平衡的并发数受到制约,但却不会对索引数据造成影响。
另外一个值得一提的参数是cluster.routing.allocation.disk.threshold_enabled
。如果这个参数设置为true,则在shard分配过程中为shard预留空闲的磁盘空间,相反如果设置为false,则分配到该节点上的shard数据的未来增加将受到限制(没有足够的空间)。
当threshold_enabled设置为true,有两个相应的指标可以配置:low和high。
- low 定义了当磁盘使用量超过该指标后,ES将不再为该节点分配shard,默认值为85%;
- high 定义了当磁盘使用量超过该指标后,将有shard从该节点中移出,默认值为90%;
这两个参数即可按已使用量的百分比定义(例如,80%是说使用了80%的磁盘,尚有20%空闲),也可以按最小可用磁盘空间定义(例如,20GB是说该节点尚有20GB空闲空间)。
如果有大量的小shards,ES使用的默认值可能会有些保守。例如有1TB的存储空间,而每个shard的大小仅为10GB,理论上该节点能容纳100个数据shards。如果采用上面的默认设置,在ES认为节点饱和前,最多只能存储80个shards。
所以为了找出一个合理设置,需要仔细观察在shard生命周期中的容量变化,同时为之预留一定的安全空间。在上面的例子中,假如有5个数据shards,则需要确认在任何时候都要有50GB的可用空间(不是空闲空间,是5个shards将占用的总空间)。对于1TB的设备,如果不考虑安全空间,low的值可设置为95%。然而乘以50%的安全系数,则需要至少预留75GB的空闲空间,相应的合理的low值应为92.5%。
8. 合理的恢复设置提升节点重启速度
ES提供了几个属性用于提高集群恢复速度,缩短节点重启时间。合理的取值依赖于硬件能力(硬盘和网络速度通常会是瓶颈), 所以能给出的最好的建议就是尝试,尝试,再尝试。
- 控制单个节点并发恢复数据的shard数:
cluster.routing.allocation.node_concurrent_recoveries
- 控制单个节点上初始的主shard并发数:
cluster.routing.allocation.node_initial_primaries_recoveries
- 控制一个shard恢复数据时并行打开的数据流个数:
indices.recovery.concurrent_streams
- 与数据流紧密相关的是可用的带宽限制:
indices.recovery.max_bytes_per_sec
实际使用的硬件配置直接决定了以上几个参数的最优值设置。使用SSD硬盘以及高速的(10G)以太网结构和使用机械硬盘以及1G的以太网结构将有巨大的差别。
只有在集群重启或者调整shards的时候,才会使用以上数据恢复相关的参数设置。
9. 合理的线程池设置避免数据丢失
为了提高节点内的线程管理,ES维护了多个线程池。
在使用_bulk
操作来处理索引请求时发现,设置合适的threadpool.bulk.queue_size
对避免_bulk
重试以及由其可能引起的数据丢失至关重要。
threadpool.bulk.queue_size: 5000
上面的参数用于设置bulk的队列长度,即当节点的每个shard在处理bulk请求时,如果无可用线程时,能为每个shard排队等待的请求数量。这个参数应该与bulk请求负载相匹配,如果设置过小,而bulk请求较多时,ES会返回一个RemoteTransportException。
如上所述,bulk请求涉及到的每个shard的数据都在这个队列里,因此合理的设置是bulk的并发数乘以这些请求相关的shard数。比如说:单个bulk请求包含的数据分布在10个shards上,即便只有一次bulk请求,也要有一个至少长度为10的队列设置。话说回来,如果设置过大则会消耗更多的JVM堆空间(同时意味正提交的数据量可能超出实际能索引的能力),然而却能减化客户端处理逻辑。
要么设置一个相对合适的较大的队列值,要么在代码中合理的处理掉RemoteTransportException。如果处理不当,则会面临数据丢失的风险。下面的异常模仿的是队列长度为10,而并发发起了超过10个bulk请求的场景:
RemoteTransportException[[<Bantam>][inet[/192.168.1.1:9300]][bulk/shard]]; nested: EsRejectedExecutionException[rejected execution (queue capacity 10) on org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction$1@13fe9be];
网友评论