es中存储数据的基本单位时索引,比如说你现在要在 es 中存储一些订单数据,你就应该在 es 中创建一个索引 order_idx
,所有的订单数据就都写到这个索引里面去,一个索引差不多就是相当于是 mysql 里的一张表。
- index(表类别/数据库) -> type(表) -> mapping(type的表结构定义,7.X 已被完全移除) -> document(mysql 中某个表里的一行) -> field(一个字段的值)
- index拆分为多个shard(分片),每个 shard 存储部分数据。shard分为primary shard和replica shard(类似kafka的副本)。primary shard 写入之后将数据同步到其他几个 replica shard。
- master-slave架构,es 集群多个节点,会自动选举一个节点为 master 节点,这个 master 节点其实就是干一些管理的工作的,比如维护索引元数据、负责切换 primary shard 和 replica shard 身份等。要是 master 节点宕机了,那么会重新选举一个节点为 master 节点。
es 写数据过程
client->coordinating node(协调节点)->根据document路由到相应的node(有primary shard)->primary shard 处理请求并将数据同步到replica node->coordinating node->client
写数据原理
在shard中,每次写入顺序是先写入Lucene,再写入TransLog。
- refresh(1s):client->buffer(lucene缓存,建立倒排索引)->os cache(即filesystme cache es缓存/系统缓存,可查询)。(Elasticsearch是先写内存后写TransLog操作日志/事务日志,refresh的时候,避开了磁盘操作。)
- 与refresh同时进行(5s):os cache->translog(通过translog 日志真正把 segment 刷到磁盘,小的segment归并成大的segment再提交保存)
- flush/commit (30min):translog足够大->refresh->清空buffer到segment file->commit point(存有期间所有的segment file)写入磁盘->清空、重启translog
flush时有 5 秒的数据,停留在os cache->translog的过程中(translog os cache->translog),而不在磁盘(commit point)上及translog中,此时如果宕机,会导致 5 秒的数据丢失。数据恢复是根据translog及commit point回复的,即使宕机的时候数据存在segment file中,而commit point、translog中没有记录此时的segment file,segment file中的数据也无法恢复。
删除/更新数据原理
- 删除操作:commit 的时候会生成一个 .del 文件,里面将某个 doc 标识为 deleted 状态
- 更新操作:将原来的 doc 标识为 deleted 状态,然后新写入一条数据
- buffer 每 refresh 一次,就会产生一个
segment file
,所以默认情况下是 1 秒钟一个segment file
,这样下来segment file
会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个segment file
合并成一个,同时这里会将标识为deleted
的 doc 给物理删除掉,然后将新的segment file
写入磁盘,这里会写一个commit point
,标识所有新的segment file
,然后打开segment file
供搜索使用,同时删除旧的segment file
。
es 读数据过程
- 可以通过
doc id
来查询,会根据doc id
进行 hash,判断出来当时把doc id
分配到了哪个 shard 上面去,从那个 shard 去查询。 - client->协调节点->根据doc id路由到相应的node(有primary shard)->round-robin随机轮询算法在所有replica中随机选择一个replica shard+primary shard->返回document给 coordinate node->client
es 搜索数据过程
- client->协调节点->所有的shard对应的primary shard或replica shard->返回doc id给协调节点->协调节点根据doc id拉取实际的document->client
倒排索引:
- 每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。倒排索引就是关键词到文档 ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。
- 有以下文档:
DocId Doc
1 谷歌地图之父跳槽 Facebook
2 谷歌地图之父加盟 Facebook
倒排索引:
WordId Word DocIds
1 谷歌 1,2
2 跳槽 1 - 用户输入查询 Facebook,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。
性能优化的杀手锏——filesystem cache(os cache):
你往 es 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache
里面去。
- 如果给 filesystem cache 更多的内存,尽量让内存可以容纳所有的 idx segment file 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。
- 最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。
数据预热:
- 做一个专门的缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里面去。
冷热分离:
- 将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 filesystem os cache 里,别让冷数据给冲刷掉。
document 模型设计:
- es 里面的复杂的关联查询尽量别用,一旦用了性能一般都不太好。