前言
前面我们讲了ElasticSearch从认识到安装,到基本CRUD和SpringBoot整合ES实战,相信你学完之后就可以把ES融入到企业级项目开发了。本篇文章我们将深入了解一下ElasticSearch原理性的东西,我会以面试题总结的方式来展开。
常见面试题
为什么要选择全文搜索引擎,而不直接用like
可能你会觉得问这个问题的面试官有点傻,但是真有人这么问,为什么要使用全文检索引擎而不直接使用Mysql的like进行关键字检索。不一样能达到效果吗?
实际上当你的数据量不是特别庞大的时候,使用like进行模糊查询是完全没有问题的,您可以在你自己的电脑上做一个测试,只要你CPU,内存不是很差,几十万的数据使用 like进行模糊查询其实还是蛮快的,但是数据量再大一点就不好说了,数据库肯定遭不住。所以我们在做技术选型的时候需要进行评估,你的业务数据会不会增长特别快,比如:2年内预估会上百万或是千万或是更大,如果是这种情况可以直接上搜索引擎。很多企业前期还是不会投入太多技术成本,而是等到后期数据量上来再做技术转型和优化。
为什么用ES做全文检索比数据库使用 like 快
我们都知道使用 like的话会进行全文扫描,数据库会带着搜索的关键字去长文本中进行逐一匹配,当你数据量达到一定程度,那么这个扫描是非常非常耗时的。这个时间消耗往往是我们无法承担的,所以要思考优化,ElasticSearch(ES)全文检索引擎是一个不错的选择。为什么ES可以做到很快的检索呢?
这个要提到我们之前有介绍过的《ES倒排索引原理》,在ES中通过分词器把我们的数据源(文本)分词后,再进行一系列的处理形成一个有序的倒排索引文档
。有序的数据结构就可以使用算法比如二分查找进行快速搜索。所以ES的搜索是对倒排索引的快速查找,而不是对全文本的逐一扫描,当然比like快。
创建索引的过程
搜索索引的过程
ES的数据分片机制你了解吗
ES本身是分布式架构,一个ES集群由多个Node节点组成,在ES中的一个index索引由多个shard分片组成,分布在多台Node服务器上存储,数据分片的目的一是为了方便横向扩展,二是可以让搜索工作分布在多台及其上去执行,有效提升整体吞吐量。
而为了防止shard宕机达到高可用的目的,每个Shard又可以有多个Replica 副本。就有了primary shard和replica shard主从的概念。
比如一个ES集群中有三个Node,索引被设置为3个主shard,1个备shard,如下:
这里的P代表主分片,R代表背分片。一对主备分片是不允许分配在一台Node机器上的。这里的备分片既可以做故障转移(主down机了,备自动提升为主),也可以分担读的压力,备分片的数据是从主分片复制而来的。
在ES中默认是5主1备,可以在创建索引的时候设置主备分片数量,但是主分片数量一旦设置好就不可更改,备分片的数量可以动态修改。
另外,当我们增加或者减少Node机器时,分片也会自动的在Node中进行负载均衡(重新分配)
了解ES的节点类型吗
默认情况下,elasticsearch集群中每个节点都有成为主节点的资格,也都存储数据,还可以提供查询服务。在生产环境下,如果不修改elasticsearch节点的角色信息,在高数据量,高并发的场景下集群容易出现脑裂等问题。这些功能是由两个属性控制的。node.master 和 node.data 默认情况下这两个属性的值都是true。
主节点master
node.master=true,代表该节点有成为主资格,主节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。一般会把主节点和数据节点分开,node.master=true , node.data=false
数据节点data
node.data=true,数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等,数据节点对CPU,IO,内存要求较高,优化节点的时候需要做状态监控,资源不够时要做节点扩充。配置:mode.master=false,mode.data=true
负载均衡节点client
当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。配置:mode.master=false,mode.data=false
最佳实践
在一个生产集群中我们可以对这些节点的职责进行划分,建议集群中设置3台以上的节点作为master节点,这些节点只负责成为主节点,维护整个集群的状态。再根据数据量设置一批data节点,这些节点只负责存储数据,后期提供建立索引和查询索引的服务,这样的话如果用户请求比较频繁,这些节点的压力也会比较大,所以在集群中建议再设置一批client节点(node.master: false node.data: false),这些节点只负责处理用户请求,实现请求转发,负载均衡等功能。
描述一下ES添加文档的过程
这个问题是有些深度了,如果你不了解ES的分片机制你根本就答不对。
- 首先,客户端的请求会到达一个协调节点coordinating node。
- 协调节点根据算法选择一个primary shard: 算法 hash(document_id) % (num_of_primary_shards)
- 然后把数据发送给对应的primary shard, 所在节点保存完数据后,将数据同步到replica node备节点。
- 协调节点coordinating node 发现 primary node 和所有 replica node 都搞定之后返回结果给客户端
数据节点存储数据详细流程
当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒,所以ES是近实时,写到读有1s延迟)写入到Filesystem Cache,这个从Momery Buffer到Filesystem Cache的过程就叫做refresh
当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush;
在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时;
详细描述一下Elasticsearch获取文档的过程
- 客户端请求一个协调节点coordinating node
- coordinate node 根据算法hash(document_id) % (num_of_primary_shards),将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡
- 接收到请求的 node 返回 document 给调节点 coordinate node。
coordinate node 返回 document 给客户端。
搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch;
详细描述一下Elasticsearch搜索过程
- 在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。
- 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。PS:在搜索的时候是会查询Filesystem Cache的,但是有部分数据还在Memory Buffer,所以搜索是近实时的。
- 每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点,协调节点它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
- 接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。
详细描述一下Elasticsearch更新和删除文档的过程
删除和更新也都是写操作,但是Elasticsearch中的文档是不可变的,因此不能被删除或者改动以展示其变更; 磁盘上的每个段都有一个相应的.del文件。当删除请求发送后,文档并没有真的被删除,而是在.del文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在.del文件中被标记为删除的文档将不会被写入新段。
在新的文档被创建时,Elasticsearch会为该文档指定一个版本号,当执行更新时,旧版本的文档在.del文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。