es分布式架构原理

Elasticsearch 是一个兼有搜索引擎和NoSQL数据库功能的开源系统,基于Java/Lucene构建,可以用于全文搜索,结构化搜索以及近实时分析。可以说Lucene是当今最先进,最高效的全功能开源搜索引擎框架。 说明: Lucene:只是一个框架,要充分利用它的功能,需要使用JAVA,并且在程序中集成Lucene,学习成本高,Lucene确实非常复杂。 Elasticsearch 是 面向文档型数据库,这意味着它存储的是整个对象或者 文档,它不但会存储它们,还会为他们建立索引,这样你就可以搜索他们了

应用场景

站内搜索:主要和 Solr 竞争,属于后起之秀
NoSQL json文档数据库:主要抢占 Mongo 的市场,它在读写性能上优于 Mongo ,同时也支持地理位置查询,还方便地理位置和文本混合查询,属于歪打正着 (对比测试参见:http://blog.quarkslab.com/mongodb-vs-elasticsearch-the-quest-of-the-holy-performances.html)
监控:统计以及日志类时间序的数据的存储和分析以及可视化,这方面是引领者
国外:Wikipedia使用 ES 提供全文搜索并高亮关键字、StackOverflow结合全文搜索与地理位置查询、Github使用Elasticsearch检索1300亿行的代码
国内:百度(在casio、云分析、网盟、预测、文库、直达号、钱包、风控等业务上都应用了ES,单集群每天导入30TB+数据,总共每天60TB+)、新浪(见大数据架构–log),阿里巴巴、腾讯等公司均有对ES的使用
使用比较广泛的平台ELK(ElasticSearch, Logstash, Kibana)

solr VS ES

Solr是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。
Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。
Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。
Solr强大的外部配置功能使得无需进行Java编码,便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制

Elasticsearch 与 Solr 的比较总结

二者安装都很简单
Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能
Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式
Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供
Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch
Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用

核心概念

集群(Cluster): 包含一个或多个具有相同 cluster.name 的节点.
集群内节点协同工作,共享数据,并共同分担工作负荷。
由于节点是从属集群的,集群会自我重组来均匀地分发数据.
cluster Name是很重要的,因为每个节点只能是群集的一部分,当该节点被设置为相同的名称时,就会自动加入群集。
集群中通过选举产生一个mater节点,它将负责管理集群范畴的变更,例如创建或删除索引,添加节点到集群或从集群删除节点。master 节点无需参与文档层面的变更和搜索,这意味着仅有一个 master 节点并不会因流量增长而成为瓶颈。任意一个节点都可以成为 master 节点。我们例举的集群只有一个节点,因此它会扮演 master 节点的角色。
作为用户,我们可以访问包括 master 节点在内的集群中的任一节点。每个节点都知道各个文档的位置,并能够将我们的请求直接转发到拥有我们想要的数据的节点。无论我们访问的是哪个节点,它都会控制从拥有数据的节点收集响应的过程,并返回给客户端最终的结果。这一切都是由 Elasticsearch 透明管理的

节点(node): 一个节点是一个逻辑上独立的服务,可以存储数据,并参与集群的索引和搜索功能, 一个节点也有唯一的名字,群集通过节点名称进行管理和通信.

索引(Index): 索引与关系型数据库实例(Database)相当。索引只是一个 逻辑命名空间,它指向一个或多个分片(shards),内部用Apache Lucene实现索引中数据的读写
文档类型(Type):相当于数据库中的table概念。每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取

文档(Document) :相当于数据库中的row, 是可以被索引的基本单位。例如,你可以有一个的客户文档,有一个产品文档,还有一个订单的文档。文档是以JSON格式存储的。在一个索引中,您可以存储多个的文档。请注意,虽然在一个索引中有多分文档,但这些文档的结构是一致的,并在第一次存储的时候指定, 文档属于一种 类型(type),各种各样的类型存在于一个 索引 中。你也可以通过类比传统的关系数据库得到一些大致的相似之处:

关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns)
Elasticsearch ⇒ 索引 ⇒ 类型 ⇒ 文档 ⇒ 字段(Fields)

