资讯详情

资讯详情

MySQL日志查询全攻略:从错误日志、binlog到慢查询优化实战

1. 日志体系全景MySQL到底在记录些什么接手MySQL运维的第一天老师傅多半会丢给你一句话“先把日志看明白再谈优化和排障。”这句话我当年没当回事直到线上一个慢查询把业务拖垮我却连错误日志在哪都翻不明白才老老实实回头补课。MySQL的日志不是“一个文件”那么简单而是一整套分层记录体系。按用途可以粗暴分成三类一是给人和排障看的错误日志、慢查询日志、通用查询日志二是给数据恢复和主从复制用的binlog重做日志、redo log、undo log三是给审计和安全用的审计日志、连接日志。很多人一上来就盯着binlog翻结果连接异常、事务回滚、权限被拒这类问题其实都写在错误日志里方向完全跑偏。我自己习惯先看一张总表把日志的“身份信息”理清楚再谈怎么查。这张表建议每个DBA都存一份日志类型默认文件名核心作用是否可关闭对应参数错误日志hostname.err记录启动、运行、崩溃时的错误信息不建议关log_error通用查询日志hostname.log记录所有客户端连接和SQL语句可关默认关general_log慢查询日志hostname-slow.log记录超过long_query_time的SQL按需开启slow_query_log二进制日志binlog.000001记录所有数据变更操作用于复制和恢复按需开启log_binredo logib_logfile0崩溃恢复时保证数据不丢必须开启innodb_redo_log_capacityundo logundo_001事务回滚和MVCC读视图必须开启innodb_undo_log_truncate这张表想表达的核心观点是日志记录的内容不同查询方式也不同。错误日志是“纯文本编辑器直接翻”binlog 是“二进制必须用工具解析”慢查询日志可以“直接tail但最好结合mysqldumpslow聚合”通用查询日志则是“全量记录别长时间开着”。把日志类型和查看方式对应上后面所有操作都不会乱。另外提一句MySQL 8.0 之后 redo log 的文件管理方式和5.7差别很大不再是一对固定的 ib_logfile 文件而是改用 innodb_redo_log_capacity 参数控制容量文件还会自动清理。很多老教程还在讲“删除ib_logfile重启”这套做法在8.0下已经过时千万别照着试。2. 从命令行到客户端查看日志的四种姿势2.1 直接翻文件最朴素也最有效查看MySQL日志最直观的方式就是用 Linux 的文本查看命令直接读文件。前提是你知道日志文件的路径。路径怎么确认两种办法第一种登录MySQL执行SHOW VARIABLES LIKE log_error; SHOW VARIABLES LIKE slow_query_log_file; SHOW VARIABLES LIKE general_log_file;第二种直接在Linux命令行里查mysql -uroot -p -e SHOW VARIABLES LIKE log_error;拿到路径后用tail、less、grep组合着看。这里我强烈建议优先用less而不是cat原因很现实日志文件动辄几百MB甚至几GBcat会把整个文件灌进终端轻则卡死编辑器重则直接撑爆SSH会话。less是分页加载打开大文件毫无压力还支持/关键词向下搜索、?关键词向上搜索排障效率高出一个量级。# 实时跟踪最新日志输出排障时首选 tail -f /var/log/mysql/error.log # 搜索关键词并显示上下文行号 grep -n ERROR /var/log/mysql/error.log | tail -50 # 用less打开支持上下翻页和搜索 less /var/log/mysql/slow-query.log有人会问日志里出现Warning算不算问题我的判断标准是看具体内容。比如Using a password on the command line interface can be insecure这种Warning是客户端提示不影响数据安全但如果是InnoDB: Assertion failure或者Table doesnt exist那就是实打实的故障必须处理。别看到Warning就恐慌也别无视所有Warning养成看上下文的习惯。2.2 SHOW命令查状态适合快速定位参数是否生效很多时候我们不是要看日志内容而是要先确认“日志到底开没开、文件写在哪、阈值设了多少”。这时候用SQL查参数最直接。常用组合如下-- 查看错误日志路径 SHOW VARIABLES LIKE log_error; -- 查看慢查询是否开启、阈值、文件路径 SHOW VARIABLES LIKE slow_query_log%; SHOW VARIABLES LIKE long_query_time; -- 查看binlog是否开启、文件前缀、格式 SHOW VARIABLES LIKE log_bin%; SHOW VARIABLES LIKE binlog_format; -- 查看通用查询日志状态 SHOW VARIABLES LIKE general_log%;注意一个坑long_query_time在MySQL 5.7以上默认单位是秒且支持小数比如设置为2.5表示2.5秒。但很多人改了参数发现不生效原因往往是没加GLOBAL关键字或者只改了会话级别。正确姿势SET GLOBAL long_query_time 2;然后重新连接会话再查或者执行SHOW GLOBAL VARIABLES LIKE long_query_time;确认。这里还有一个很多老手都会踩的细节long_query_time的生效是“语句执行完成后判断”如果一条SQL执行了1.9秒阈值正好是2秒它不会被记录。另外慢查询日志里默认不记录管理语句如ALTER TABLE需要把log_slow_admin_statements打开才会记录这个参数排查DDL性能问题时非常有用。2.3 系统表与performance_schema数据化分析更高效MySQL 5.7开始慢查询日志和通用查询日志的信息可以写入系统表而不是文件这就为后续的SQL统计、分析、报表提供了方便。核心配置如下SET GLOBAL log_output TABLE; SET GLOBAL slow_query_log ON;设置完成后慢查询记录会写入mysql.slow_log表通用查询记录会写入mysql.general_log表。查询方式SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 20;把日志存表的好处是可以用SQL聚合分析比如统计哪类SQL最慢、哪个用户慢查询最多。但坏处也明显表数据量大了之后查询本身也会慢而且清理还需要专门的TRUNCATE操作。我的建议是线上环境日常用文件方式记录做复盘分析时临时切换到表模式分析完再切回文件。再说说performance_schema。它不直接存日志但提供了大量与日志相关的等待事件、语句统计信息。比如想查某条SQL在哪个阶段耗时最长可以用SELECT * FROM performance_schema.events_statements_summary_by_digest ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;这个查询能按SQL模板聚合出累计执行时间配合慢查询日志的原始记录基本可以定位90%的性能瓶颈。performance_schema的查询开销很低但也不是零成本默认开启即可没必要专门去调它。2.4 可视化工具DataGrip、DBeaver、Navicat的日志面板很多图形化客户端自带日志查看面板比如 DataGrip 的控制台会展示MySQL返回的警告和错误Navicat 也有日志浏览功能。这类工具适合“日常开发顺手瞄一眼”但我不建议把它作为生产环境排障的主手段。原因有三第一工具显示日志时通常会做截断或格式化丢失了原始时间戳和线程ID等关键上下文第二生产环境的日志文件可能分散在多台机器图形工具只能连其中一台看不到全貌第三有些工具查看大日志文件时直接卡死还不如命令行tail来得利索。可视化工具的正确使用场景是本地开发环境联调时快速看SQL执行报错、看事务冲突、看连接被拒原因。真要排查线上故障老老实实SSH到服务器上用命令行查这才是专业姿态。3. binlog详解看完它你就看懂了MySQL的底层逻辑binlog 是MySQL所有日志里最特殊的一个。它不是给人“读”的而是给数据库“用”的——主从复制靠它、时间点恢复靠它、数据闪回也靠它。很多人学了多年MySQL一说binlog就只知道“记录变更”但具体怎么查、怎么看、怎么解析从来没系统研究过遇到问题只能干瞪眼。3.1 为什么binlog不能用cat直接看binlog是二进制格式不是纯文本。如果你直接用cat binlog.000008会看到一堆乱码夹杂着可读字符完全没法分析。这是因为binlog为了节约空间、提高写入效率对事件做了编码压缩必须通过MySQL自带的mysqlbinlog工具解析成可读的SQL语句。mysqlbinlog是MySQL安装包自带的命令行工具无需额外安装。基本用法# 查看binlog文件内容解析后的可读文本 mysqlbinlog /var/lib/mysql/binlog.000008 # 指定时间范围 mysqlbinlog --start-datetime2024-12-01 00:00:00 --stop-datetime2024-12-01 12:00:00 /var/lib/mysql/binlog.000008 # 指定位置范围位置数字在日志里可以看到 mysqlbinlog --start-position157 --stop-position450 /var/lib/mysql/binlog.000008 # 解析结果输出到文件方便后续分析 mysqlbinlog /var/lib/mysql/binlog.000008 /tmp/binlog_analysis.sql必须先确认binlog开启了没有。MySQL 5.7默认是不开binlog的8.0默认开启。检查命令SHOW VARIABLES LIKE log_bin;如果返回OFF说明当前实例没开binlog那主从复制和时间点恢复都无从谈起。开启方式是在my.cnf配置文件加[mysqld] log_bin /var/lib/mysql/binlog server_id 1 binlog_format ROW expire_logs_days 15expire_logs_days在8.0里已经废弃改用binlog_expire_logs_seconds比如设置保留15天就是1296000秒。这个参数决定了binlog文件自动清理的周期设置太短影响备份恢复太长会撑爆磁盘需要根据备份策略合理设定。3.2 确认当前binlog文件和位置日志分析时经常要“从上一个备份节点恢复”这就需要明确当前写到哪个binlog文件、位置是多少。执行SHOW MASTER STATUS;返回结果里会有File和Position两列分别代表当前正在写入的binlog文件名和偏移量。还有一条命令用于查看所有binlog文件列表SHOW BINARY LOGS;这两个命令在配置主从复制时几乎是必用的。拿到主库的binlog文件名和位置后从库的CHANGE MASTER TO才能精确指定起点。实际工作中我见过不少新手把SHOW MASTER STATUS和SHOW BINLOG EVENTS混为一谈其实前者看的是全局位置后者看的是某文件内的事件明细。3.3 分析binlog事件用SHOW BINLOG EVENTS如果你不想把binlog导出成文件再翻也可以直接在SQL层面对binlog做事件查询SHOW BINLOG EVENTS IN binlog.000008 FROM 157 LIMIT 10;这条命令会按顺序列出binlog里的事件类型、表名、SQL语句如果是ROW格式则显示伪SQL、事务ID等。用处在于快速定位某个binlog文件里有没有某张表的更新操作但注意它不会显示ROW格式下每行的具体值变化要想看细节还是得用mysqlbinlog -v或-vv输出带行数据的伪SQL。ROW格式的binlog用mysqlbinlog -v查看时会呈现类似下面的结构### UPDATE test.user ### WHERE ### 11 ### 2zhangsan ### SET ### 2lisi1、2分别代表第1列、第2列的原值和目标值。这个信息在数据恢复和误操作分析时是“黄金证据”能精确告诉你哪一行、哪些列被改成了什么值。binlog_format 有三种选择STATEMENT记录SQL语句、ROW记录行变化、MIXED自动切换。8.0默认是ROW虽然日志体积更大但安全性和可恢复性远胜STATEMENT不要轻易改成STATEMENT。3.4 binlog可以删吗怎么安全清理binlog日志可以删除吗是热搜词也是群里高频提问。答案可以删但要讲方式。直接用rm -rf binlog.000008是绝对不能做的因为binlog文件之间有相互关联硬删可能导致主从复制断裂或备份链条中断。正确的删除姿势有三种第一种手动指定删除到哪个文件之前PURGE BINARY LOGS TO binlog.000010;这个命令会删除所有比binlog.000010序号小的文件保留到当前这个文件为止。第二种指定删除某个时间之前的日志PURGE BINARY LOGS BEFORE 2024-12-10 00:00:00;第三种设置自动过期时间让MySQL自己清理SET GLOBAL binlog_expire_logs_seconds 1296000;注意上面这个GLOBAL设置重启后可能失效要持久化得写进配置文件。还有个大坑——从库还在读取的binlog不能删。如果你有从库的IO线程正在消费某个binlog文件强行PURGE会导致主从报错。删除之前建议先执行SHOW SLAVE STATUS看看从库已经读取到哪个文件。我的习惯做法是binlog保留周期和全备周期对齐。比如每天凌晨做全量备份那么binlog至少保留两天这样即使备份失败也能从前一天的binlog做增量恢复。少于这个保留周期等于把自己的退路切断了。4. 慢查询日志从“看”到“诊断”这才是优化的开始慢查询日志是MySQL优化路上绕不开的必修课。很多教程只会教“开启慢查询日志”但开启之后呢怎么从一堆慢SQL里找到真正需要优化的怎么分析重复出现的SQL模式这些都很少有人系统地讲。今天我把全流程走一遍。4.1 开启慢查询的完整配置先看当前状态SHOW VARIABLES LIKE slow_query_log%; SHOW VARIABLES LIKE long_query_time;如果显示slow_query_log OFF需要开启。临时开启当前实例生效重启失效SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 2;要永久生效编辑 my.cnf[mysqld] slow_query_log 1 slow_query_log_file /var/log/mysql/slow-query.log long_query_time 2 log_queries_not_using_indexes 1 log_slow_admin_statements 1log_queries_not_using_indexes这个参数很多人不知道它会把“没有走索引”的查询也记进慢日志哪怕这条查询实际执行时间很短。在开发环境开启非常有用能提前发现索引缺失问题。但线上要慎开因为有些本该全表扫描的小表查询会被大量记录日志会膨胀得很快。log_slow_admin_statements则把ALTER TABLE、OPTIMIZE TABLE这类DDL操作也纳入慢日志对于排查DDL锁表问题特别关键。默认它是关闭的5.7和8.0都是建议改表结构频繁的业务一定打开。4.2 手工分析慢日志mysqldumpslow实战慢查询日志是纯文本可以直接tail但日志一多靠肉眼是看不过来的。MySQL自带了一个聚合分析工具mysqldumpslow用法如下# 按执行次数排序显示前10条 mysqldumpslow -s c -t 10 /var/log/mysql/slow-query.log # 按总耗时排序 mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log # 按平均耗时排序并显示完整SQL语句 mysqldumpslow -s at -t 10 -g SELECT /var/log/mysql/slow-query.logmysqldumpslow会把相似的SQL语句做归一化处理比如WHERE id 1和WHERE id 2会被归并为WHERE id N然后汇总出执行次数、平均耗时、最大耗时等指标。这样看慢日志就不再是“一条条翻”而是“一眼看到底哪些SQL模板最该优化”。还有一个小技巧如果系统里没有mysqldumpslow比如用源码编译安装时没加工具链可以直接用pt-query-digest。这是Percona Toolkit里的工具功能比自带的更强大支持按时间窗口分析、生成HTML报告、精确到每一行的执行耗时统计。安装方式# Ubuntu/Debian apt install percona-toolkit # CentOS/RHEL yum install percona-toolkit日常分析我用pt-query-digest更多输出可读性远超自带的工具。但要注意pt-query-digest需要Perl环境和相关依赖装的时候注意版本兼容老版本在MySQL 8.0上解析binlog时会报格式错误。4.3 分析慢SQL之后我做了什么拿到慢SQL别急着EXPLAIN先看几件事第一看是不是“一条SQL吃遍所有请求”。如果mysqldumpslow聚合结果显示某条SQL占了80%以上的执行次数那这往往是业务侧反复调用的“热SQL”优化它的收益最大。第二用EXPLAIN看执行计划EXPLAIN SELECT * FROM orders WHERE user_id 123 AND status 1;重点看type列从好到差依次是system const eq_ref ref range index ALL。如果看到ALL全表扫描或者index全索引扫描大概率需要加索引。第三看实际的扫描行数和返回行数。EXPLAIN给出的rows只是估计值不一定准但结合慢日志里的Rows_examined和Rows_sent字段就能判断是否“读多回少”。如果Rows_examined是10万Rows_sent只有10说明查询条件的选择性太差索引设计有问题。优化手段往往很朴素加合适的联合索引、改写SQL条件顺序、拆分大查询为小批量。我记得有一次线上慢查询是统计某日订单金额单条SQL跑了20秒。排查后发现是对一张800万行的表做了全表聚合而且没有走二级索引。加了(created_at, status)联合索引后同样的查询从20秒降到0.3秒这就是慢查询日志分析带来的直接收益。5. 错误日志与通用查询日志故障现场的第一手线索5.1 错误日志的核心价值启动失败和运行崩溃MySQL实例连不上、服务起不来、频繁重启第一件事不是查监控而是看错误日志。错误日志是MySQL“自述病历”启动时的参数错误、InnoDB的恢复过程、连接数超限、磁盘空间不足、主从复制异常都会记录在这里。常见错误日志位置# 默认日志目录 /var/log/mysql/error.log # 或者根据配置查询 mysql -uroot -p -e SHOW VARIABLES LIKE log_error;经典场景一启动失败提示Permission denied。这通常不是MySQL自身问题而是日志目录或数据目录的属主不对。解决办法是把目录属主改成mysql用户chown -R mysql:mysql /var/lib/mysql经典场景二磁盘满了导致写入失败。错误日志会频繁出现No space left on device。这时要先用df -h确认磁盘使用率再定位是binlog膨胀、慢查询日志膨胀还是数据文件本身增长。区分定位很关键别一上来就删数据文件。经典场景三[ERROR] InnoDB: Unable to lock ./ibdata1。这是另一个MySQL实例还在运行或者上次异常退出后残留了pid文件。解决方式不是删文件而是检查是否有残留进程ps -ef | grep mysqld确认真没有进程后再考虑删除/var/run/mysqld/mysqld.pid之类的残留文件。5.2 通用查询日志什么时候开什么时候千万别开通用查询日志general log记录所有客户端连接和所有SQL语句功能很强大但副作用也很大——日志量级是“每次查询一条”高并发下磁盘写入会爆炸性能下降肉眼可见。所以我的原则是仅在两种场景下开启用完即关。场景一排查“某个客户端到底发来了什么SQL”。比如开发反馈“我在代码里没执行这个语句但数据库里出现了”开启general log抓取几分钟就能看到完整SQL和来源IP。场景二排查连接问题。比如“为什么会有大量Sleep状态的连接”开启general log看连接的建立和断开顺序能迅速定位是连接池配置问题还是程序忘记释放连接。开启方式SET GLOBAL general_log ON; -- 做完排查后务必马上关闭 SET GLOBAL general_log OFF;排查期间建议把日志输出到表方便查询SET GLOBAL log_output TABLE; SELECT * FROM mysql.general_log WHERE command_type Query ORDER BY event_time DESC LIMIT 50;极端情况下我遇到过一次连接风暴几分钟内几万个连接涌进来直接把MySQL撑挂了。当时就是靠general log抓到来源发现是某个服务的连接池配置错误把maximum-pool-size设成了5000而且没有设置连接超时。定位后改回50系统立刻恢复正常。但也要老实说那几分钟的general log直接把磁盘写满了所以千万记住开general log必须设置超时提醒自己关闭别开着过夜。6. 多实例与容器环境Docker和Filebeat场景下的日志处理6.1 Docker容器里MySQL日志的查看方法容器化部署MySQL已经很普及但日志查看和裸机部署差异不小。先明确一个点容器里的MySQL进程是前台运行的mysqld的日志默认输出到标准输出stdout由Docker的日志驱动捕获。所以最简单的查看方式是docker logs mysql-containerdocker logs -f可以实时跟踪docker logs -f --tail200 mysql-container如果你想看MySQL内部的错误日志文件需要先进入容器docker exec -it mysql-container bash tail -f /var/log/mysql/error.log但很多官方镜像比如mysql:8.0里默认没有配置log_error指向文件日志直接走stdout。这时进容器是看不到error.log的只能靠docker logs。这就带来一个问题容器重启后docker logs历史日志会被清掉不利于排障。解决方式是把容器的日志持久化到宿主机文件docker run -d \ --name mysql8 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -v /data/mysql/log:/var/log/mysql \ -p 3306:3306 \ mysql:8.0然后在容器配置里加[mysqld] log_error /var/log/mysql/error.log这样容器日志落盘到宿主机/data/mysql/log目录配合logrotate做轮转日志管理就和裸机一样顺手了。还有一个容器场景下特别容易踩的坑docker run时如果只映射了数据目录没映射日志目录容器跑着跑着突然报了“磁盘空间不足”进容器一看/var/lib/mysql没满但/var/log/mysql所在的分区满了。因为日志文件也写容器内层容器默认的存储驱动如果配置不当日志会把可写层撑爆。规避方案就是上面那种“显式挂载日志卷”一条命令解决。6.2 Filebeat采集MySQL日志从分散到集中热搜词里出现了filebeat日志采集说明越来越多团队在做日志集中化。Filebeat是Elastic官方出的轻量级采集器常用于把服务器上的文本日志转发到Elasticsearch、Logstash或Kafka。在MySQL场景下我主要用它采集三类日志错误日志、慢查询日志、审计日志。先安装Filebeat或者直接用压缩包# 下载并解压filebeat wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.12.0-linux-x86_64.tar.gz tar -zxvf filebeat-8.12.0-linux-x86_64.tar.gz cd filebeat-8.12.0-linux-x86_64配置filebeat.yml核心逻辑是“哪个文件、什么类型、发到哪”。一个基础配置filebeat.inputs: - type: log enabled: true paths: - /var/log/mysql/error.log fields: log_type: mysql_error fields_under_root: true - type: log enabled: true paths: - /var/log/mysql/slow-query.log fields: log_type: mysql_slow fields_under_root: true output.elasticsearch: hosts: [http://192.168.1.100:9200] index: mysql-logs-%{yyyy.MM.dd}启动./filebeat -e -c filebeat.yml这里要提醒一个细节MySQL慢查询日志的每一条记录是多行的包含时间、用户、耗时、SQL语句Filebeat默认按单行读取会拆散记录。需要在input里配置多行匹配- type: log enabled: true paths: - /var/log/mysql/slow-query.log multiline: pattern: ^# Time: negate: true match: after这个配置的含义是以# Time:开头的行作为新日志的开始其他行都归并到前一条日志中。不配置这项你在Kibana里看到的慢日志就是碎成一片一片的毫无分析价值。Filebeat采集之后配合ELK的Dashboard可以把慢查询日志做成可视化报表按时间趋势、SQL类型、执行次数排序效果比命令行高不少。但要注意Filebeat本身不带过滤功能日志里敏感信息比如SQL中带手机号会原样写进ES生产环境记得在Ingest Pipeline里做脱敏。6.3 一台机器多个MySQL实例的日志区分有些服务器上会部署多个MySQL实例多端口、多数据目录比如3306供业务、3307供报表分析。此时日志文件不能写同一个路径否则互相覆盖、完全分不清。正确做法是在配置里用不同的日志文件名[mysqld1] port 3306 log_error /data/mysql3306/log/error.log slow_query_log_file /data/mysql3306/log/slow.log log_bin /data/mysql3306/log/mysql-bin [mysqld2] port 3307 log_error /data/mysql3307/log/error.log slow_query_log_file /data/mysql3307/log/slow.log log_bin /data/mysql3307/log/mysql-bin多实例环境下用tail -f同时跟踪两个日志建议用tail -f配合文件名前缀或者用multitail这类工具分屏监控不然日志一多两个实例的输出混在一起人眼很容易看错。我自己的习惯是每个实例的日志目录标准化命名日志文件按日期切分再用rsyslog的模板标签区别来源后续交给Filebeat采集时直接按目录区分即可。7. 日志轮转与清理不设防的日志会撑爆磁盘日志如果不做轮转迟早把磁盘塞满。MySQL的错误日志、慢查询日志、binlog都是“只增不减”的选手。常见故障里“磁盘满导致数据库只读”的案例有一大半是日志没管好。7.1 利用logrotate管理MySQL日志Linux自带的logrotate是处理日志轮转的标准方案。以CentOS/RHEL为例在/etc/logrotate.d/下新建一个mysql文件/var/log/mysql/*.log { daily rotate 7 missingok notifempty compress delaycompress sharedscripts postrotate /etc/init.d/mysql rotate /dev/null 21 || true endscript }说明一下几个关键项daily每天轮转一次也可以按大小size 500M。rotate 7保留7个轮转文件更久的自动删除。compress轮转后的旧日志压缩成 .gz 文件节省磁盘。delaycompress推迟一天再压缩配合MySQL写入方式更安全。postrotate轮转后执行命令告诉MySQL“日志文件被换掉啦请重新打开”。这个动作非常重要不然MySQL还在往已经被rotate的旧文件里写磁盘释放不出来。对MySQL而言更优雅的通知方式是mysqladmin flush-logsmysqladmin -uroot -p flush-logs它会令MySQL重新打开日志文件并生成新的binlog文件。这个操作应该加在postrotate脚本里。7.2 binlog的自动清理配置binlog清理有几个层面。第一层前面说过的binlog_expire_logs_seconds控制自动过期时间。第二层备份完成后主动清理比如在crontab里跑备份脚本时加一句mysql -uroot -p -e PURGE BINARY LOGS BEFORE NOW() - INTERVAL 2 DAY;第三层如果binlog已经无用了比如改成只做逻辑备份直接关闭binlog也是一种选择但主从复制场景下绝对不能关。判断binlog能不能清理的底线是所有从库都已经消费完对应文件以及全量备份时间点早于需要恢复的最小时间点。7.3 清理慢日志文件的操作顺序慢查询日志清理顺序有讲究如果直接rm /var/log/mysql/slow-query.logMySQL进程还持有这个文件的句柄磁盘空间不会释放日志也会继续写进“已经被删除”的文件里而且你再也看不到内容。正确的清空方式是# 方式一清空文件内容保留文件句柄 truncate -s 0 /var/log/mysql/slow-query.log # 方式二重命名旧日志然后刷新日志MySQL会新建文件 mv /var/log/mysql/slow-query.log /var/log/mysql/slow-query.log.$(date %Y%m%d) mysqladmin -uroot -p flush-logs这个细节在排障时特别容易翻车。我见过同事直接rm了慢日志文件结果磁盘空间一点没降他还纳闷好久最后发现MySQL还在占用被删除文件的inode。记住了MySQL运行中日志文件只能用truncate清空或者flush-logs重建不能直接删。8. 实用速查表常见问题排查一句话指南最后送上一份我自己整理的速查表。排查MySQL日志相关问题时先按这个列表过一遍大部分场景都能快速定位方向。现象优先查看的日志常见原因一句排查命令MySQL无法启动错误日志配置错误、数据目录权限、端口冲突tail -50 /var/log/mysql/error.log连接数超限报错错误日志max_connections过小、连接未释放grep Too many connections /var/log/mysql/error.log一条SQL执行特别慢慢查询日志缺索引、数据量过大、锁等待mysqldumpslow -s t -t 5 /var/log/mysql/slow-query.log主从同步中断错误日志 / 从库statusbinlog位置错乱、网络问题、SQL错误SHOW SLAVE STATUS\G误操作删了数据binlog需要从binlog恢复mysqlbinlog --start-datetime... binlog.000008磁盘空间突降binlog 慢日志binlog未自动清理、慢日志无限膨胀SHOW BINARY LOGS;du -sh /var/log/mysql/*客户端报错但未见异常通用查询日志日志级别过滤、客户端连接异常SET GLOBAL general_logON;后重放操作容器环境日志丢失docker logs容器重启、日志未挂载卷docker logs --tail100 mysql-container最后分享一个个人习惯我会在每台MySQL服务器上写一个get_mysql_logs.sh脚本一键打包导出今天的错误日志、慢查询日志、binlog列表和参数状态排障时直接执行并输出到一个统一目录。这省去了每次敲一堆命令的时间而且不容易遗漏关键信息。脚本内容很简单核心就是把日志路径的变量统一提取后续用rsync或Filebeat把打包结果同步到日志中心。这个习惯在排查“半夜偶发故障”时特别有用——早上到公司先看昨晚的打包日志基本能定位问题不用再手忙脚乱翻服务器。日志这个东西平时没人注意出故障时才知道值钱。MySQL的日志体系并不复杂但需要你提前把“看日志的路径和方法”摸熟而不是等故障来了再临时学。拿到一台新服务器我建议你先花5分钟执行一遍上面提到的SHOW VARIABLES系列命令确认日志开关和路径然后写进自己的运维笔记里。真到了凌晨两点被报警叫醒的时候你会感谢那个提前做了准备的自己。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →