Mysql云服务简介
目录:
- 体系架构
- InnoDB
- 索引结构
- 事务与锁
- Mysql备份恢复及安全防护
- Mysql复制及常见高可用架构
概述
Mysql发展
- 2013年 5.6版本
- 2015年 5.7版本
- 2018年 8.0版本
推荐二进制版本安装
服务启停
- 启动 systemctl(更方便)/mysqld_safe(安全停止)
- 停止 systemctl/mysqladmin … shutdown
- kill -15
- kill -9 会跳过-15的正常关闭
体系架构
- 单进程多线程结构
- 数据库实例才是真正操作数据库文件的
- 一个数据库对应操作系统是一个文件夹
数据库 vs 实例:
- 一个数据库对应一个实例 - oracle
- 一个实例对应“多个”数据库 - mysql - database和schema同义
- 一个数据库对应多个实例 - oralce rac
物理文件:
- 数据文件 包括redo等文件
- 配置文件
- pid文件 进程文件
- socket文件 套接字
配置关键参数:
- innodb_buffer_pool_size 建议内存50%-70%
- expire_logs_days 自动清理binlog 一般7天
- max_connections
- transaction_isolation 隔离级别,默认RR(repeatable read),建议初始设置为RC(read commited),避免RR下由于间隙锁导致可能的死锁 等等
常见的事务隔离级别包括:
- 读未提交(Read Uncommitted, RU): 事务可以读取其他未提交事务的更改,可能导致脏读。
- 读已提交(Read Committed, RC): 事务只能读取其他已提交事务的更改,防止脏读,但可能导致不可重复读。
- 可重复读(Repeatable Read, RR): 事务在执行期间看到的数据是一致的,即使其他事务在此期间提交了新更改,防止脏读和不可重复读,但可能导致幻读。
- 可串行化(Serializable, S): 事务之间完全隔离,保证数据的一致性,但性能最低,防止脏读、不可重复读和幻读。
为什么推荐使用 RC 而不是 RR
- 避免间隙锁导致的死锁:在
Repeatable Read (RR)隔离级别下,为了防止幻读,数据库引擎会使用间隙锁(Gap Lock),这可能导致死锁,特别是在高并发的环境中。 - 性能考虑:
Read Committed (RC)隔离级别相对于Repeatable Read (RR)更加高效,因为它不会使用间隙锁,仅防止脏读。这对于大多数应用场景来说,RC是一种性能与数据一致性之间的良好平衡。
InnoDB
特点:
- 支持事务
- 行级锁
- 故障恢复:undo+redo
- 缓存buffer
- 索引组织表:按主键顺序排序
主要线程:
- master thread 主线程,负责调度,作用将缓冲池中数据异步刷新到磁盘
- purge thread 回收undo页
表空间:
- 系统表空间 所有innodb数据
- 独立表空间 每个表都有 页是管理的基本单位
redo log 专属于innodb 环状结构(write_position, check_point) 相关参数:innodb_flush_log_at_trx_commit 推荐设置为1
binlog 记录方式:
- sql语句,更高效
- 记录行的前后变化
- 混合模式,一般生产不会用
binlog的刷新:
- binlog_cache
- binlog_file
- disk
两阶段提交
- 先写redolog - prepare
- 再写binlog
- redolog commit
- fsync
多版本并发控制 MVCC
- 只有写写会相互阻塞了
- 快照(readview)
索引结构
- 行记录 - 单向链表
- 页目录
- 数据页 - 双向链表
- B+树(聚集索引、二级索引)
事务与锁
事务 transaction
特性:
- 原子性 commit rollback redo undo
- 一致性 双写
- 隔离性 锁机制
- 持久性 innodb_flush_log_at_trx_commit, sync_binlog
提交方式:
- 自动提交 一般是
- 手动提交
- 隐式提交 如ddl,修改数据库架构, 管理类语句
并发执行带来的问题 ⬇️ 事务隔离级别
查看加锁情况
|
|
数据备份和安全
工具、方式、窗口等
冷备、热备 物理、逻辑
逻辑备份-mysqldump 物理备份-xtrabackup/innobackupex
安全连接插件 connection_control
加密存储 - 一般不用
推荐定期清理mysql_history,否则可能有安全风险
复制、高可用
看binlog工具:mysqlbinlog
mysql主从复制 异步复制、半同步复制(其中一个从库确认后主库才commit)、全同步复制(所有从库确认后)
半同步状态查看:
show status like '%semi%';
查看复制状态
show slave status\G
slave_sql_running: yes - 开启复制状态
参数要了解下
Mysql云平台服务介绍-略
Mysql体系架构及存储引擎解析
目录
- 体系架构、Innodb索引结构
- Online ddl
- mysql开发规范
体系架构
连接器 长连接(应用连接池)、短连接(自己命令行查数据) 长连接:可能会内存不够->重连
查询缓存 query_cache 会先看是否缓存里有(key-value),有直接返回 不建议使用,因为可能不实时 mysql8.0 直接删掉了查询缓存的功能
分析器(解析器)
- 词法分析 识别关键字
- 语法分析 判断sql语法
优化器 生成执行计划
- 多个索引,决定用哪个索引
- 多表join,决定连接顺序(哪张是驱动表)
执行器 通过存储引擎提供的接口执行语句
慢日志里: 可以关注 rows_examined 扫描的行数(比较准确的) 执行计划里的rows 是估计值
写日志顺序:两阶段提交
- 更新到内存
- 写入redo log 处于prepare阶段 - innodb
- 写binlog - 执行器
- commit - innodb
物理存储结构 mysql是单进程,多线程
innodb内存结构
- 缓冲池 innodb_buffer_pool
- 数据页
- 索引页
- 插入缓存
- 锁信息
- 数据字典
- 哈希索引
- 重做日志缓存 redo log_buffer
表空间 ibd文件
MVCC 以前只有读读才能并发 版本链 - 回滚指针
B+树 上面的节点是索引页,叶子节点存数据的页位置
- 页结构
- 页有多行
- 双向链表 范围查询友好
- 行结构
- 页目录
online ddl
在已有表加字段、加索引
- 5.5 copy
- 5.6/5.7 inplace rebuild/metadata
- 8.0 instant 某些操作支持
怎么确定我的修改是以上哪种方式,可以在测试环境先试下,看下输出 query ok, n rows affected. 如果n是0的话,一般是后2种,比较快,在线
题外话:备份时 要保证所有表没有锁 没有要commit的 不然会阻塞。备份最好没有批处理的时间做
mysql开发规范
- 避免隐式转换:索引问题、长的话还会有精度失效的问题
- join优化:给驱动表的连接字段(on的字段)加索引
- 大批量操作:分批操作,如1w行为单位来操作
- 子查询改为join效率更高
- 排序:先看执行计划,如果是using filesort就会很慢。索引一般可以where+orderby的字段作为复合索引。但是索引里有用到范围查找的字段(如
where xxx > 10),则xxx字段无法利用索引。 - limit分页查询:limit m,n mysql不是直接从第m行开始取,而是取m+n行然后放弃前m行。因为为保证不要取很多内容,考虑用join来优化。比如:
- 反例:
select * from table limit 10000,20; - 正例:
select * from table a where join (select id from table limit 10000,20) b on a.id=b.id
- 反例:
推荐使用自增id或其他递增字段作为主键
主要原因:优化 B+ 树结构
InnoDB 存储引擎使用 B+ 树来组织主键索引(也称为聚簇索引)。B+ 树是一种平衡树结构,能够高效地进行数据查找、插入和删除操作。
- 自增 ID(或递增字段)有助于保持 B+ 树的平衡:当使用递增字段作为主键时,新的数据总是插入到 B+ 树的末端。由于每次插入的记录都比前一条记录大,InnoDB 不需要在树的内部进行频繁的节点分裂或调整树的结构,这使得 B+ 树的维护成本较低,插入操作也更加高效。
- 避免随机插入:如果主键是随机的(如 UUID),每次插入记录时,B+ 树可能需要在不同的节点之间插入新数据,这会导致更多的页分裂和树的重新平衡,进而影响插入性能,并增加存储的碎片化。
DDL规范:
- alter变更时,不要有大的查询或更新,即不要有慢sql,否则可能阻塞alter,进而崩溃
- alter变更时,不允许有未提交的锁
select * from information_schema.innodb_trx\G看下哪些事务未提交 - 对大表(>1GB)alter时,需在业务低峰期执行
- ddl禁止加sql_log_bin=0,因为这样不写binlog,主从复制就会失效