1)客户端任意选择一个node发送请求过去,这个node就是coordinating node(协调节点)
2)coordinating node,对该数据经过hash后,判断该数据属于哪个shard进程,找到有该shard的primary shard的node,然后对document进行路由,将请求转发给对应的node(有primary shard的结点)
3)具体接收的primary shard处理请求,然后将数据同步到replica node
4)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端
写数据底层原理
1)先写入buffer, 在buffer里的时候数据是搜索不到 的;同时将数据写入 translog日志文件 (防止宕机buffer数据丢失)
2)如果 buffer快满了 , 或者到一定时间 ,就会将buffer数据refresh到一个 新的segment file中 ,但是此时数据不是直接进入segment file的磁盘文件的,而是先进入os cache的。这个过程就是refresh。
默认每隔1秒钟,es将buffer中的数据写入一个 新的segment file,每秒钟会产生一个新的磁盘文件 segment file ,这个segment file中就存储最近1秒内buffer中写入的数据
但是如果buffer里面此时 没有数据 ,那当然 不会执行refresh *** 作,不会创建文件 ,如果buffer里面有数据,默认1秒钟执行一次refresh *** 作,刷入一个新的segment file中;
*** 作系统里面,磁盘文件其实都有一个东西,叫做os cache, *** 作系统缓存,就是说 数据写入磁盘文件之前,会先进入os cache,先进入 *** 作系统级别的一个内存缓存中去,再进入磁盘
只要buffer中的数据被refresh *** 作,刷入os cache中,就代表这个数据就可以被搜索到了 , 只要数据被输入os cache中,buffer就会被清空了,因为不需要保留buffer了,数据在translog里面已经持久化到磁盘去一份了
3)只要数据进入os cache,此时就可以让这个segment file的数据对外提供搜索了
4)重复1~3步骤,新的数据不断进入buffer和translog,不断将buffer数据写入一个又一个新的segment file中去(数据写入到segment file里后就建立好了倒排索引),每次refresh完buffer清空,translog保留。随着这个过程推进,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到磁盘文件中去
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 *** 作,就对应着tanslog commit的全过程 。我们也可以通过es api,手动执行flush *** 作,手动将os cache中的数据fsync强刷到磁盘上去,记录一个commit point,清空translog日志文件。
9) translog其实也是先写入os cache的,默认每隔5秒刷一次到磁盘中去
所以默认情况下, 可能有5秒的数据会仅仅停留在buffer或者translog文件的os cache中,如果此时机器挂了,会丢失5秒钟的数据。但是这样性能比较好,最多丢5秒的数据。也可以将translog设置成每次写 *** 作必须是直接fsync到磁盘,但是性能会差很多。
10)如果是删除 *** 作,commit的时候会生成一个.del文件(磁盘),里面将某个doc标识为deleted状态,那么搜索的时候根据.del文件就知道这个doc被删除了
11)如果是 更新 *** 作,就是将原来的doc标识为deleted状态,然后新写入一条数据
12)buffer每次refresh一次,就会产生一个segment file,所以默认情况下是1秒钟一个segment file, segment file会越来越多,此时会定期执行merge
13) 每次merge的时候,会将多个segment file合并成一个,同时这里会将标识为deleted的doc给物理删除掉,然后将新的segment file写入磁盘,这里会写一个commit point,标识所有新的segment file,然后打开segment file供搜索使用,同时删除旧的segment file。
https://www.elastic.co/guide/en/elasticsearch/guide/2.x/near-real-time.html
https://www.elastic.co/guide/en/elasticsearch/guide/2.x/merge-process.html
1、数据存储可靠性保证原理
1.1 translog机制
当一个文档写入Lucence后是存储在内存中的,即使执行了refresh *** 作仍然是在文件系统缓存中,如果此时服务器宕机,那么这部分数据将会丢失
当进行文档写 *** 作时会先将文档写入Lucene,然后写入一份到translog,写入translog是落盘的
tips:如果对可靠性要求不是很高,也可以设置异步落盘,可以提高性能,由配置index.translog.durability和index.translog.sync_interval控制
tips:translog是追加写入,因此性能比较好
先写入Lucene再写入translog。原因是写入Lucene可能会失败,为了减少写入失败回滚的复杂度,因此先写入Lucene
1.2 flush *** 作
refresh_interval定时触发 或当translog达到index.translog.flush_threshold_size(默认512mb),ES会触发一次flush *** 作:先执行refresh *** 作将buffer中的数据生成segment,然后调用lucene的commit方法将所有内存中的segment fsync到磁盘,最后会清空translog中的数据(6.x版本为了实现sequenceIDs,不删除translog) 。
1.3 merge *** 作
refresh *** 作会产生大量的小segment,因此产生的每个文件都会消耗文件句柄,内存,CPU 使用等各种资源。更重要的是每个查询请求都要顺序检查每个segmentsegment越多检索会越慢.
ES会运行一个检测任务,在后台把近似大小的segment合并成一个新的大segment,并删除旧segment
1.4、多副本机制
ES有多副本机制(默认是1个副本),一个分片的主副分片不能分片在同一个节点上,进一步保证数据的可靠性。
2、ES写索引的流程
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)