FUSE耗尽LXC容器内存问题解决
大量网络文件协议需要利用FUSE(用户空间文件系统)挂载成本地目录,例如SSHFS、CurlFtpFS、EncFS等。而此挂载过程随着IO和网络请求的产生必然会形成缓存,其中包括FUSE协议本身使用的缓存以及内核缓存。在物理机和硬件虚拟化(Hypervisor)环境下,这些缓存会在内存中体现为cache,内存耗尽时将会自动被挤出,并不会对系统产生影响。但是,在LXC等容器环境下,受限于请求控制,这些缓存并无法被标记为cache,而是标记为正在使用的实际内存,虽然最终内存耗尽时仍会部分被挤出,但对于运维等服务器管理工作来说,会造成不必要的误会。
Kaijia的服务器利用SSHFS在LXC内挂载并顺序读取位于另一台远程服务器上的数据,每个文件均有数百兆大小。经过数周观察,Kaijia发现即使挂载时已经禁用了FUSE缓存(“cache=no”),在连续读取多个文件后,LXC内部将会显示标记为used的内存已经占满了全部内存总量(例如使用“free -m”查看时)。除非强行卸载并重新挂载SSHFS(“umount /path/to/directory/; mount -a”),该数据并不会下降。这导致的一个问题便是Zabbix经常错误地报告系统内存已经耗尽。
参阅了FUSE的文档后,Kaijia发现了一个简单解决问题的FUSE参数——direct_io,它被描述为:
This option disables the use of page cache (file content cache) in the kernel for this filesystem. This has several affects:
此参数禁止此文件系统使用内核页缓存,效果包括:
- Each read() or write() system call will initiate one or more read or write operations, data will not be cached in the kernel.
每个read()和write()调用将启动一个或多个读写操作,数据将不会被缓存在内核中。- The return value of the read() and write() system calls will correspond to the return values of the read and write operations.
read()和write()调用的返回值将对应读写操作的返回值。
简单的说,direct_io既是使FUSE读取的内容不写入缓存,直接以先进先出形式传输至IO,从而避免了缓存被视为实际使用中内存的问题,因此,只需要挂载文件是加入direct_io参数,例如:
1 |
user@host:/path/to/remote /path/to/local fuse.sshfs defaults,direct_io,cache=no,_netdev 0 0 |
即可避免FUSE在容器中的内存问题。
评论