日期:2014-05-16  浏览次数:20759 次

VirtualBox ShareFolder 充当Apache2 源路径时宿主-客户机双缓存机制缺乏沟通导致的微妙问题

      最近发现了一个很有意思的问题。问题的场景是在  Windows Server 2003 x64 + VirtualBox+ Ubuntu 12.04x64 , 具体有点复杂,分几步来说。

     1、 apache2 设置了一个 Alias,原始的Directory 设置的是 /media/sf_images ,这个文件夹是使用VMBox的  Shared folders 从宿主的路径  E:\images 映射过来的,读写权限。

     2、Ubuntu下的 一个后台服务不断的产生一些图片,并在完成后向数据库中写入完成标志。

     3、用户通过网络访问apache2,一个 fcgi 负责响应用户的图片请求。这个FCGI 检测数据库的标志,把确定存在的image返回用户,不存在的,返回一个卡通的“稍等”图片。

     问题出来了。有时,用户通过网络获得的png 图片的 CRC是错误的,在IE上是一个叉叉,预览也木有。用Firefox和PS可以打开,但分析下载下来的文件,发现CRC确实不对。于是跑到Ubuntu下,发现也无法预览,说明这个文件确实没有写对。

     接下来,神奇的事情发生了! 一气之下,重启虚拟机后,相同的文件竟然自己变成对的了!!

    兴奋之下,反复尝试,重演错误,总结出了现象的特点:

     同一个文件,产生后在宿主机器WinSvr003看着是正确的,在Ubuntu虚拟机下,却有些地方不对了(一般是尾部几个-几千个字节)!这样,apache2返回的流肯定有问题。只有重启虚拟机,才能解决问题。


     初步思考,原因应该出在VMBox的共享文件夹的机制上, 应该是Ubuntu 自己有一个缓存,而后Shared Folder 的后台服务有一个缓存(直接使用宿主缓存?),

     1、当后台服务写入文件时,文件经过宿主缓存写入物理磁盘。这个过程需要1秒。所以,当0.7秒时,文件仅仅部分写入了磁盘,还有一部分在宿主的缓存中。这个时候,Ubuntu内部已经“觉得”所有数据全部 flush到磁盘了,其实不知道只是 flush 给了宿主的缓存而已。

     2、恰恰在第0.7秒,客户通过网络访问了 FCGI ,FCGI 读取磁盘,结果,读取的是写了一半的文件,还有一部分尾巴在内存里没有来及写。

     3、更为糟糕的是,由于Ubuntu 自己有缓存,当用户在第2秒第二次读取Shared Folder 里的磁盘文件时,系统认为该文件没变化(在Ubuntu里没有操作啊),直接从缓存里读取,结果还是错误的!

     4、除非重启Ubuntu , 从虚拟机看到的文件始终是错的!但宿主看到的是对的。

    主要原因应该就是,在读写数据时,二者缺乏正确及时的沟通。Ubuntu 写入 Shared folder 只是确保自己的数据全部flush给底层,如果在真正的机器上,底层应该就是磁盘。可是,这是在虚拟机上,底层是宿主的操作系统。宿主操作系统在没有真正写入磁盘时,无法告知虚拟机“它还没写好”,导致虚拟机提前读到了混乱的数据。


      原本为了方便在更换虚拟机时,image文件夹可以不变,但看来还有问题啊!解决方法:新建了一个虚拟硬盘来存放images,而不是使用共享文件夹,问题再也木有出现。


    


1楼goldenhawking3天前 12:55
后面我来试试 VMWare 是不是也有类似的问题。