ElasticSearch是建立在全文搜索引擎 Apache Lucene(TM) 基础上的分布式、高性能、高可用、可伸缩的实时搜索和分析引擎。可支持扩展到上百台服务器,处理PB级别的结构化或非结构化数据。常用于日志数据分析、商品检索等场景。
索引的写入机制
Elasticsearch索引是以分片的形式进行保存的,一个索引由多个主分片(默认为5个)组成,每一个主分片通常有一个或多个副本。
当数据写入的时候,Elasticsearch首先根据路由规则对路由参数(路由参数默认使用_id,当然Index Request中也可以设置使用哪个Filed的值作为路由参数)进行Hash取模,确定要写入的主分片。
shard = hash(routing) % number_of_primary_shards
然后,通过集群状态信息,找出要写入的主分片所在的节点,将请求转发到此节点。当主分片成功写入数据后,会并行地将请求转发送给它的副本。当请求在全部副本上执行成功,并响应主分片后,主分片将结果返回给客户端。
在Elasticsearch将索引数据写入分片的过程中,首先会将索引数据保存到内存缓存中,与此同时还生成translog(这是保证数据一致性的关键)。然后,再以默认1秒的速度,将内存缓存中的数据按片段(segment)为单位刷新到文件系统的缓存中。要保证索引数据能被搜索,将索引数据刷新到文件系统的缓存中是关键。
由于内存缓存中的数据,默认每1秒都会以片段(segment)的方式刷新至文件系统缓存中,所以,如果不进行片段合并,文件缓存中的片段数将非常庞大。因此,为减少片段(segment)数量,在将内存中的索引片段刷新到文件系统的缓存中时,Elasticsearch会将多个小的片段(segment)合并成一个大的片段(segment),当大片段合成完后,小的片段将会被删除掉。
前面已经提到,Elasticsearch索引数据的一致性是通过translog来保证的,默认情况下,Elasticsearch每5秒,或每次请求操作结束前,就会强制刷新translog到磁盘上,当translog成功保存到磁盘后,translog就会被Elasticsearch删除。
分片的分配机制
每一个索引数据都是由多个分片租成的,当创建索引、删除索引、新增索引副本、增减节点时,就会发生分片分配操作。某个分片分配到哪个节点,一般来说,是由Elasticsearch自动决定的。
Elasticsearch中,比较常见的分配策略有两种:
- 磁盘限额:为了保护节点数据安全,Elasticsearch会定时(默认30秒)检查一下各节点的数据目录磁盘使用情况。当达到cluster.routing.allocation.disk.watermark.low(默认85%)时,新索引分片就不会再分配到这个节点上。当达到cluster.routing.allocation.disk.watermark.high(默认90%)时,就会触发该节点现存分片的数据均衡,把数据挪到其他节点上去。这两个值不但可以写百分比,还可以写具体的字节数。
- 热索引分片不均匀:默认情况下,Elasticsearch集群的数据均衡策略时以各节点的分片总数作为基准的。这对于搜索服务来说无疑是均衡搜索压力、提升性能的好办法。但对于ELK stack场景,一般压力集中在新索引的数据写入方面。正常运行的时候,也没有问题。但当集群扩容时,新加入集群的节点,分片总数远低于其他节点。这个时候如果有新索引创建,Elasticsearch的默认策略会导致新索引的所有主分片几乎全部分配到这台新节点上。整个集群的写入压力,压在一个节点上,结果很可能是这个节点直接被压死,集群出现异常。所以,对于ELK stack场景,强烈建议大家预先计算好索引的分片数后,配置好单节点分片的限额。