强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

systemd 教程 / Path 监控

Path 监控

概述

Path 单元是 systemd 提供的一种文件系统监控机制,可以监控文件或目录的变化,并自动触发关联的服务。它基于 Linux 内核的 inotify 机制实现,适用于文件上传触发处理、目录监控自动部署等场景。


Path 单元文件

基本结构

Path 单元文件以 .path 为后缀,核心配置在 [Path] 段中:

# /etc/systemd/system/watcher.path
[Unit]
Description=Watch Upload Directory

[Path]
DirectoryNotEmpty=/data/uploads
Unit=processor.service

[Install]
WantedBy=multi-user.target

[Path] 段关键参数

参数说明示例
PathExists文件存在时触发PathExists=/tmp/trigger
PathExistsGlob匹配 glob 模式的文件存在时触发PathExistsGlob=/data/*.csv
PathChanged文件内容关闭后变化时触发PathChanged=/etc/config.yaml
PathModified文件内容实时修改时触发PathModified=/var/log/app.log
DirectoryNotEmpty目录非空时触发DirectoryNotEmpty=/data/uploads
Unit触发的服务单元Unit=processor.service
MakeDirectory自动创建监控目录MakeDirectory=true
DirectoryMode自动创建目录的权限DirectoryMode=0755

监控类型详解

PathExists

当指定路径存在时立即触发。适用于一次性触发场景:

[Path]
PathExists=/run/myapp/trigger
Unit=myapp.service

⚠️ 注意PathExists 只在文件从不存在变为存在时触发,如果文件一直存在则不会重复触发。

PathExistsGlob

使用 glob 模式匹配文件:

[Path]
PathExistsGlob=/data/import/*.csv
Unit=import-csv.service

支持的 glob 通配符:

通配符说明示例
*匹配任意字符(不含 /*.csv
?匹配单个字符data?.txt
[abc]匹配方括号内的字符[abc].log

PathChanged

当文件被写入后关闭时触发。适用于监控配置文件变化:

[Path]
PathChanged=/etc/myapp/config.yaml
Unit=myapp-reload.service

💡 提示PathChanged 在文件写入完成后才触发,适合监控需要原子更新的配置文件。

PathModified

文件内容被修改时实时触发(不需要关闭文件):

[Path]
PathModified=/var/log/app/current.log
Unit=log-processor.service

⚠️ 注意PathModified 可能会频繁触发(每次写入都触发),需要注意服务的去重处理。

DirectoryNotEmpty

当目录从空变为非空时触发:

[Path]
DirectoryNotEmpty=/var/spool/mail
Unit=mail-notifier.service

事件触发机制

inotify 后端

systemd 使用 Linux 内核的 inotify 子系统实现文件监控:

inotify 事件类型:
├── IN_CREATE     → PathExists / PathExistsGlob
├── IN_DELETE     → PathExists / PathExistsGlob
├── IN_CLOSE_WRITE → PathChanged
├── IN_MODIFY     → PathModified
└── IN_MOVED_TO   → PathExistsGlob

查看 inotify 限制

# 查看系统 inotify 限制
cat /proc/sys/fs/inotify/max_user_instances
cat /proc/sys/fs/inotify/max_user_watches
cat /proc/sys/fs/inotify/max_queued_events

# 增加 inotify 监控数量限制
echo 524288 | sudo tee /proc/sys/fs/inotify/max_user_watches

⚠️ 注意:如果监控的目录包含大量文件,可能需要增加 max_user_watches 限制。

事件去抖动

systemd 的 Path 单元内建了去抖动(debounce)机制:

  • PathChanged:在文件关闭后等待一小段时间再触发,避免重复
  • PathModified:使用合理的触发间隔

如果需要更精细的去抖动控制,可以在被触发的服务中实现:

# /etc/systemd/system/process-uploads.service
[Unit]
Description=Process Uploads

[Service]
Type=oneshot
# 等待几秒确保所有文件写入完成
ExecStartPre=/bin/sleep 2
ExecStart=/opt/scripts/process-uploads.sh

Path 与 Service 联动

基本联动

Path 单元触发服务启动:

# /etc/systemd/system/watcher.path
[Unit]
Description=Watch for new files

[Path]
DirectoryNotEmpty=/data/uploads
Unit=processor.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/processor.service
[Unit]
Description=Process uploaded files

[Service]
Type=oneshot
ExecStart=/opt/scripts/process.sh

使用模板单元

可以使用模板单元,Path 单元的名称会传递给服务:

# /etc/systemd/system/[email protected]
[Unit]
Description=Watch %i

[Path]
DirectoryNotEmpty=/data/%i
Unit=processor@%i.service
# /etc/systemd/system/[email protected]
[Unit]
Description=Process %i

[Service]
Type=oneshot
ExecStart=/opt/scripts/process.sh %i
# 启动监控
sudo systemctl enable --now [email protected]

实际案例

案例 1:监控目录自动处理文件上传

场景:用户通过 FTP/SFTP 上传文件到 /data/uploads,自动触发处理脚本。

# /etc/systemd/system/upload-watcher.path
[Unit]
Description=Watch upload directory for new files

[Path]
DirectoryNotEmpty=/data/uploads
MakeDirectory=true
DirectoryMode=0755

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/upload-watcher.service
[Unit]
Description=Process uploaded files

[Service]
Type=oneshot
User=processor
Group=processor
WorkingDirectory=/data/uploads
ExecStartPre=/bin/sleep 2
ExecStart=/opt/scripts/process-uploads.sh
StandardOutput=journal
StandardError=journal
# 创建监控用户
sudo useradd -r -s /bin/false processor

# 创建目录并设置权限
sudo mkdir -p /data/uploads
sudo chown processor:processor /data/uploads

# 启用并启动
sudo systemctl enable --now upload-watcher.path

# 检查状态
systemctl status upload-watcher.path

案例 2:文件上传触发编译

场景:监控源代码目录,文件变化时自动触发构建。

# /etc/systemd/system/auto-build.path
[Unit]
Description=Watch source directory for changes

[Path]
PathChanged=/opt/project/src
Unit=auto-build.service

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/auto-build.service
[Unit]
Description=Auto build project

[Service]
Type=oneshot
WorkingDirectory=/opt/project
ExecStart=/usr/bin/make build
StandardOutput=journal
StandardError=journal

案例 3:监控配置文件自动重载

# /etc/systemd/system/config-watcher.path
[Unit]
Description=Watch configuration file

[Path]
PathChanged=/etc/myapp/config.yaml
Unit=config-reload.service
# /etc/systemd/system/config-reload.service
[Unit]
Description=Reload myapp configuration

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl reload myapp.service

案例 4:邮件通知触发

# /etc/systemd/system/mail-watcher.path
[Unit]
Description=Watch for new mail

[Path]
DirectoryNotEmpty=/var/spool/mail
Unit=mail-notifier.service
# /etc/systemd/system/mail-notifier.service
[Unit]
Description=Send mail notification

[Service]
Type=oneshot
ExecStart=/opt/scripts/notify-mail.sh
User=mail

Path vs inotifywait 对比

对比项systemd Pathinotifywait
集成度原生 systemd 集成独立工具
配置方式单元文件命令行参数
去抖动内建支持需手动实现
服务联动直接触发服务需要脚本包装
监控粒度5 种类型更多事件类型
资源占用由 systemd 统一管理独立进程
持久化systemd 管理开机启动需要额外配置

inotifywait 替代方案

如果 Path 单元无法满足需求,可以使用 inotifywait 配合 systemd 服务:

# /etc/systemd/system/inotify-watcher.service
[Unit]
Description=Inotify watcher for /data

[Service]
Type=simple
ExecStart=/usr/bin/inotifywait -m -r -e create,modify /data/uploads
Restart=always
RestartSec=5s

💡 提示:对于简单的目录监控,优先使用 Path 单元;对于需要复杂事件过滤的场景,考虑使用 inotifywait 或 fswatch。


调试 Path 单元

检查 Path 状态

# 查看 path 单元状态
systemctl status watcher.path

# 查看 path 单元详细信息
systemctl show watcher.path

# 查看触发的服务状态
systemctl status watcher.service

手动测试触发

# 触发 PathExists
touch /tmp/trigger

# 触发 DirectoryNotEmpty
echo "test" > /data/uploads/test.txt

# 触发 PathChanged
echo "new_value" >> /etc/myapp/config.yaml

查看日志

# 查看 path 单元日志
journalctl -u watcher.path

# 查看触发的服务日志
journalctl -u watcher.service

# 实时监控
journalctl -fu watcher.path

常见问题排查

问题原因解决方案
Path 不触发Path 单元未启动systemctl start watcher.path
触发后服务未启动Unit 配置错误检查单元文件名拼写
inotify 资源不足监控数量超限增加 max_user_watches
频繁触发PathModified 过于敏感改用 PathChanged 或增加去抖动
权限问题systemd 无权访问目录检查目录权限和 SELinux/AppArmor

⚠️ 注意:如果使用 SELinux,可能需要为监控的目录设置正确的上下文标签。


实用命令汇总

# 启用并启动 path 单元
sudo systemctl enable --now watcher.path

# 停止并禁用
sudo systemctl disable --now watcher.path

# 重新加载配置
sudo systemctl daemon-reload

# 查看所有活跃的 path 单元
systemctl list-units --type=path

# 查看 path 单元依赖
systemctl list-dependencies watcher.path

扩展阅读