目录
1 es 写数据过程
2 es 读数据过程
3 es 搜索数据过程
4 写数据底层原理
5 删除/更新数据底层原理
coordinating node
(协调节点)。coordinating node
对 document 进行路由,将请求转发给对应的 node(有 primary shard)。primary shard
处理请求,然后将数据同步到 replica node
。coordinating node
如果发现 primary node
和所有 replica node
都搞定之后,就返回响应结果给客户端。可以通过 doc id
来查询,会根据 doc id
进行 hash,判断出来当时把 doc id
分配到了哪个 shard 上面去,从那个 shard 去查询。
coordinate node
(协调节点)。coordinate node
对 doc id
进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin
随机轮询算法,在 primary shard
以及其所有 replica 中随机选择一个,让读请求负载均衡。coordinate node
。coordinate node
返回 document 给客户端。es 最强大的是做全文检索,就是比如你有三条数据:
java真好玩儿啊 java好难学啊 j2ee特别牛
你根据 java
关键词来搜索,将包含 java
的 document
给搜索出来。es 就会给你返回:java真好玩儿啊,java好难学啊。
coordinate node
。primary shard
或 replica shard
,都可以。doc id
)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。doc id
去各个节点上拉取实际的 document
数据,最终返回给客户端。写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法,在primary shard 或 replica shard中选择读取.
1)先写入buffer,在buffer里的时候数据是搜索不到的;之后每隔1s刷入os cache,同时将数据写入translog日志文件
2)如果buffer快满了,或者到一定时间,就会将buffer数据refresh到一个新的segment file中,但是此时数据不是直接进入segment file的磁盘文件的,而是先进入os cache的。这个过程就是refresh。
每隔1秒钟,es将buffer中的数据写入一个新的segment file,每秒钟会产生一个新的磁盘文件,segment file,这个segment file中就存储最近1秒内buffer中写入的数据
但是如果buffer里面此时没有数据,那当然不会执行refresh操作咯,每秒创建换一个空的segment file,如果buffer里面有数据,默认1秒钟执行一次refresh操作,刷入一个新的segment file中
操作系统里面,磁盘文件其实都有一个东西,叫做os cache,操作系统缓存,就是说数据写入磁盘文件之前,会先进入os cache,先进入操作系统级别的一个内存缓存中去
只要buffer中的数据被refresh操作,刷入os cache中,就代表这个数据就可以被搜索到了
为什么叫es是准实时的?NRT,near real-time,准实时。默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1秒之后才能被看到。
可以通过es的restful api或者java api,手动执行一次refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。
只要数据被输入os cache中,buffer就会被清空了,因为不需要保留buffer了,数据在translog里面已经持久化到磁盘去一份了
3)只要数据进入os cache,此时就可以让这个segment file的数据对外提供搜索了
4)重复1~3步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完buffer清空,translog保留。随着这个过程推进,translog会变得越来越大。当translog达到一定长度的时候,就会触发commit操作。
buffer中的数据,倒是好,每隔1秒就被刷到os cache中去,然后这个buffer就被清空了。所以说这个buffer的数据始终是可以保持住不会填满es进程的内存的。
每次一条数据写入buffer,同时会写入一条日志到translog日志文件中去,所以这个translog日志文件是不断变大的,当translog日志文件大到一定程度的时候,就会执行commit操作。
5)commit操作发生第一步,就是将buffer中现有数据refresh到os cache中去,清空buffer
6)将一个commit point写入磁盘文件,里面标识着这个commit point对应的所有segment file
7)强行将os cache中目前所有的数据都fsync到磁盘文件中去
translog日志文件的作用是什么?就是在你执行commit操作之前,数据要么是停留在buffer中,要么是停留在os cache中,无论是buffer还是os cache都是内存,一旦这台机器死了,内存中的数据就全丢了。
所以需要将数据对应的操作写入一个专门的日志文件,translog日志文件中,一旦此时机器宕机,再次重启的时候,es会自动读取translog日志文件中的数据,恢复到内存buffer和os cache中去。
commit操作:1、写commit point;2、将os cache数据fsync强刷到磁盘上去;3、清空translog日志文件
8)将现有的translog清空,然后再次重启启用一个translog,此时commit操作完成。默认每隔30分钟会自动执行一次commit,但是如果translog过大,也会触发commit。整个commit的过程,叫做flush操作。我们可以手动执行flush操作,就是将所有os cache数据刷到磁盘文件中去。
不叫做commit操作,flush操作。es中的flush操作,就对应着commit的全过程。我们也可以通过es api,手动执行flush操作,手动将os cache中的数据fsync强刷到磁盘上去,记录一个commit point,清空translog日志文件。
9)translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去,所以默认情况下,可能有5秒的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。但是这样性能比较好,最多丢5秒的数据。也可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多。
实际上你在这里,如果面试官没有问你es丢数据的问题,你可以在这里给面试官炫一把,你说,其实es第一是准实时的,数据写入1秒后可以搜索到;可能会丢失数据的,你的数据有5秒的数据,停留在buffer、translog os cache、segment file os cache中,有5秒的数据不在磁盘上,此时如果宕机,会导致5秒的数据丢失。
如果你希望一定不能丢失数据的话,你可以设置个参数,官方文档,百度一下。每次写入一条数据,都是写入buffer,同时写入磁盘上的translog,但是这会导致写性能、写入吞吐量会下降一个数量级。本来一秒钟可以写2000条,现在你一秒钟只能写200条,都有可能。
es里的写流程,有4个底层的核心概念,refresh、flush、translog、merge
当segment file多到一定程度的时候,es就会自动触发merge操作,将多个segment file给merge成一个segment file。
如果是删除操作,commit 的时候会生成一个 .del
文件,里面将某个 doc 标识为 deleted
状态,那么搜索的时候根据 .del
文件就知道这个 doc 是否被删除了。
如果是更新操作,就是将原来的 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
。