一、什么是 ElastcSearch?
ElasticSearch 是基于 Lucene 的 Restful 的分布式实时全文搜索引擎。
1.1 ElasticSearh 的基本术语概念
- index 索引
索引类似与 mysql 中的数据库,ES 中的索引是存储数据的地方,包含了一堆有相似结构的文档数据。 - type 类型
类型是用来定义数据结构的,可以认为是 mysql 中的一张表,type 是 index 中的一个逻辑数据分类。 - mapping 映射
对字段的定义称为 mapping,可以认为是 mysql 中的表结构。 - document 文档
类似于 mysql 中的一行,不同之处在于 ES 中的每个文档可以用不同的字段,但是对于通用的字段应该具有相同的数据类型,文档是 ES 中的最小数据单元,可以认为一个文档就是一条记录。 - field 字段
field 是 ES 的最小单位,一个 document 里面有多个 field 。
mysql | ES |
---|---|
数据库 | 索引 |
表 | 类型 |
行 | 文档 |
列 | 字段 |
表结构 | 映射 |
- shard 分片
单台机器无法存储大量数据,ES 可以将一个索引中的数据切分为多个 shard,分布在多台服务器上存储。有了 shard 就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。 - replica 副本
任何一个服务器随时都可能故障或宕机,此时 shard 可能会丢失,因此可以为每个 shard 创建多个 replica 副本。replica 可以在 shard 故障时提供备用服务,保证数据不丢失,多个 replica 还可以提升搜索操作的吞吐量和性能。 - 倒排索引
在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,某个文档经过分词,提取20个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。那么,倒排索引就是关键词到文档 ID 的映射,每个关键词都对应着一系列的文件,这些文件都出现了该关键词。有了倒排索引,搜索引擎可以很方便地响应用户的查询。 - text 和 keyword类型的区别
两个的区别主要分词的区别:keyword 类型是不会分词的,直接根据字符串内容建立倒排索引,keyword类型的字段只能通过精确值搜索到;Text 类型在存入 Elasticsearch 的时候,会先分词,然后根据分词后的内容建立倒排索引。 - DocValues
倒排索引也是有缺陷的,假如我们需要对数据做一些聚合操作,比如排序/分组时,lucene内部会遍历提取所有出现在文档集合的排序字段,然后再次构建一个最终的排好序的文档集合list,这个步骤的过程全部维持在内存中操作,而且如果排序数据量巨大的话,非常容易就造成solr内存溢出和性能缓慢。
DocValues 就是 es 在构建倒排索引的同时,构建了正排索引,保存了docId到各个字段值的映射,可以看作是以文档为维度,从而实现根据指定字段进行排序和聚合的功能。另外doc Values 保存在操作系统的磁盘中,当docValues大于节点的可用内存,ES可以从操作系统页缓存中加载或弹出,从而避免发生内存溢出的异常,docValues远小于节点的可用内存,操作系统自然将所有Doc Values存于内存中(堆外内存),有助于快速访问。
二、ES 写数据流程及原理
2.1 写数据流程
- 客户端选择一个节点发送请求过去,这个节点就是协调节点(coordinating node);
- 协调节点对 document 进行路由,将请求转发给对应的有 primary shard 的节点;
- 实际的节点上的 primary shard 处理请求,然后将数据同步到 replica node;
- 协调节点等到 primary node 和所有 replica node 都执行成功之后,就返回响应结果给客户端;
2.2 写数据底层实现原理
- 数据先写入内存缓存(Memory Buffer),然后定时(默认每隔1s)将内存缓存中的数据写入一个新的 segment 文件中,并写入文件缓存(Filesystem Cache)(同时清空内存缓存),这个过程就叫 refresh;
- 由于内存缓存和文件系统缓存都是基于内存的,如果服务器宕机,那么数据就会丢失,所以 ES 通过 translog 日志文件来保证数据可靠性,在数据写入内存缓存的同时,将数据写入 translog 文件中,在机器宕机重启时,ES 会自动读取 translog 日志文件中的数据,恢复到内存缓存和文件系统缓存中去。
- flush 操作:不断重复上面的步骤,translog 会变得越来越大,当 translog 文件默认每 30 分钟或者阈值超过 512M 时,就会触发 commit 操作,这个过程称为 flush 操作。
commit 操作:
- 1.将 Buffer 中的数据 refush 到 Filesysytem Cache 中,清空 Buffer;
- 2.创建一个新的 commit point,同时强行将 Filesystem Cache 中目前所有的数据都 fsync 到磁盘文件中;
- 3.删除旧的 translog 日志文件并创建一个新的 translog 日志文件,此时 commit 操作完成;
三、ES 搜索的过程
搜索过程被分为 Query then Fetch 两个阶段执行:
- Query 阶段
客户端发送请求到协调节点,协调节点将搜索请求广播到所有的 primary shard 或 replica shard。每个分片在本地执行搜索并构建一个匹配文档的大小为 from+size 的优先队列。每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点,由协调节点及执行数据的合并、排序、分页等操作,产生最终结果; - Fetch 阶段
协调节点根据 doc Id 去各个节点上查询实际的 document 数据,由协调节点返回结果给客户端。
原理:
1、协调节点对 doc Id 进行哈希路由,将请求转发到对应的节点,此时会使用 round-robin 随机轮询算法,在 primary shard 以及所有 replica shard 中随机选择一个,让读请求负载均衡;
2、接受请求的节点返回 document 给协调节点;
3、协调节点返回 document 给客户端;
四、Master 节点的选举
4.1 ES 的分布式原理
ES 会对存储的数据进行切分,将数据划分到不同的分片上,同时每一个分片会保存多个副本,主要是为了保证分布式环境的高可用。在 ES 中,节点时对等的,节点间会选取集群的 Master,由 Master 负责集群状态信息的改变,并同步给其他节点。
4.2 ES 如何选举 Master
ES 的选主是 ZenDiscovery 模块负责的,主要包含 Ping 和 Unicast这两部分;
- 确认候选主节点的最少投票通过数量;
- 对所有候选主节点根据 node Id 字典排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个节点,暂时认为它是 Master 节点;
- 如果对某个节点的投票数达到阈值,并且该节点自己也选举自己,那这个节点就是 Master。否则重新选举,一直到满足上诉条件;
4.3 ES 如何避免脑裂现象
- 当集群中 Master 候选节点数不小于 3 个时,可以通过设置最少投票通过数量,设置超过所有候选节点一半以上来解决脑裂问题,即设置为(N / 2)+1;
- 当集群 Master 候选节点只有 2 时,这种情况是不合理的,最好把另外一个 node.master 改成 false;