模拟示意图如:

在这里插入图片描述
Mapping: 相当于数据库中的schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以自动根据数据创建
分片(shard) :是 工作单元(worker unit) 底层的一员,用来分配集群中的数据,它只负责保存索引中所有数据的一小片。
1.分片是一个独立的Lucene实例,并且它自身也是一个完整的搜索引擎。
2.文档存储并且被索引在分片中,但是我们的程序并不会直接与它们通信。取而代之,它们直接与索引进行通信的
3.把分片想象成一个数据的容器。数据被存储在分片中,然后分片又被分配在集群的节点上。当你的集群扩展或者缩小时,elasticsearch 会自动的在节点之间迁移分配分片,以便集群保持均衡
4.分片分为 主分片(primary shard) 以及 从分片(replica shard) 两种。在你的索引中,每一个文档都属于一个主分片
5.从分片只是主分片的一个副本,它用于提供数据的冗余副本,在硬件故障时提供数据保护,同时服务于搜索和检索这种只读请求
6.索引中的主分片的数量在索引创建后就固定下来了,但是从分片的数量可以随时改变。
7.一个索引默认设置了5个主分片,每个主分片有一个从分片对应

ES模块结构

模块结构图如下
在这里插入图片描述
Gateway: 代表ES的持久化存储方式,包含索引信息,ClusterState(集群信息),mapping,索引碎片信息,以及transaction log等
对于分布式集群来说,当一个或多个节点down掉了,能够保证我们的数据不能丢,最通用的解放方案就是对失败节点的数据进行复制,通过控制复制的份数可以保证集群有很高的可用性,复制这个方案的精髓主要是保证操作的时候没有单点,对一个节点的操作会同步到其他的复制节点上去。
ES一个索引会拆分成多个碎片,每个碎片可以拥有一个或多个副本(创建索引的时候可以配置),这里有个例子,每个索引分成3个碎片,每个碎片有2个副本,如下:

$ curl -XPUT http://localhost:9200/twitter/ -d ’
index :
number_of_shards : 3
number_of_replicas : 2

每个操作会自动路由主碎片所在的节点,在上面执行操作,并且同步到其他复制节点,通过使用“non blocking IO”模式所有复制的操作都是并行执行的,也就是说如果你的节点的副本越多,你网络上的流量消耗也会越大。复制节点同样接受来自外面的读操作,意义就是你的复制节点越多,你的索引的可用性就越强,对搜索的可伸缩行就更好,能够承载更多的操作

第一次启动的时候,它会去持久化设备读取集群的状态信息(创建的索引,配置等)然后执行应用它们(创建索引,创建mapping映射等),每一次shard节点第一次实例化加入复制组,它都会从长持久化存储里面恢复它的状态信息

Lucence Directory: 是lucene的框架服务发现以及选主 ZenDiscovery: 用来实现节点自动发现,还有Master节点选取,假如Master出现故障,其它的这个节点会自动选举,产生一个新的Master
它是Lucene存储的一个抽象,由此派生了两个类:FSDirectory和RAMDirectory,用于控制索引文件的存储位置。使用FSDirectory类,就是存储到硬盘;使用RAMDirectory类,则是存储到内存
在这里插入图片描述
一个Directory对象是一份文件的清单。文件可能只在被创建的时候写一次。一旦文件被创建,它将只被读取或者删除。在读取的时候进行写入操作是允许的

Discovery
节点启动后先ping(这里的ping是 Elasticsearch 的一个RPC命令。如果 discovery.zen.ping.unicast.hosts 有设置,则ping设置中的host,否则尝试ping localhost 的几个端口, Elasticsearch 支持同一个主机启动多个节点)
Ping的response会包含该节点的基本信息以及该节点认为的master节点
选举开始,先从各节点认为的master中选,规则很简单,按照id的字典序排序,取第一个
如果各节点都没有认为的master,则从所有节点中选择,规则同上。这里有个限制条件就是 discovery.zen.minimum_master_nodes,如果节点数达不到最小值的限制,则循环上述过程,直到节点数足够可以开始选举
最后选举结果是肯定能选举出一个master,如果只有一个local节点那就选出的是自己
如果当前节点是master,则开始等待节点数达到 minimum_master_nodes,然后提供服务, 如果当前节点不是master,则尝试加入master.
ES支持任意数目的集群(1-N),所以不能像 Zookeeper/Etcd 那样限制节点必须是奇数,也就无法用投票的机制来选主,而是通过一个规则,只要所有的节点都遵循同样的规则,得到的信息都是对等的,选出来的主节点肯定是一致的. 但分布式系统的问题就出在信息不对等的情况,这时候很容易出现脑裂(Split-Brain)的问题,大多数解决方案就是设置一个quorum值,要求可用节点必须大于quorum(一般是超过半数节点),才能对外提供服务。而 Elasticsearch 中,这个quorum的配置就是 discovery.zen.minimum_master_nodes 。

memcached
1.通过memecached协议来访问ES的接口,支持二进制和文本两种协议.通过一个名为transport-memcached插件提供
2.Memcached命令会被映射到REST接口,并且会被同样的REST层处理,memcached命令列表包括:get/set/delete/quit

River : 代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的,river这个功能将会在后面的文件中重点说到

分片示例
启用一个既没有数据,也没有索引的单一节点, 如下图
在这里插入图片描述
在空的单节点集群中上创建一个叫做 blogs 的索引,设置3个主分片和一组从分片(每个主分片有一个从分片对应),代码如下:

PUT /blogs
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

集群示例图如下: (此时集群健康状态为: yellow 三个从分片还没有被分配到节点上)
在这里插入图片描述
在这里插入图片描述
主分片(primary shards) 启动并且运行了,这时集群已经可以成功的处理任意请求,但是 从分片(replica shards) 没有完全被激活。事实上,当前这三个从分片都处于 unassigned(未分配)的状态,它们还未被分配到节点上。在同一个节点上保存相同的数据副本是没有必要的,如果这个节点故障了,就等同于所有的数据副本也丢失了
启动第二个节点,配置第二个节点与第一个节点的 cluster.name 相同(./config/elasticsearch.yml文件中的配置),它就能自动发现并加入到第一个节点的集群中,如下图:

在这里插入图片描述
在这里插入图片描述
cluster-health 的状态为 green,这意味着所有的6个分片(三个主分片和三个从分片)都已激活,文档在主节点和从节点上都能被检索
随着应用需求的增长,启动第三个节点进行横向扩展,集群内会自动重组,如图
在这里插入图片描述
在 Node 1 和 Node 2 中分别会有一个分片被移动到 Node 3 上,这样一来,每个节点上就都只有两个分片了。这意味着每个节点的硬件资源(CPU、RAM、I/O)被更少的分片共享,所以每个分片就会有更好的性能表现
一共有6个分片(3个主分片和3个从分片),因此最多可以扩展到6个节点,每个节点上有一个分片,这样每个分片都可以使用到所在节点100%的资源了
主分片的数量在索引创建的时候就已经指定了,实际上,这个数字定义了能存储到索引中的数据最大量(具体的数量取决于你的数据,硬件的使用情况)。例如,读请求——搜索或者文档恢复就可以由主分片或者从分片来执行,所以当你拥有更多份数据的时候,你就拥有了更大的吞吐量
从分片的数量可以在运行的集群中动态的调整,这样我们就可以根据实际需求扩展或者缩小规模。接下来,我们来增加一下从分片组的数量:

PUT /blogs/_settings
{
“number_of_replicas” : 2
}

