分布式特性
es支持集群模式,是一个分布式系统,其好处主要有两个:
增大系统容量,如内存、硬盘,使得es集群可以支持PB级的数据。
提高系统的可用性,即使部分节点停止服务,整个集群仍然可以正常服务。
es集群由多个es实例组成
不同集群通过集群名称进行区分,可以通过cluster.name进行修改,默认名称为elasticsearch。
每个es实例本质上是一个JVM进程,且有自己的名字,通过node.name进行修改。
cerebro安装与运行
通过cerebro可以可视化的监控elasticsearch集群的状态。
下载地址
https://github.com/lmenezes/cerebro
下载https://github.com/lmenezes/cerebro/releases/tag/v0.7.1
解压安装包并运行
tar zxvf cerebro-0.7.1.tgz
cd cerebro-0.7.1
cd bin
./cerebro
jdk9+安装不成功可参考:https://blog.csdn.net/ilwoziji/article/details/129230044
es集群的构建
es的安装与下载
可参见:https://blog.csdn.net/ilwoziji/article/details/129227381?spm=1001.2014.3001.5501
启动一个节点
./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node1 -Enode.name=node1 -Ehttp.port=5200 -d
cluster state
es集群相关的数据被称为cluster state,主要记录如下信息
节点信息,比如节点名称、链接地址等。
索引信息,比如索引名称配置等。
...
master node
可以修改cluster state的节点称为master节点,一个集群只能有一个
cluster state存储在每一个节点上,master节点维护最新版本并同步给其他节点。
master节点是通过集群中所有节点选举产生的,可以被选举的节点称为master-eligible节点,相关配置如下:
node.master:true默认就是true。是可以被选举为master的节点。
创建一个索引
我们通过如下API创建一个索引
PUT test_index
Coordinating Node
处理请求的节点被称为coordinating节点,该节点为所有节点的默认角色,不能取消
路由请求到正确的节点进行处理,比如创建索引的请求到master节点。
Data Node
存储数据的节点Data Node,默认节点都是data类型,相关配置如下:
data.node:true
新增一个节点
新增node2节点,命令如下:
./elasticsearch -Ecluster.name=my_cluster -Epath.data=my_cluster_node2 -Enode.name=node2 -Ehttp.port=5300 -d
提高系统可用性-副本与分片
服务可用性
两个节点的情况下,允许其中一个节点停止服务。
数据可用性
引入副本(Replication)解决。
每个节点上都有完备的数据。
增大系统容量
如何将数据分布到所有节点上?
引入分片(shard)解决问题。
分片是es支持PB级数据的基石。
分片存储了部分数据,可以分布于任意节点上。
分片数在索引创建时指定,且后续不允许在修改,默认为5个。
分片有主分片和副本分片之分,以实现数据的高可用。
副本分片的数据由主分片同步,可以有多个,从而提高读取的吞吐量。
两个问题
此时增加节点是否能提高test_index的容量?
答案是不能,因为只有3个分片,已经分布在3个节点上,新增节点无法利用。
此时增加副本数是否能提高test_index的读取吞吐量?
答案是不能,因为新增的副本也是分步在当前的3个节点上,还是利用了同样的资源。如果要增加吞吐量,还需要新增节点。
分片设定很重要,需要提前规划好
过小会导致后续无法通过增加节点来提高查询的吞吐量。
过大会导致一个节点上的分片过多,此时也就影响查询的性能。
集群状态cluster health
通过_cluster/health API可以查看集群的健康状态,包括以下三种:
green 健康状态,指所有主副分片都分配正常。
yellow所有主分片都正常,但是副本分片未分配正常。
red 有主分片未分配。
http://localhost:5200/_cluster/health
故障转移
node1所在机器宕机导致服务终止,此时集群会如何处理?
node2和node3发现node1无法响应一段时间后会发起master选举,比如这里选择node2为master节点。此时由于主分片P0下线,集群状态变为red。
node2发现主分片P0未分配,此时将R0提升为主分片。此时由于所有主分片都正常分配,集群状态变为yellow。
node2为P0和P1生成新的副本,集群状态变为绿色。
文档分布式存储
文档最终会存储到分片上,如下图所示:
Document1是如何存储到分片P1上的?选择P1的依据是什么?
需要文档到分片的映射算法。
目的
使得文档均匀的分布在所有的分片上,以充分利用资源。
文档到分片的映射算法
随机选择或round-robin算法?
不可取,因为需要维护文档到分片的映射关系,成本巨大。
根据文档值时时的计算对应的分片
shard = hash(routing)%number_of_primary_shards。
hash算法保证可以将数据均匀地分散在分片中。
routing是一个关键参数,默认是文档id,也可以自行指定。
number_of_primary_shards主分片数
该算法与主分片数相关,这也是分片数一旦确定后便不能修改的原因。
文档创建的流程
文档读取的流程
文档批量创建流程
文档批量读取流程
脑裂问题
脑裂问题,英文为split-brain,是分布式系统中的经典网络问题,如下图所示:
node2和node3会重新选举master,比如node2成为新的master,此时会更新cluster state。
node1自己组成集群后也会更新cluster state。
同一个集群有两个master,而且维护不同的cluster state,网络恢复后无法选择正确的master。
接解决方案
仅在可选举master-eligible节点数大于等于quorum时才可以进行选举。
quorum=(master-eligible节点数)/ 2 + 1,例如3个master-eligible,quorum为2。
设定discovery.zen.minimum_master_nodes为quorum即可避免脑裂问题。
shard详解
倒排索引的不可变更
倒排索引一旦生成,不能更改。
其好处如下:
不用考虑并发写文件的问题,杜绝了锁机制带来的性能问题。
由于文件不在更改,可以充分利用文件系统缓存,只需载入一次,只要内存足够,对该文件的读取都会从内存读取,性能高。
利于生成缓冲数据。
利于对文件进行压缩存储,节省磁盘和内存存储空间。
坏处
需要写入新文档时,必须重新构建倒排索引,然后替换老文件后,新文档才能被检索,导致文档实时性差。
方案一:新增文档时,针对所有文档重新构建索引。
缺点开销太大,实时性差。不可取。
方案二:新文档直接生成新的倒排索引文件,查询时同时查询所有的倒排索引文件,然后做结果的汇总计算即可。
Lucene的实现方案,采用的事方案二,它构建的单个倒排索引称为segment,合一起称为Index,与es中的Index不同,es中的一个shard对应一个Lucene Index。
Lucene会有一个专门的文件来记录所有的segment信息,成为commit point。
文档搜索实时性-refresh
segment写入磁盘的过程依然很耗时,可以借助文件系统缓存的特性,先将segment在缓存中创建并开放查询来进一步提升实时性,该过程在es中被称为refresh。
在refresh之前文档会先存储在一个buffer中,refresh时会将buffer中的所有文档清空并生成segment。
es默认每一秒执行一次refresh,因此文档的实时性被提高到1秒,这也是es被称为近实时(near real time)的原因。
refresh发生的时机
间隔时间达到时,通过index.settings.refresh_interval来设定,默认为1秒。
index_buffer占满时,其大小通过indices.memery.index_buffer_size设置,默认时JVM heap的10%,所有shard共享。
flush时也会发生refresh。
文档搜索实时性-translog
如果内存中的segment还没写入到磁盘前发生宕机,那么其中的文档就无法恢复了。如何解决此问题?
es引入translog的机制,写入文档到buffer时,同时写入文档到translog。
translog文件会即时写入到磁盘(fsync),6.x默认每次都会落盘。可以修改为每5秒写入一次,来提高写入性能,这样同时会带来可能会丢失5秒内的数据,相关配置为index.translog.*。
es启动时会检查translog文件,并从中恢复数据。
文档搜索实时性-flush
负责将内存中的segment写入磁盘,主要工作如下:
将translog写入磁盘。
将index buffer清空,其中的文档生成一个新的segment,相当于一个refresh操作。
更新commit point并写入磁盘。
删除旧的translog文件。
flush发生的时机
间隔时间达到时,默认30分钟,5.x之前的版本可以修改,之后的版本不可修改。
translog占满时,其大小可以通过index.translog.flush_threshold_size控制,默认时512m,每个index都有自己的translog。
删除与更新文档
segment一旦生成就不能修改,那么你要删除文档要如何操作?
Lucene专门维护一个.del文件,记录所有已删除的文档,注意.del文档上记录的是文档在lucene内部的id。
在查询返回结果前会过滤掉.del文件中的文档。
更新文档如何进行
首先删除文档,在创建新文档。
es index 与 lucene index的对照,如下图:
segment merging
随着segment的增多,由于一次查询的segment的增多,查询速度会变慢。
es会定时后台惊喜segment merging,减少segment数量。
通过force_merge api可以手动强行做segment merge的操作。