即使是不成熟的尝试,也胜于胎死腹中的策略。

执行refresh的时候会存盘吗?

Elasticsearch | 作者 Charele | 发布于2023年08月04日 | 阅读数:1403

一般意义上,认为refresh只是为了可见性,数据并不存到硬盘上。
这个动作由flush去完成。
 
所以,多数人的观点是这样的:
111.PNG

 
这里的这个”文件系统缓存“,也有人说是“操作系统缓存”种种。
 
 我没有明白这个“文件系统缓存”是个什么东东,
是一块介于内存和硬盘之间的某种特殊介质吗???

我观察到的情况是,refresh的时候数据就存盘了,
所以我能证明,"refresh数据不存盘"这个说法,肯定是错的。
 
我也法没法证明 "refresh时,数据会存盘"
也有可能是“有的场景存,有的场景不存”
但至少在我这里,是存盘的
 
 另外,我并不是说“因为fresh存盘了,flush就不需要做了“,没有这个意思。
已邀请:

Ombres

赞同来自: emmning

不是你知道我说的啥吗.....只是说缓冲在哪学。
refresh肯定看ReferenceManager.maybeRefresh()啊,可以了解NRT的实现方式DirectoryReader.openIfChanged(DirectoryReader oldReader),DocumentsWriter.flushAllThreads()。
 
综合看 es的flush是执行lucene的commit,refresh则是 openIfChanged 。
 
至于你说的写入磁盘的时机,了解缓冲才好往后看。
DocumentsWriter.flushAllThreads(),这个其实就是lucene的flush机制,就已经开始向操作系统写了,只是要经过缓冲区,具体写入取决于操作系统(异步操作,文件大写的慢,一般会很快)
 
commit操作 会执行 DocumentsWriter.flushAllThreads() ,随后执行IOUtils.fsync()方法(),会等待操作系统完全写完

 

emmning - for learn you know

赞同来自: Charele

refresh触发数据落盘,数据在写入磁盘前会先写入文件系统缓存异步刷新到磁盘,flush会等待数据正在写入磁盘再返回

Charele - Cisco4321

赞同来自:

那你又知道我说的是啥吗?
 
1 这里刚建的一个索引("index.refresh_interval": -1)
啥数据都没有。
111.PNG

 
 
2 这是我插入一个文档后,手动refresh了一下
可以看到数据文件已经在磁盘上了
222.PNG

 
3 这是我手动flush后的,可以看到,
数据文件还是原来的,没有任何变化。
只是增加了一个提交点文件
333.PNG

 
你不能拿代码来说事,我不懂。
 
 
如果我是小白,你说“refresh不会存盘“,
而现在我又在磁盘上看到了真实存在的文件
你会如何解释?难道你说,不不不,这是假的文件?这是缓冲区的文件?

Charele - Cisco4321

赞同来自:

他上面说的那个“此时文档还没有写磁盘上”,
 
他的意思是说,磁盘上没有数据,一直要到flush后才会有数据

Charele - Cisco4321

赞同来自:

"如果此流的预期目标是由基础操作系统提供的一个抽象(如一个文件),则刷新此流只能保证将以前写入到流的字节传递给操作系统进行写入,但不保证能将这些字节实际写入到物理设备(如磁盘驱动器)。“
这是对Java输出流的flush()方法的解释, 
执行Lucene flush 就是把内存中的像倒排表之类的东西写到文件。
就是一个标准的写文件输出流的过程,
1 建立文件输出流
2 write()
3 close()(flush())
  
 它得到的指令是“写数据文件到磁盘”,
它得到的指令不是:“唉,那个谁,你不要写磁盘,你要写到文件系统缓冲区”
 
至于这个“缓冲区”,究竟如何实现,或者究竟有没有,那是系统不同实现的事,跟ES跟本没有关系。
 
只要不出事,数据文件100%会在磁盘上。

Charele - Cisco4321

赞同来自:

回想你们学习Java的时候,或者在实际工作中,
写入一个文件(输出流)最后的步骤是什么呢?
当然是执行OutputStream的flush()或者close()方法,确保已经写入。
 
还有没有其它操作呢?没有了(或者说你可能想不到别的)
这正是ES refresh(或者Lucene flush)对数据文件所做的。
 
 
楼上说了“随后执行IOUtils.fsync()方法(),会等待操作系统完全写完”,
貌似有道理。好,让我们来看看它做了什么?
111.PNG

它重新打开了数据文件,然后执行了一个force()方法。
 
只有文件在磁盘上,才能用这个api打开的吧。
至少肯定是已经写了部分,
如果此时文件全部都还在那个所谓的“缓冲区”里,
能用这个方法打开吗?????????? 
 
  可能在Lucene场景,有必要这么做确保一下安全。
但通常你在写文件的时候,会不会也这么搞一下来确保安全呢???
没必要吧,或者说,不是所有人都会必须这么搞才安全。
  
 所以,我要说的:
 什么"refresh写数据到文件系统缓冲区“,”refresh不存盘“,这些都是荒唐的。
 
因为Lucene flush,明胆执行的就是一个标准的写磁盘文件操作,
为什么非得说是“写文件系统缓冲区”呢,让人匪夷所思。
 
 
 
 
 

Charele - Cisco4321

赞同来自:

有不同意见的人,欢迎来提

pzw9696

赞同来自:

Charele - Cisco4321

赞同来自:

楼上的朋友发了一个链接,讲的是linux,缓存这类的东西。
(下面表述不针对别人,只是我自言自语:-)
 
  我不否认在Java写文件时有缓存存在,内部实现会先到缓存,再到硬盘。
 
这就能说明ES refresh就是“不是写到磁盘文件,而是写到缓存了”?
 
https://blog.csdn.net/Zain_hor ... 41476
这是一个最简单的Java写文件到磁盘例子,
 ES refresh也是执行的这种操作啊,
 
既然大家都是同样的写硬盘文件,那ES有啥味特别之处吗?
 
为什么非得要说“写到文件系统缓存呢”,而”不是写到硬盘“呢?
  
 反正冥冥中有缓存在,你是不是也可以这么说,我举个例子,
CTO给你布置任务,“那个谁,你写个Java程序,把销售数据从mysql取出来,写到Excel文件,懂事长要看“
 
你纠正说,”总监,你说错了。应该是把数据取出来,写到文件系统缓存,然后刷新到Excel文件!“ 
这不搞笑吗?

Charele - Cisco4321

赞同来自:

假设你能找出代码中,ES refresh时(或者说Lucene flush时),
用的不是Java write() / flush()方法,
 
而是像writeCache()或者writeFilesystemCahce()这种的方法,
 
那我绝对会相信这是先写到缓存,

要回复问题请先登录注册