现在 blogs 的索引总共有9个分片:3个主分片和6个从分片, 又会变成一个节点一个分片的状态了,最终得到了三倍搜索性能的三节点集群
在这里插入图片描述
说明:仅仅是在同样数量的节点上增加从分片的数量是根本不能提高性能的,因为每个分片都有访问系统资源的权限。你需要升级硬件配置以提高吞吐量。
尝试一下,把第一个节点杀掉,我们的集群就会如下图所示:
在这里插入图片描述
被杀掉的节点是主节点,主分片 1 和 2 在我们杀掉 Node 1 后就丢失了,我们的索引在丢失主节点的时候是不能正常工作的。如果我们在这个时候检查集群健康状态,将会显示 red:存在不可用的主节点
而为了集群的正常工作必须需要一个主节点,所以首先进行的进程就是从各节点中选择了一个新的主节点:Node 2
新的主节点所完成的第一件事情就是将这些在 Node 2 和 Node 3 上的从分片提升为主分片,然后集群的健康状态就变回至 yellow。这个提升的进程是瞬间完成了,就好像按了一下开关
如果再次杀掉 Node 2 的时候,我们的程序依旧可以在没有丢失任何数据的情况下运行,因为 Node 3 中依旧拥有每个分片的备份
如果我们重启 Node 1,集群就能够重新分配丢失的从分片,这样结果就会与三节点两从集群一致。如果 Node 1 依旧还有旧节点的内容,系统会尝试重新利用他们,并只会复制在故障期间的变更数据

es写入数据的过程

1.客户端选择一个node发送请求过去,这个node就是coordinating node (协调节点)
2.coordinating node,对document进行路由,将请求转发给对应的node
3.实际上的node上的primary shard处理请求,然后将数据同步到replica node
4.coordinating node,如果发现primary node和所有的replica node都搞定之后,就会返回请求到客户端

es读数据过程

查询,GET某一条的数据,写入某个document,这个document会自动给你分配一个全局的唯一ID,同时跟住这个ID进行hash路由到对应的primary shard上面去,当然也可以手动的设置ID

客户端发送任何一个请求到任意一个node,成为coordinate node
coordinate node 对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮训算法,在primary shard 以及所有的replica中随机选择一个,让读请求负载均衡,
接受请求的node,返回document给coordinate note
coordinate node返回给客户端

es搜索数据过程

1.客户端发送一个请求给coordinate node
2.协调节点将搜索的请求转发给所有的shard对应的primary shard 或replica shard
3.query phase:每一个shard 将自己搜索的结果(其实也就是一些唯一标识),返回给协调节点,有协调节点进行数据的合并,排序,分页等操作,产出最后的结果
4.fetch phase ,接着由协调节点,根据唯一标识去各个节点进行拉去数据,最总返回给客户端

写入数据的底层原理

