ES写入数据的工作原理
- 客户端选择一个node发送请求过去,接受数据的这个node在此时相当于coordinating node(协调节点)
- coordinating node首先会对该消息进行hash运算,然后拿hash运算后的值取模,来计算该条数据应存放的shard节点,计算出来这个shard节点之后,会将数据路由到对应的parmary shard节点
- 然后由primary node将数据同步到对应的replica node
- coordinating node 发现primary node 和所有的replica node将该条消息存储之后,就返回响应结果给客户端,告知消息写入成功
ES写入数据的底层流程
es数据写入到primary 节点时,会先写入一个buffer,再buffer里的数据是搜索不到的,同时将数据写入一个tranSlog日志文件
如果buffer快满了或者到一定时间(1s),就会将buffer数据refresh到一个新的segment file种,但是此时数据不是直接进入segmentfile的磁盘文件的,而是先进入os cache,这个过程就是refresh
为什么叫es是准实时的(NRT near real-time 准实时)每隔一秒钟,es将buffer种的数据写入一个新的segment file,每秒钟会产生一个新的磁盘文件,segment file,这个segment file中就存储最近1秒内的buffer中写入数据,如果buffer中没有数据,那么就不会执行refresh操作,并不会每秒创建一个新的segment file文件
此时其实并不是直接将文件保存到磁盘中,操作系统中,针对磁盘文件其实有一个叫做os cache,操作系统级别的缓存,就是说数据写入磁盘文件之前,会先进入os cache,先进入操作系统级别的一个内存缓存中去
也可以主动调用es的refreshAPI来手动将buffer中的数据写入到segment file中
重复1-2步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去,每次refresh完,buffer清空,translog保留,随着这个过程推进,translog会变得越来越大,当translog达到一定长度的时候,就会触发commit操作
buffer中的数据还好,每隔1秒就会被刷到os cache中去,然后这个buffer就被清空了,所以说这个buffer的数据始终是可以保持住不会填满es进程的内存的,但是每写入一条数据就会同步更新一条信息写入到translog日志文件中,所以这个日志文件是不断变大的,当translog日志文件达到一定程度的时候,就会commit操作
commit操作发生第一步,就是将buffer中现有的数据refresh到os cache中去,清空buffer
然后将一个commit point写入磁盘文件,里面标示着这个commit point对应的所有segment file
强行将os cache中的目前所有数据都fsync到磁盘文件中
将现有的translog清空,然后再次重启启用一个translog,此时commit操作完成,默认每隔30分钟就会i自动执行一次commit,但是如果translog,也会触发commit,整个commit过程叫做flush操作,我们额可以手动执行flush操作,就是将所有的os cache数据刷到磁盘文件中去
commit操作其实再ES中不叫commit操作,而是叫flush操作,es中的flush操作对应的就是commit
translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去,所以默认情况下,可能有5秒的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5s左右的数据,但是这样性能比较好,最多丢失5秒的数据,也可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多
如果是删除操作,commit的时候就会生成一个.del文件,里面将某个doc标识为deleted
如果是更新操作,将原来的的doc标识为deleted状态,然后写入一条新的数据
buffer每次refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file,segment file会越来越多,此时会定期执行merge
每次merge的时候,就会进啊嘎多个segment file合并成一个,同时这里会将标识为deleted的doc给物理删除,然后新的segmentfile写入磁盘,这里会写一个commit point,标识所有新的segment file,然后打开segment file供搜索使用,同时删除旧的segment file
commit操作其实进行了三步操作
- 在磁盘上记录下 commit point
- 将os cache 中的数据强行刷进磁盘中
- 将translog日志文件清空
根据上述的运行流程,其实ES是可能会丢失数据的,也就是说,写入数据是每一秒钟往OS-cache中更新一次数据,translog是每5秒钟向此盘中同步一次,同时os-cache每三十分钟会将数据持久化到磁盘中,所以极端情况下,可能会丢失5秒的数据
数据在写入segment file的时候,其实就已经建立好了倒排索引
ES读取数据过程
查询,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客户端
ES搜索数据过程
- 客户端发送一个请求到一个coordinate node
- 调节节点将请求转发到所有的primary shared 进行全局检索
- 每个shared 将检索到的数据路由给coordinate node,此时检索到的数据是doc id
- coordinate node 会将这些doc id去查询所有的document数据,然后封装返回信息