1.elasticsearch底层采用lucenehtml
Lucene底层原理:node
2.Elasticsearch架构图:git
第1部分分析了Elasticsearch基本的读、写、更新、存储等方面的实现原理,本文档主要介绍Elasticsearch如何实现分布式系统的三个特性(consensus, concurrency和consistency),以及分片的内部概念,例如:translog(Write Ahead Log - WAL)和Lucene segments。
本章主要包括如下内容:github
Consensus是一个分布式系统的基本挑战。它要求分布式系统中的全部的进程/节点,对给定的数据的值/状态达成一致。有不少Consensus的算法,如Raft,Paxos等。这些算法在数学上被证实是有效的,但Elasticsearch实现了它本身的consensus系统(zen discovery),是由于Shay Banon(Elasticsearch的建立者)所描述的缘由。
zen discovery模块有两个部分:算法
Elasticsearch是一种点对点(peer-to-peer)系统,其中全部节点彼此通讯,而且只有一个活动的主节点,该节点能够更新和控制群集状态和操做。新的Elasticsearch集群将会进行一次选举,该选举做为ping进程的一部分在节点中运行。在全部有资格选举的节点中,其中有一个节点被选举为主节点(master node),其余节点加入该主节点。
默认的ping_interval为1秒,ping_timeout为3秒。当节点加入时,他们会发生一个join的请求给master主机,该请求有一个join_timeout时间,默认是参数ping_timeout的20倍。
若主节点失败,集群中的几点再次开始ping,开始另外一次新的选举。若是节点意外地认为主节点发生故障,而且经过其余节点发现主节点,则该ping过程也将有所帮助。
注意:默认状况下,客户端(client)和数据节点不会对选举过程作出贡献。能够经过改变如下参数的设置,这些参数在elasticsearch.yml 文件中:数据库
discovery.zen.master_election.filter_client:False discovery.zen.master_election.filter_data: False
故障检测的过程是这样的:主节点ping全部的节点来检查这些节点是否存活,而全部的节点回ping主节点来汇报他们是存活的。缓存
若使用默认配置,Elasticsearch会遇到脑裂的问题,若是是网络分区,则节点能够认为主节点已经死机,并将其自身选为主节点,从而致使集群具备多个主节点。这样可能致使数据丢失,可能没法正确合并数据。这种状况能够经过将如下属性设置为主合格节点的法定数量来避免:网络
discovery.zen.minimum_master_nodes = int(# of master eligible nodes/2)+1
该参数要求法定数量的可参加选举的节点加入新的选举过程来完成新的选举过程,并接受新节点做为新的master节点。这是确保集群稳定性的极其重要的参数,若是集群大小发生变化,能够进行动态更新。图a和b分别显示了在minimum_master_nodes属性被设置,和未被设置的两种状况。
注意:对于生产环境的集群,建议有3个专用主节点,在任何给定的时间点只有一个处于活动状态,其余的节点不服务任何客户请求。架构
Elasticsearch是一个分布式系统,支持并发请求。当建立/更新/删除请求命中主分片时,它同时发送到副本分片,可是这些请求到达的顺序是不肯定的。在这种状况下,Elasticsearch使用乐观并发控制(optimistic concurrency control)来确保文档的较新版本不会被旧版本覆盖。
每一个被索引的文档都会有一个版本号,每次文档改变时,该版本号就会增长。使用版本号能够确保对文档的改变是顺序进行的。为确保咱们的应用程序中的更新不会致使数据丢失,Elasticsearch的API容许您指定,更改应该应用到目前哪个版本号。若是请求中指定的版本号,早于分片中存在的版本号,则请求失败,这意味着该文档已被其余进程更新。
如何处理失败的请求?能够在应用程序级别进行控制。还有其余锁定选项可用,您能够在这里阅读。并发
当咱们向Elasticsearch发送并发请求时,下一个问题是 - 咱们如何使这些请求保持一致?如今要回答 CAP原则,还不是太清晰,这是接下来要讨论的问题。
可是,咱们将回顾如何使用Elasticsearch实现一致的写入和读取。
对于写操做,Elasticsearch支持与大多数其余数据库不一样的一致性级别,它容许初步检查以查看有多少个分片可用于容许写入。可用的选项是:quorum的可设置的值为:one和all。默认状况下,它被设置为:quorum,这意味着只有当大多数分片可用时,才容许写入操做。在大部分分片可用的状况下,因为某种缘由,写入复制副本分片失败仍然可能发生,在这种状况下,副本被认为是错误的,该分片将在不一样的节点上进行重建。
对于读操做,新文档在刷新间隔时间后才能用于搜索。为了确保搜索结果来自最新版本的文档,能够将复制(replication)设置为sync(默认值),当在主分片和副本分片的写操做都完成后,写操做才返回。在这种状况下,来自任何分片的搜索请求将从文档的最新版本返回结果。
即便你的应用程序为了更快的indexing而设置:replication=async,也可使用_preference参数,能够为了搜素请求把它设置为primary。这样,查询主要分片就是搜索请求,并确保结果未来自最新版本的文档。
当咱们了解Elasticsearch如何处理consensus,并发性和一致性时,咱们来看看分片内部的一些重要概念,这些概念致使了Elasticsearch做为分布式搜索引擎的某些特征
自从开发关系数据库以来,数据库世界中一直存在着write ahead log(WAL)或事务日志(translog)的概念。Translog在发生故障的状况下确保数据的完整性,其基本原则是,在数据的实际更改提交到磁盘以前必须先记录并提交预期的更改。
当新文档被索引或旧文档被更新时,Lucene索引会更改,这些更改将被提交到磁盘以进行持久化。每次写请求以后进行持久化操做是一个很是消耗性能的操做,它经过一次持久化多个修改到磁盘的方式运行(译注:也就是批量写入)。正如咱们在以前的一篇博客中描述的那样,默认状况下每30分钟执行一次flush操做(Lucene commit),或者当translog变得太大(默认为512MB)时)。在这种状况下,有可能失去两次Lucene提交之间的全部变化。为了不这个问题,Elasticsearch使用translog。全部的索引/删除/更新操做都先被写入translog,而且在每一个索引/删除/更新操做以后(或者每默认默认为5秒),translog都被fsync’s,以确保更改被持久化。在主文件和副本分片上的translog被fsync’ed后,客户端都会收到写入确认。
在两次Lucene提交或从新启动之间出现硬件故障的状况下,会在最后一次Lucene提交以前重播Translog以从任何丢失的更改中恢复,并将全部更改应用于索引。
建议在从新启动Elasticsearch实例以前显式刷新translog,由于启动将更快,由于要重播的translog将为空。POST / _all / _flush命令可用于刷新集群中的全部索引。
使用translog刷新操做,文件系统缓存中的段将提交到磁盘,以使索引持续更改。
如今咱们来看看Lucene segment:
Lucene索引由多个片断(segment)组成,片断自己是彻底功能的倒排索引。片断是不可变的,这容许Lucene增量地向索引添加新文档,而无需从头开始重建索引。对于每一个搜索请求,搜全部段都会被搜素,每一个段消耗CPU周期,文件句柄和内存。这意味着分段数越多,搜索性能就越低。
为了解决这个问题,Elasticsearch将小段合并成一个更大的段(以下图所示),将新的合并段提交到磁盘,并删除旧的较小的段。
合并操做将会自动发生在后台,而不会中断索引或搜索。因为分段合并可能会浪费资源并影响搜索性能,所以Elasticsearch会限制合并过程的资源使用,以得到足够的资源进行搜索。