1.数据先写入到buffer里面,在buffer里面的数据时搜索不到的,同时将数据写入到translog日志文件之中
2.如果buffer快满了,或是一段时间之后,就会将buffer数据refresh到一个新的OS cache之中,然后每隔1秒,就会将OS cache的数据写入到segment file之中,但是如果每一秒钟没有新的数据到buffer之中,就会创建一个新的空的segment file,只要buffer中的数据被refresh到OS cache之中,就代表这个数据可以被搜索到了。当然可以通过restful api 和Java api,手动的执行一次refresh操作,就是手动的将buffer中的数据刷入到OS cache之中,让数据立马搜索到,只要数据被输入到OS cache之中,buffer的内容就会被清空了。同时进行的是,数据到shard之后,就会将数据写入到translog之中,每隔5秒将translog之中的数据持久化到磁盘之中
3.重复以上的操作,每次一条数据写入buffer,同时会写入一条日志到translog日志文件之中去,这个translog文件会不断的变大,当达到一定的程度之后,就会触发commit操作。
4.将一个commit point写入到磁盘文件,里面标识着这个commit point 对应的所有segment file
5.强行将OS cache 之中的数据都fsync到磁盘文件中去。
解释:translog的作用:在执行commit之前,所有的而数据都是停留在buffer或OS cache之中,无论buffer或OS cache都是内存,一旦这台机器死了,内存的数据就会丢失,所以需要将数据对应的操作写入一个专门的日志问价之中,一旦机器出现宕机,再次重启的时候,es会主动的读取translog之中的日志文件的数据,恢复到内存buffer和OS cache之中。
将现有的translog文件进行清空,然后在重新启动一个translog,此时commit就算是成功了,默认的是每隔30分钟进行一次commit,但是如果translog的文件过大,也会触发commit,整个commit过程就叫做一个flush操作,我们也可以通过ES API,手动执行flush操作,手动将OS cache 的数据fsync到磁盘上面去,记录一个commit point,清空translog文件
补充:其实translog的数据也是先写入到OS cache之中的,默认每隔5秒之中将数据刷新到硬盘中去,也就是说,可能有5秒的数据仅仅停留在buffer或者translog文件的OS cache中,如果此时机器挂了,会丢失5秒的数据,但是这样的性能比较好,我们也可以将每次的操作都必须是直接fsync到磁盘,但是性能会比较差。
如果时删除操作,commit的时候会产生一个.del文件,里面讲某个doc标记为delete状态,那么搜索的时候,会根据.del文件的状态,就知道那个文件被删除了。
如果时更新操作,就是讲原来的doc标识为delete状态,然后重新写入一条数据即可。
buffer每次更新一次,就会产生一个segment file 文件,所以在默认情况之下,就会产生很多的segment file 文件,将会定期执行merge操作
每次merge的时候,就会将多个segment file 文件进行合并为一个,同时将标记为delete的文件进行删除,然后将新的segment file 文件写入到磁盘,这里会写一个commit point,标识所有的新的segment file,然后打开新的segment file供搜索使用。
总之,segment的四个核心概念,refresh,flush,translog、merge

搜索的底层原理

查询过程大体上分为查询和取回这两个阶段,广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。

查询阶段

当一个节点接收到一个搜索请求,这这个节点就会变成协调节点,第一步就是将广播请求到搜索的每一个节点的分片拷贝,查询请求可以被某一个主分片或某一个副分片处理,协调节点将在之后的请求中轮训所有的分片拷贝来分摊负载。
每一个分片将会在本地构建一个优先级队列,如果客户端要求返回结果排序中从from 名开始的数量为size的结果集,每一个节点都会产生一个from+size大小的结果集,因此优先级队列的大小也就是from+size,分片仅仅是返回一个轻量级的结果给协调节点,包括结果级中的每一个文档的ID和进行排序所需要的信息。
协调节点将会将所有的结果进行汇总,并进行全局排序,最总得到排序结果。
取值阶段

查询过程得到的排序结果,标记处哪些文档是符合要求的,此时仍然需要获取这些文档返回给客户端
协调节点会确定实际需要的返回的文档,并向含有该文档的分片发送get请求,分片获取的文档返回给协调节点,协调节点将结果返回给客户端。

倒排索引

倒排索引就建立分词与文档之间的映射关系,在倒排索引之中,数据时面向分词的而不是面向文档的。

在海量数据中怎样提高效率

filesystem cache
ES的搜索引擎是严重的依赖底层的filesystem cache,如果给filesystem cache更多的内存,尽量让内存可以容纳所有的index segment file 索引数据文件
数据预热
对于那些你觉得比较热的数据,经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据,每隔一段时间,你就提前访问以下,让数据进入filesystem cache里面去,这样期待下次访问的时候,性能会更好一些。
冷热分离
关于ES的性能优化,数据拆分,将大量的搜索不到的字段,拆分到别的存储中去,这个类似于MySQL的分库分表的垂直才分。

1.document的模型设计
不要在搜索的时候去执行各种复杂的操作,尽量在document模型设计的时候,写入的时候就完成了,另外对于一些复杂的操作,尽量要避免

2.分页性能优化
翻页的时候,翻得越深,每个shard返回的数据越多,而且协调节点处理的时间越长,当然是用scroll,scroll会一次性的生成所有数据的一个快照,然后每次翻页都是通过移动游标完成的。 api 只是在一页一页的往后翻。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值