meta 目录改完名,我用 inotify 才发现软链没跟着动
目录结构:meta 仓库在 /data/meta,线上服务读取的是 /srv/meta,中间是一层软链。版本是 meta 0.9.4,机器是 Ubuntu 20.04,目录里约 6.8 万个文件,单文件大多在 2KB 到 40KB 之间。现象是:在 /data/meta 里改文件名之后,服务端读到的还是旧名字,重启进程才恢复。
我的做法是先确认软链和挂载点,不急着改服务:
readlink -f /srv/meta
findmnt -T /srv/meta
确认 /srv/meta 只是指向 /data/meta 的软链,没有单独挂载。然后用 inotifywait 只盯改名和移动事件,不盯全量写事件,避免 6.8 万文件刷屏:
inotifywait -m -r -e moved_to -e moved_from -e delete \
--format '%T %e %w%f' --timefmt '%H:%M:%S' /data/meta \
| tee /tmp/meta-rename.log
结果很清楚:改名的路径在日志里出现了,但服务读的 /srv/meta 下没有对应事件。因为软链本身不产生 inotify 事件,服务进程持有的又是旧目录项缓存。我的处理是把服务改成读真实路径,软链只留给人用;如果不方便改,就在改名后 touch 一下目标目录,逼内核重新走路径解析。
为什么这样做:inotify 监听的是 inode 和目录项,软链只是路径字符串,跨过软链这一层不会产生事件;而 rename 本身不修改文件内容,只改目录项,靠内容校验或定时全量扫描都抓不到。代价是 inotify 有 max_user_watches 上限,6.8 万文件我只监听了目录层,没有监听每个文件的属性事件,否则要调高 fs.inotify.max_user_watches,内存也会跟着涨。
哪里会失效:一是跨文件系统 mv 不是 rename,会变成复制加删除,事件类型不同;二是 NFS 或容器挂载的目录,inotify 本身不可靠,我在这类环境上试过,事件会丢;三是批量改名时日志会短时间暴涨,得配合限速或只保留 moved_to。我自己踩过的坑是拿 mv 改目录名之后,又用 rsync 同步了一次,结果两边目录项对不上,排查了很久才发现是软链那层没刷新。
你们那套 meta 目录是直接读真实路径,还是也隔了一层软链?如果是后者,改名之后服务端是怎么感知到的?
0 条评论
还没有评论,写下第一条。