分布式搜索引擎面试题系列(建议收藏)
1.说一下es的分布式架构原理 / es是如何实现分布式的
核心思想就是在多台机器上启动多个 es 进程实例,组成了一个 es 集群。
创建一个index,index包含多个shard,每个shard都是一个最小工作单元,每个 shard 存储部分数据。
一个shard 的数据实际是有多个备份,就是说每个 shard 都有一个 primary shard ,接受写和读请求,但是还有几个 replica shard ,负责容错,以及承担读请求负载。 primary shard 写入数据之后,会将数据同步到其他几个 replica shard 上去。这样,每个 shard 的数据都有多个备份,如果某个机器宕机了,还有别的数据副本在别的机器上呢,这样就实现了高可用。
es 集群多个节点,会自动选举一个节点为 master 节点,这个 master 节点其实就是干一些管理的工作的,比如维护索引元数据、负责切换 primary shard 和 replica shard 身份等。要是 master 节点宕机了,那么会重新选举一个节点为 master 节点。
如果某个非 master 节点宕机了。那么此节点上的 primary shard 就没了。那好,master 会让 primary shard 对应的 replica shard(在其他机器上)切换为 primary shard。如果宕机的机器修复了,修复后的节点上的shard也不再是 primary shard,而是 replica shard。同步后续修改的数据之类的,让集群恢复正常。
上述就是 ElasticSearch 作为一个分布式搜索引擎最基本的一个架构设计。
2.说一下es的写入数据流程以及底层原理
1)客户端选择一个node (es节点)发送请求过去,这个node (es节点)就是coordinating node (协调节点),对document (文档)进行路由,将请求转发给对应的node 2)实际的node上的primary shard处理请求,然后将数据同步到replica node 3)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端
es写入数据的原理
- 先写入buffer,在buffer里的时候数据是搜索不到的; 同时将数据写入translog日志文件
- 如果b uffer快满了,或者每隔一秒钟,就会将buffer数据refresh到一个新的segment file中并清空buffer,但是此时数据不是直接进入segment file的磁盘文件的,而是先进入os cache的。 当数据进入os cache后,就代表该数据可以被检索到了。 因此说es是准实时的,这个过程就是 refresh 。
- 只要数据进入os cache,此时就可以让这个segment file的数据对外提供搜索了
- 重复1~3步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完buffer清空,translog保留。 随着这个过程推进,translog会变得越来越大。 当translog达到一定长度的时候,就会触发commit操作。
- commit操作(也叫 flush 操作,默认每隔30分钟执行一次):执行refresh操作 -> 写commit point -> 将os cache数据fsync强刷到磁盘上去 -> 清空translog日志文件
- commit操作保证了在机器宕机时,buffer和os cache中未同步到segment file中的数据还可以在重启之后恢复到内存buffer和os cache中去,
- translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去,所以默认情况下,可能有5秒的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。 但是这样性能比较好,最多丢5秒的数据。 也可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多。
- 如果是删除操作,commit的时候会生成一个.del文件,里面将某个doc标识为deleted状态,那么搜索的时候根据.del文件就知道这个doc被删除了
- 如果是更新操作,就是将原来的doc标识为deleted状态,然后新写入一条数据
- buffer每次refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file,segment file会越来越多,此时会定期执行merge,当segment多到一定的程度时,自动触发merge操作
- 每次 merge 的时候,会将多个segment file合并成一个,同时这里会将标识为deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这里会写一个commit point,标识所有新的segment file,然后打开segment file供搜索使用,同时删除旧的segment file。
3.说一下es的读数据流程
读数据分为GET和Search,即查询一条 和 搜索操作。
查询:
查询操作,即GET某一条数据,写入了某个document,该document会自动给你分配一个全局唯一id-doc id,同时也是根据doc id进行hash路由到对应的primary shard上面去。当然也可以手动指定doc id,比如用订单id,用户id。
可以通过doc id来查询,会根据doc id进行hash,判断出当时把doc id分配到了哪个shard,从那个shard去查询
- 客户端发送请求到任意一个node(节点),成为coordinate node(协调节点)
- coordinate node(协调节点)对document路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard及其所有replica中随机选择,使读请求负载均衡
- 接收请求的node返回document给coordinate node(协调节点)
- coordinate node(协调节点)返回document给客户端
搜索:
- 客户端发送请求到一个 coordinate node
- 协调节点将搜索请求转发到所有的shard对应的 primary shard 或 replica shard
- query phase 每个shard将自己的搜索结果(本质上就是一些doc id),返回给 coordinate node ,由 coordinate node 进行数据的合并、排序、分页等,以生成最终结果
- fetch phase 接着由 coordinate node ,根据doc id去各节点中拉取实际的 document 数据,最终返回给客户端
4.为什么es集群至少需要三个节点
首先需要知道一点:es的配置文件中有一个配置:discovery.zen.minimum master nodes:2 ,默认是2,即选举Master时需要的节点数。
假设es有两个节点,master node 和 data node,即选举Master时锁需要的节点为 1,此时出现网络波动,导致 master node 和 data node出现短暂的断开连接,根据选举规则,data node将自己选举为master,当网络波动结束后,就会出现两个master,即我们所说的脑裂。
当es有三个节点,master node、data data(A)、data node(B),即选举Master时锁需要的节点为 2,此时出现网络波动,master node 和 A 、B断开连接,则 master node降级,A、B进行选举,假设选举为A为master,当网络恢复后,之前的 master node --> data node,之前的 data node(A)--> master node。
所以,通过配置 minimum master nodes 来防止出现脑裂,在生产过程中, 为了尽量保持集群高可用, 至少需要三台机器搭建集群。
end:如果你觉得本文对你有帮助的话,记得关注点赞转发,你的支持就是我更新动力。