一、MySQL 日志系统(Log System)

(一)错误日志(Error Log)

1. 定义

错误日志是 MySQL 的核心诊断日志,记录数据库运行过程中的关键事件,如 启动、关闭、崩溃、权限异常、表损坏、主从复制错误等。遇到任何 MySQL 服务不可用的情况,第一步永远是看 Error Log。

默认存储位置

/var/log/mysqld.log

或在某些系统中:

/var/log/mysql/error.log

日志路径可能被自定义,因此建议使用 系统变量检查实际位置:

SHOW VARIABLES LIKE '%log_error%';


2.  错误日志中常见内容与定位作用

日志内容类型场景说明能定位的问题
启动/关闭信息启动失败、异常重启、强制 kill配置错误、端口冲突、数据文件被占用
InnoDB 运行异常表崩溃、Buffer Pool 损坏、回滚段异常数据损坏、未正常关闭
权限认证失败用户无法登录、连接失败账号密码错误、host 限制
主从复制异常Slave IO/SQL thread 报错主从断链、延迟、binlog 损坏
插件或存储引擎报错MyISAM 崩溃、插件启动失败表损坏、存储引擎不兼容

3. 经典错误示例与分析

[ERROR] InnoDB: Unable to lock ./ibdata1
可能原因处理建议
系统中已有 MySQL 实例运行检查 `ps -ef
MySQL 上次异常退出,文件锁未释放执行 service mysqld stop 后手动清理 lock
数据目录权限不足chown -R mysql:mysql /var/lib/mysql

该报错属于 启动失败常见类型,通常伴随 mysqld 无法启动。


MySQL 无法启动排查指南

排查顺序

① 查看 Error Log → 判断是否是配置/权限/端口问题  
② 检查 3306 是否被占用  
③ 检查目录权限、磁盘空间  
④ 检查 ib_logfile / ibdata 损坏  


排查示例步骤

排查动作命令示例目的
查看错误日志(必做)tail -100f /var/log/mysqld.log找到第一现场报错信息
检查端口占用lsof -i:3306 / `netstat -anpgrep 3306`
检查 mysqld 进程`ps -efgrep mysql`
检查目录权限ls -l /var/lib/mysql错误常见于迁移或手动拷贝数据目录
修复表损坏mysqlcheck --repair --all-databasesMyISAM 表损坏恢复第一手段

如日志出现 InnoDB: corruption detected,需考虑 ibdata 损坏,可能需要内存恢复 / 数据迁移 / binlog 回放等方式救援。


MySQL 崩溃后你如何排查?

先查看 error log 定位启动失败原因  
→ 再排查端口占用 / 权限问题 / 数据损坏  
→ 如果是 InnoDB 表损坏,可先备份再修复  
→ 必要时借助 binlog 做数据恢复


(二)二进制日志(BINLOG)

1. 定义与作用

Binlog 是 MySQL 最重要的日志之一,用于记录所有会对数据产生修改的操作(INSERT / UPDATE / DELETE / DDL),但 不包含只读 SQL(SELECT、SHOW)。

只要会改动数据,就一定进 binlog

其核心价值包含 三大用途:

作用说明
数据恢复可通过 binlog 进行 point-in-time recovery(PITR)
主从复制依赖Slave IO 线程拉取 binlog 写入 relay log 从而同步
审计回放可还原谁在什么时候改了什么数据

查询 Binlog 是否启用:

SHOW VARIABLES LIKE '%log_bin%';

正式环境必须开启,否则 无法做主从、无法增量恢复,风险极高


(1)Binlog 三种记录格式
格式记录内容优点适用场景缺点/陷阱
STATEMENT原始 SQL体积最小、性能最高历史系统、低写入量业务NOW()、UUID、LIMIT 等非确定性语句可能导致主从数据不一致
ROW(默认)每行变更前后镜像 row event最可靠、可完全恢复金融、支付、电商核心库日志量巨大、大事务可能撑爆磁盘
MIXEDS + ROW 动态切换兼顾体积&安全中大型业务通用较难排查某条用的是哪种

查看当前格式:

SHOW VARIABLES LIKE '%binlog_format%';

为什么行格式安全?

因为它记录的是“变更后的真实数据”,而不是 SQL 描述,不受函数、随机数影响,因此主从永不产生逻辑偏差。


(2)Binlog 查看 / 分析 / 恢复

二进制不可直接读 → 使用 mysqlbinlog 工具解析:

mysqlbinlog -vv binlog.000123 > log.txt

常用参数:

参数含义
-vv输出更详细注释,包含 row-based 修改前后值
-d dbname仅解析某个库的操作
--start-datetime / --stop-datetime精确恢复某时间区间
--start-position / --stop-position适用于恢复某事务范围

误删数据如何救?

假设执行了:

DROP DATABASE prod;

恢复流程:

1) 确保有 recent binlog(未过期)
2) 将 Drop 之前的 binlog 解出
3) 回放除 DROP 外所有 SQL


示例命令:

mysqlbinlog --start-datetime="2025-01-01 10:00:00" \
            --stop-datetime="2025-01-01 12:00:00" \
            binlog.000125 | mysql -uroot -p

专业场景通常还会配合全量备份 + 增量 binlog 做 PITR 精准恢复到秒级


(3)Binlog 清理与 MySQL 8.0 优化机制

因为 Binlog 可能非常大(Row 格式下尤甚),必须设置自动清理,否则产生磁盘爆满 → MySQL 直接挂掉!

手动清理:

PURGE BINARY LOGS TO 'binlog.000200';
PURGE BINARY LOGS BEFORE '2025-02-01';

但更推荐 MySQL 8.0+

SHOW VARIABLES LIKE '%binlog_expire_logs_seconds%';
SET GLOBAL binlog_expire_logs_seconds = 604800; -- 7天

经验建议:主库保留 7-30 天,备库可更长
有归档需求可 scp 拉取冷存


(三)查询日志(General Log)

1. 定义

General Log 记录所有客户端发送给 MySQL 的 SQL,包括查询、连接请求、管理命令。

它是最完整、最暴力的 SQL 审计方式,但 性能开销巨大,因此 默认关闭。

查看配置:

SHOW VARIABLES LIKE '%general%';

启用方式:

general_log=1
general_log_file=/var/log/mysql/general.log

一旦开启,每条 SQL 都会写磁盘 → TPS 直接下降
只建议排查问题时短暂使用


使用场景:

使用场景价值
某接口执行了什么 SQL?用于排查 ORM 框架生成 SQL
判断是否有扫描、慢语句来源结合 slow log 定位性能热点
安全审计/违规操作分析找出误删数据的操作者、语句来源

若需长期 SQL 审计,更推荐替代方案:ProxySQL、Audit Plugin、Binlog 解析流式存储


(四)慢查询日志(Slow Log)

1. 定义

慢日志用于记录执行时间超出阈值(long_query_time 默认 10s)的 SQL,是性能优化必须开启的日志。

slow_query_log=1
long_query_time=1             -- 建议生产 ≤1s
log_queries_not_using_indexes=1
log_slow_admin_statements=1

日志位置:

SHOW VARIABLES LIKE '%slow_query_log_file%';

如何分析慢日志?

推荐工具:Percona pt-query-digest

pt-query-digest /var/log/mysql/slow.log > report.txt

可输出:

项目说明
最耗时语句优先优化 Top N!
执行次数最多的语句高频低效 → 必须建索引或优化 SQL
平均耗时/锁等待时间判断是否是索引失效 or 竞争阻塞

生产场景优化思路

慢日志定位后需分析:

是否缺索引?
是否走全表扫描?
是否存在回表与排序成本?
是否具有不必要的运算(函数、计算列)?
是否大事务或批量写入导致锁等待?


优化手段:

问题处理方式
没索引 / 索引未使用建索引 + 避免对索引列做计算
回表严重改覆盖索引(SELECT t.col1,t.col2),避免 SELECT *
排序/分组慢加合适索引 / 使用分页优化方案
大事务拆分 batch / 控制单次提交量

二、主从复制(Replication)

(一) 主从复制核心目的

主从复制不仅是数据同步手段,更是企业级 MySQL 架构优化和高可用的核心组件。

价值说明 & 企业意义
读写分离,提高并发性能主库负责写,从库分担读压力(电商类场景显著)
容灾容错,提高可用性主库宕机,从库快速接管,减少停服时间
备份不影响业务在从库执行备份任务,不干扰线上请求
数据审计、安全追踪Binlog 作为业务操作的不可抵赖数据来源

注意:复制本身 不是备份,仅提供数据冗余和同步机制,仍需定期做全量 + 增量备份。


(二) 主从复制底层原理(核心三阶段 + Thread 机制)

主从复制流程:

Client → Master → Binlog → Slave IO Thread → Relay Log → SQL Thread → Apply
阶段执行位置核心操作关键点底层原理
① 主库提交事务写入 BinlogMaster所有变更记录 event仅提交成功才写入,保证一致性事务成功提交后写 binlog(同步到磁盘/缓冲区),保证 ACID
② 从库 IO Thread 拉取 BinlogSlave传输并落盘为 Relay Log默认异步,不阻塞主库TCP 异步复制,网络 + 磁盘 flush
③ SQL Thread 回放 Relay LogSlave将 event 转换为真实 SQL 执行单线程回放 → 延迟瓶颈来源row/statement 格式 event 回放,事务大时耗时显著

1. 为什么必须先提交成功才写入 Binlog?

事务若失败,不应被复制到从库,否则会导致数据冲突。这体现了 ACID 的一致性原则。


2. 为什么主从复制会延迟?

延迟表现:主库写入成功 → 从库可见延迟 1s、10s,甚至分钟级。

根因:

A. SQL Thread 单线程回放成为瓶颈(核心本质)

        主库可能多个并发事务写入 binlog

        从库 SQL Thread 却只能串行执行 → 堵塞累积

示例:

Master: T1、T2、T3 并行提交
Slave: T1 未完成 → T2 阻塞 → T3 堵塞

B. 大事务/批量写入放大积压

        1条超过10万行 UPDATE 就能让从库落后数分钟

优化建议:

现象解决方案
大批量写入导致延迟分批小事务提交;使用 LIMIT 分片更新
大表 DDL(ALTER)阻塞回放使用 pt-online-schema-change 或 gh-ost 避免长锁

C. IO、CPU、磁盘性能不足

Relay Log 写入慢 → 延迟

SQL 回放慢 → 表缺索引、CPU 瓶颈

优化:SSD + RAID10、增加从库实例、SQL 优化


3.  解决主从延迟的工程级方案

方案原理适用场景
多线程复制(MySQL 5.7+)按库或事务并行回放多 schema、事务独立性高
MTS-Enhanced 并行事务执行(MySQL 8.0)基于事务提交顺序并发执行单库事务多、并发提升明显
强制 binlog group commit批量提交提高写入吞吐写入压力大、电商高峰期
提升硬件/多从库分担SSD + RAID10 + xtrabackup备份高负载场景必配

延迟不是偶发现象,而是架构本质,需要通过 并发复制 + 多从库 对抗。


(三)MySQL 8.0 GTID复制

GTID 是什么?

        GTID(Global Transaction ID) = 事务级唯一编号

格式示例:

UUID:transaction_id
3E11FA47-71CA-11E1-9E33-C80AA9429562:23

相比传统基于 binlog_file + pos 的复制方式:

传统复制GTID复制
需要指定文件 + 位置只需执行到下一个事务 GTID
主故障切换需要手工调整同步位点从库自动寻找位置并追上主库
切主复杂,一旦错位难恢复GTID 极大降低故障切换成本

优点

        无需关心 binlog 位置
        宕机后从库可自动补偿缺失事务
        做主从切换、故障恢复极其方便

启用配置(生产推荐 MySQL8.0):

gtid_mode=ON
enforce_gtid_consistency=ON

(四)复制模式比较

复制模式特点评价
异步复制(默认)主不等待从库,最快高性能 ,但可能丢数据
半同步复制主至少等待 1个从确认强一致性更高但延迟上升
MGR(Group Replication)多主协议,自动选主分布式一致性最高但配置复杂

企业级推荐:

        读多写少 → 异步 + 多从库
        写敏感强一致性 → 半同步 or MGR


(五)主从切换/故障迁移

手动切换示例:

STOP REPLICA;
RESET SLAVE ALL;
CHANGE MASTER TO ...
START REPLICA;

企业生产通常使用自动 HA 工具:

工具作用
MHA (Master High Availability)自动切主,恢复binlog位置
OrchestratorGitHub开源,可视化拓扑 & 智能切换
MGR自带共识算法,不依赖第三方

生产最佳实践:

     一主多从 + MHA/Orchestrator + GTID
→ 最佳平衡方案


(六)主从复制配置示例(MySQL8.0)

主库 my.cnf:

server-id=1
binlog-do-db=db01

从库 my.cnf

server-id=2
read-only=1

从库建立复制连接:

CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='xx.xx',
  SOURCE_USER='itcast',
  SOURCE_PASSWORD='123',
  SOURCE_LOG_FILE='binlog.000001',
  SOURCE_LOG_POS=120;

启动复制:

START REPLICA;  # MySQL8.0+

查看状态:

SHOW REPLICA STATUS\G

关注:

参数是否正常含义
Replica_IO_RunningYES从库成功获取主库 binlog
Replica_SQL_RunningYES从库 relay log 回放成功

主从复制:MySQL 复制通过 IO Thread 拉取 Binlog 写入 Relay Log,再由 SQL Thread 回放并执行。延迟本质来自从库回放单线程瓶颈,MySQL 8.0 支持基于提交顺序的并行复制,配合 GTID 可实现自动定位事务,故障切换无需关心 Position,大幅简化运维复杂度。生产建议开启 ROW 格式 + 多线程复制 + binlog 清理策略,必要时接入 Orchestrator/MHA 做高可用。


三、分库分表

(一)背景问题

在高并发、大数据量的应用场景下,单库单表很容易出现性能瓶颈,主要表现为:

性能瓶颈说明底层原理
IO 不足热点数据频繁访问,磁盘频繁读写磁盘寻址速度有限,随机访问多时 I/O 队列成为瓶颈
CPU 顶满大量复杂查询(JOIN、聚合)查询解析、优化器生成执行计划以及执行引擎计算消耗 CPU
单表数据过大索引膨胀,查询退化为全表扫描B+Tree 索引页数膨胀,随机访问增加,缓存命中率下降,导致回表成本上升

示例:

假设 order 表存储了 5 年的订单数据,单表有 10 亿行。使用 SELECT * FROM order WHERE user_id = 123 查询时,如果没有合适的分库分表,数据库需要扫描整个索引,导致查询延迟数秒甚至十秒以上。

“当系统单表数据量过大或热点数据集中时,单机数据库无法承受高并发访问,容易出现 I/O 和 CPU 瓶颈,同时索引效率下降,查询退化为全表扫描,这是分库分表的主要驱动力。”


(二)分库分表方案对比

分库分表主要分为垂直拆分和水平拆分两种方式:

拆分方式特点适用场景底层原理示例
垂直分库按业务模块拆分订单库、用户库、商品库独立每个库独立运行,IO/CPU 隔离DB_user、DB_order、DB_product
垂直分表按字段拆分表宽表拆分成基本信息表和扩展信息表减少单表列数,降低回表成本user_base + user_profile
水平分库数据按某字段拆入不同库高并发、数据量大通过中间件或应用路由请求到对应库DB_user_0、DB_user_1
水平分表数据按某字段拆入同库多表核心高并发场景减少单表数据量,保持索引效率user_00、user_01、user_02 分片字段:user_id % 4

示例:

假设有 1000 万用户,要查询用户信息:

水平分表方案:user_id % 4 → user_0、user_1、user_2、user_3 四张表,每张表约 250 万行,单表查询更快。

垂直分库方案:订单数据放在 DB_order,用户信息放在 DB_user,写入/查询操作互不干扰。

“垂直拆分主要解决不同业务模块之间的隔离问题,水平拆分主要解决单表数据量过大导致的性能问题。常用水平分片字段为用户 ID 或订单 ID,通过取模或哈希将请求路由到对应表/库。”


(三)技术选型

常用中间件:

中间件优点缺点底层原理
ShardingJDBC性能高,可灵活定制需改代码,侵入性强基于 JDBC 层拦截 SQL,解析逻辑表 → 路由到物理表/库,支持读写分离、分片
MyCat可直接当 MySQL 使用性能逊色于 JDBC,配置复杂作为数据库代理,接收 SQL 并路由到不同库表,内部维护分片规则和连接池

MyCat 核心配置文件理解

文件内容
 schema.xml定义逻辑库、逻辑表及节点分布
rule.xml定义分片算法、路由策略
server.xml配置用户权限、端口、线程池等

示例配置:
逻辑表 user,4 个分表:

<table name="user">
    <rule>user_rule</rule>
</table>

<rule name="user_rule" class="hash">
    <columns>user_id</columns>
    <shards>DB_user_0.user_0,DB_user_1.user_1,DB_user_2.user_2,DB_user_3.user_3</shards>
</rule>

当应用执行 SELECT * FROM user WHERE user_id=123,中间件会根据 user_id % 4 将请求路由到 DB_user_3.user_3。

“分库分表可通过中间件实现透明路由。ShardingJDBC 基于 JDBC 层拦截 SQL,MyCat 作为数据库代理实现分片。核心是根据分片键计算路由,并将逻辑表映射到物理表,保证应用无感知地访问分表。”

更多推荐