如何在生产环境安全地开启慢日志?
解读
面试官问“生产环境”“安全地”开启慢日志,核心考察三点:
- 对 PHP-FPM 慢日志机制与 MySQL 慢查询日志机制的区别与配置细节是否熟悉;
- 是否具备“最小可用、最小暴露、最小影响”的线上变更意识;
- 能否把日志采集、存储、脱敏、轮转、监控闭环讲清楚,避免“开了日志却没人看”或“日志爆盘”的运维事故。
国内大厂/金融/政务云等场景对 GDPR、等保 2.0、国密合规要求极高,答案必须体现“可审计、可回滚、可告警”。
知识点
- PHP-FPM slowlog:
request_slowlog_timeout、slowlog 文件路径、php_admin_value[disable_functions] 防止 Web 用户读日志。 - MySQL slow_query_log:
long_query_time、log_slow_extra、log_timestamps、max_slowlog_size(8.0+)、slow_log 表转存。 - 内核级安全:
日志目录挂载独立 inode、noexec/nodev/nosuid、auditd 监控 chmod/chown、SELinux/AppArmor 策略。 - 敏感信息脱敏:
正则滤身份证号、手机号、银行卡号;国密 SM4 加密后再落盘。 - 日志轮转:
logrotate copytruncate + compress,按 100 MB 切割、保留 14 天,避免 IO 抖动。 - 观测与告警:
日志接入 ELK/ClickHouse,Grafana 配置“单实例 5 min 内慢查询 >100 条”即飞书/企微/钉钉告警;
Prometheus + Exporter 采集 phpfpm_slow_requests_total。 - 变更流程:
国内互联网标准“灰度→监控→全量”三步走;变更单需三级审批,保留 30 天回滚脚本。
答案
线上开启慢日志的“七步安全法”:
- 评估窗口:选低峰时段(通常 02:00–05:00),先在预发布环境压测,确认 IO 增幅 <3%。
- 目录隔离:
mkdir -p /var/log/php-slow /var/log/mysql-slow
chown www-data:adm /var/log/php-slow
chmod 0750 /var/log/php-slow
挂载独立 5 GB lv,加 attr +a 防止误删。 - PHP-FPM 配置:
[www]
request_slowlog_timeout = 1s
slowlog = /var/log/php-slow/www-$pool.log
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
重载:systemctl reload php-fpm,禁止直接 restart,防止长连接 502。 - MySQL 配置:
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;
SET GLOBAL log_slow_extra = 1;
将 slow_log 表改为 CSV 引擎并 truncate,避免 mysql 库膨胀。 - 脱敏与加密:
rsyslog 模板中用 mmexternal 调用国密 SM4 动态库,对 18 位身份证、11 位手机全字段加密;
日志文件属组 adm,禁止 www-data 读取,防止 WebShell 下载。 - 轮转与清理:
/etc/logrotate.d/php-slow:
/var/log/php-slow/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
postrotate
systemctl reload php-fpm > /dev/null 2>&1 || true
endscript
}
加 cron 每日 06:00 执行,轮转后立刻 fsync 刷盘。 - 监控与回滚:
日志接入公司统一 Kafka → Flink → ClickHouse;
Grafana 面板配置“单实例 1 min 慢请求率突增 3σ”即告警;
保留 Ansible 回滚剧本:关闭慢日志只需 SET GLOBAL slow_query_log = 0; 并 reload php-fpm,30 s 内可回滚。
变更记录录入 Jira,审计保存 180 天,满足等保要求。
拓展思考
- 若业务使用容器 sidecar 模式,慢日志 stdout 直接打到宿主机,如何避免 Docker json-file driver 造成 inode 耗尽?
答:使用 local 日志驱动 + max-size=50m,max-file=5,并挂载 hostPath 到独立 SSD 盘,sidecar 里用 Vector 实时吐到 Kafka,不落盘。 - 当慢日志里出现“password=***”字段,如何证明已做脱敏?
答:在等保测评时提供 rsyslog 的 mmexternal 调用脚本、SM4 加密密钥托管在 KMS 的审计截图、以及第三方渗透测试报告,证明无法逆向。 - 如果开启慢日志后 QPS 下跌 5%,如何定位是 IO 还是锁竞争?
答:用 perf top -ppgrep php-fpm观察 __write_nocancel 占比;同时 iostat -x 1 看 %util;若 IO 高则升高 log_slow_extra=0 减少行数;若 mutex 竞争高则调低 request_slowlog_timeout 精度,或改用异步日志(PHP 8.3 的 zend_observer 接口)。