分布式搜索引擎
ES 分布式原理(如何实现分布式)
概念解释
- index:类似数据库中的表
- type:数据中没有对应的概念,虚拟的逻辑分组,用来过滤、分组 Document
- Document:类似数据库中的数据行
ElasticSearch 设计理念就是分布式搜索引擎,底层依赖 Lucene
多台节点上多个 ES 实例。一个索引拆分成多个 shard 分别存放部分数据
shard 有多个备份,primary 负责写数据,并同步到其他 replica,所有节点都负责读
ES 集群中会自动选举一个节点作为 master,负责维护集群
master 宕机后会重新推选 master,原 master 如果恢复,则需调整其中的 shard
ES 数据操作原理(过程)
数据写入
- 客户端选择一个 node 发送请求,这个 node 就是 coordinating node(协调节点)
- coordinating node 对 document 进行路由(比如 hash),将请求转发给对应的 node (primary shard 所在 node)
- 实际的 node 上的 primary shard处理请求,然后将数据同步到 replica node
- coordinating node 如果发现 primary node 和所有replica node 都搞定之后,就返回响应结果给客户端
数据读取
- 客户端发送请求到任意一个 node,成为 coordinate node
- coordinate node 对 document 进行路由,将请求转发到对应的 node,此时会使用round-robin 随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡
- 接收请求的 node 返回 document 给 coordinate node
- coordinate node 返回 document 给客户端
搜索
- 客户端发送请求到任意一个 node,成为 coordinate node
- coordinate node 将搜索请求转发到所有 shard
- 每个 shard 将自己的搜索结果(doc id)返回,有协调节点进行合并、排序、分页等处理
- coordinate node 根据 doc id 获取实际 document 后返回给客户端
写数据底层原理
- 先写入内存 buffer,同时写入 translog 日志,此时并不能被搜索
- buffer 快满或到达一定时间(默认1s),将 buffer 中的数据 refresh 到一个新的 segment file 中,但此过程的数据并不直接写入磁盘文件,而是首先进入 OS cache(操作系统缓存), 此时已可见
- 数据进入 OS Cache 后,即可使 segment file 的数据对外提供搜索
- 不断重复上述步骤,translog 增大到一定程度后触发 commit 操作
- 发生 commit 时,首先要对当前 buffer 进行 refresh 清空
- 将一个 commit point 写入磁盘文件,标识着所有对应的 segment file
- 强行将 OS Cache 中所有数据(segment file) fsync 到磁盘上
- 清空、新开 translog。默认 30min 执行一次 commit,translog 过大或手动均可触发,commit 操作也叫 flush
- 实际上 translog 也需要经过 os cache,默认 5s flush 一次,这可能导致丢失 5s 的数据,也可以设置每次操作都刷新
translog
写数据过程中,数据保存在 buffer 或 OS Cache,均为内存,不可靠
意外宕机恢复时,ES 会自动读取 translog 恢复数据到 buffer 和 os cache
删除
在 .del
文件中标识删除的文件,并不是去 segment file 上删除文件
更新
将原 doc 标记为删除,并写入新的数据
segment file 的合并
segment file 会越来越多,因此会定期合并
合并时,将多个 segment file 合并为一个,并将标记为删除的数据物理删除。此后会写一个 commit point
ES 数据量很大时,提高查询效率
提升查询性能
ES 搜索性能严重依赖于 OS 底层的 filesystem cache,cache 较大(留给系统的内存)时搜索性能会很高,命中缓存则无需IO
在数据量较大时,需要确保一半的数据在内存才能确保较好的搜索性能
仅向ES中写入与搜索相关的必要字段,将其他数据存到另外的数据库中
数据预热
对于较热的数据,使用一个预热子系统对其进行定期查询,让数据进入缓存
冷热分离
数据拆分,将大量不搜索的字段,分离到其他存储中,类似 MySQL 的垂直拆分
将大量冷数据单独写一个索引,热数据单独建立索引,类似 MySQL 的水平拆分
document 模型设计
一般不使用 ES 进行关联查询,性能一般较差,如果业务需要,一般直接在代码中处理或存储冗余数据
分页性能优化
ES 的分页性能较差,例如需要10条一页的第十页数据,则需要每个shard将100条数据发送到协调节点,由协调节点排序、分页处理后返回。当翻页深度较大时性能会很差
解决办法:
- 不允许深度分页、允许性能随深度下降
- 使用下拉加载 scroll api(一次性给所有的数据生成一个快照,翻页就是移动游标,不支持跳页、指定页面跳转)
ES 生产集群的部署架构、索引、分片
回答举例:
ES 集群部署了 5 台机器,均为 6 核 64G,集群总内存 320G
ES 集群日增数据量 2000 万,约 500 M,每月大概6亿,15G,运行数月,约有100G数据
线上有 5 个索引,每个索引约 20G,当前数据量下,为每个索引分配 8 个 shard,比默认多 3 个