MySQL 高并发场景下的性能优化

MySQL 高并发场景下的性能优化 MySQL 的性能优化并不是简单地给表增加几个索引。 在真实的高并发系统中,数据库性能通常受到多个因素共同影响: 应用请求 ↓ 数据库连接 ↓ SQL 执行 ↓ 索引 ↓ Buffer Pool ↓ 锁 / 事务 ↓ 磁盘 I/O 当并发量继续增加以后,还会遇到: 连接数过高 SQL 执行时间增加 锁竞争 事务堆积 Buffer Pool 压力 磁盘 I/O CPU 使用率 Redo Log 压力 因此,高并发 MySQL 优化应该从整个访问链路出发,而不是只盯着 SQL。 1. 高并发下 MySQL 为什么容易成为瓶颈 假设一个系统每秒有: 5000 QPS 其中: 80% 查询 20% 写入 那么数据库每秒需要处理: 4000 次查询 1000 次写入 如果单条 SQL 平均执行: 10 ms 看起来并不算慢。 但当大量请求同时进入数据库后,数据库真正面对的是: 大量连接 ↓ 大量 SQL ↓ 大量索引访问 ↓ 大量数据页 ↓ 大量事务 ↓ 锁竞争 ↓ 磁盘 / CPU / 内存压力 因此:...

2024年07月19日 · 4 min · Leanku

MySQL Redo Log、Undo Log 与 Binlog

MySQL Redo Log、Undo Log 与 Binlog 在学习 MySQL InnoDB 时,经常会遇到三个日志: Redo Log Undo Log Binlog 它们名字相似,但解决的问题完全不同。 简单来说: Redo Log → 数据库崩溃后,恢复已经发生的修改 Undo Log → 事务回滚、MVCC Binlog → 记录数据库逻辑变更,用于复制、恢复等 其中最容易混淆的是: 为什么 InnoDB 已经有 Redo Log 了,MySQL 还需要 Binlog? 原因在于 Redo Log 和 Binlog 所处的层次、记录内容和设计目标并不相同。 理解三者的关系,也是理解 MySQL 事务提交和主从复制的基础。 1. 为什么数据库需要日志 假设执行: UPDATE users SET balance = balance - 100 WHERE id = 1; 最简单的想法是: 修改内存 ↓ 直接把数据写入磁盘 ↓ 完成 但真实数据库不能简单这样做。 原因是磁盘 I/O 成本较高,而且一次事务可能修改很多数据页。...

2024年06月23日 · 4 min · Leanku

MySQL InnoDB 存储引擎详解

MySQL InnoDB 存储引擎详解 InnoDB 是 MySQL 8 默认的存储引擎,也是绝大多数业务系统使用的核心存储引擎。 前面介绍索引、事务、锁和死锁时,很多机制实际上都建立在 InnoDB 的内部结构之上。 例如: 为什么 InnoDB 的索引查询通常很快? 为什么主键设计会影响二级索引大小? 为什么更新数据不一定立即写入磁盘? Buffer Pool 到底有什么作用? Redo Log 为什么能够提高写入性能? InnoDB 为什么能够支持事务和崩溃恢复? 要理解这些问题,需要从 InnoDB 的存储结构开始。 1. InnoDB 是什么 MySQL 本身并不负责所有数据存储工作。 可以简单理解为: MySQL Server ↓ SQL 解析 / 优化 / 执行 ↓ Storage Engine ↓ InnoDB ↓ 数据文件 / 日志文件 存储引擎负责真正的数据存储和访问。 早期 MySQL 中存在多种存储引擎,例如: InnoDB MyISAM Memory Archive 现代 OLTP 系统中,InnoDB 是最重要的选择。 InnoDB 提供了关系型业务系统通常需要的核心能力: 事务 行级锁 MVCC 崩溃恢复...

2024年06月21日 · 5 min · Leanku

MySQL 死锁:产生原因、分析与解决

MySQL 死锁:产生原因、分析与解决 在高并发系统中,数据库死锁是比较常见的问题。 很多开发者第一次遇到死锁时,会认为: 数据库是不是出问题了? 实际上,死锁本身并不意味着 MySQL 出现了故障。对于 InnoDB 来说,死锁是并发事务之间形成循环等待后,由存储引擎主动检测并处理的一种正常机制。 真正需要解决的问题不是简单地“关闭死锁”,而是: 为什么会产生死锁? 哪些 SQL 导致了循环等待? 为什么某个事务被回滚? 如何从根本上减少死锁? 应用程序收到死锁异常后应该怎么处理? 理解这些问题,才能正确处理生产环境中的死锁。 1. 什么是死锁 死锁(Deadlock)是指两个或多个事务互相持有对方需要的锁,同时等待对方释放锁,最终形成循环等待。 例如有两个账户: 账户 1 账户 2 事务 A: 锁住账户 1 ↓ 等待账户 2 事务 B: 锁住账户 2 ↓ 等待账户 1 最终形成: 事务 A → 等待事务 B 持有的锁 事务 B → 等待事务 A 持有的锁 这就是典型的死锁。 需要注意,死锁和锁等待不是一回事。 普通锁等待可能是: 事务 A 持有锁 ↓ 事务 B 等待事务 A 只要事务 A 最终提交或回滚,事务 B 就可以继续执行。...

2023年11月13日 · 5 min · Leanku

MySQL InnoDB 锁机制详解

MySQL InnoDB 锁机制详解 在并发业务中,多个事务可能同时修改或者读取相同的数据。如果没有并发控制,就可能出现脏写、数据覆盖、幻读等问题。 InnoDB 通过锁机制和 MVCC 等机制共同实现事务的并发控制。 例如两个事务同时修改同一条订单: UPDATE orders SET status = 2 WHERE id = 100; 如果事务 A 尚未提交,事务 B 同时执行相同的 UPDATE,那么事务 B 通常不能立即完成,而是需要等待事务 A 释放相关锁。 因此,理解 InnoDB 锁机制,对于分析以下问题非常重要: 为什么 UPDATE 会等待? 为什么 SELECT 有时候也会加锁? 为什么一个 UPDATE 影响了一行,却可能产生多个锁? 为什么会出现 Gap Lock? 为什么会发生死锁? 1. InnoDB 为什么需要锁 假设账户余额为: balance = 1000 事务 A: UPDATE accounts SET balance = balance - 100 WHERE id = 1; 同时事务 B: UPDATE accounts SET balance = balance - 200 WHERE id = 1; 如果两个事务完全不进行并发控制,就可能发生:...

2023年07月21日 · 4 min · Leanku