
事务的四大特性ACID
原子性Atomicity:
一个事务必须被事务不可分割的最小工作单元,整个操作要么全部成功,要么全部失败,一般就是通过commit和rollback来控制
一致性Consistency:
数据库总能从一个一致性的状态转换到另一个一致性的状态,比如小滴课堂下单支付成功后,开通视频播放权限,只要有任何一方发生异常就不会成功提交事务
隔离性Isolation:
一个事务相对于另一个事务是隔离的,一个事务所做的修改是在最终提交以前,对其他事务是不可见的
持久性Durability:
一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失脏读 读到其他事物未提交的数据 比如a事物查看把工资5000修改8000但为提交 b事物读的是8000 然后a事物回滚到5000 出现脏读
不可重复读 事物访问同一数据的结果不一致 比如a事物修改工资5000 到8000 b事物在a事物修改前后都查看了下工资 两次结果不一样 就是不可重复读
幻读 事物查看数据的时候出现新的记录 a事物查询员工m不存在 插入5000工资数据 但是b事物提前插入这条数据 并提交事物 a事物插入的时候失败了 这就是幻读
不可重复读 侧重修改数据 幻读侧重插入新数据未提交读 提交读 可重复读 可串行化
read uncommited read commit repeatable read serializable
默认是可重复读 有幻读问题
幻读问题 :mysql的innoDB引擎通过mvcc解决 即多版本并发控制常见的有多类,InnoDB、MyISAM、MEMORY、MERGE、ARCHIVE、CSV等
一般比较常用的有InnoDB、MyISAM
MySQL 5.5以上的版本默认是InnoDB,5.5之前默认存储引擎是MyISAMinnodb支持事物 myisam不支持
innodb适合读写均衡 写多读少场景 需要事物 myisam写少读多 不需要事物
innodb 行锁 锁粒度小 适合高并发 myisam表锁
innodb支持外键 myisam不支持
innodb不支持全文索引 可以通过插件实现 比如(5.6以后支持全文索引)ElasticSearch myisam支持全文索引 记录表的长度
mysql 5.5以后默认是innodb普通索引 create index index_name on table_name(filed_name)
唯一索引 create unique index index_name on table_name(filed_name)
主键索引 alter table table_name add primary key(field_name)
组合索引 create index index_name on table_name(filed_name1,filed_name2)
覆盖索引
全文索引 alter table table_name add fulltext(filed_name) 仅用于myisam引擎 更多使用ElasticSearch搜索
中型公司或者业务发展好的公司,一天新增几百万数据量
业务核心数据存储在Mysql里面,针对业务创建合适的索引
打点数据、日志等存储在ElasticSearch或者MongoDB里面考虑点:结合实际的业务场景,在哪些字段上创建索引,创建什么类型的索引
索引好处:
快速定位到表的位置,减少服务器扫描的数据
有些索引存储了实际的值,特定情况下只要使用索引就能完成查询
索引缺点:
索引会浪费磁盘空间,不要创建非必要的索引
插入、更新、删除需要维护索引,带来额外的开销
索引过多,修改表的时候重构索引性能差
索引优化实践
前缀索引,特别是TEXT和BLOG类型的字段,只检索前面几个字符,提高检索速度
尽量使用数据量少的索引,索引值过长查询速度会受到影响
选择合适的索引列顺序
内容变动少,且查询频繁,可以建立多几个索引
内容变动频繁,谨慎创建索引
根据业务创建适合的索引类型,比如某个字段常用来做查询条件,则为这个字段建立索引提高查询速度
组合索引选择业务查询最相关的字段
from 从哪个表查询
where 初步过滤条件
group by 过滤后进行分组[重点]
having 对分组后的数据进行二次过滤[重点]
select 查看哪些结果字段
order by 按照怎样的顺序进行排序返回[重点]
select video_id,count(id) num from chapter group by video_id having num >10
order by video_id descchar 长度不可变 varchar长度可变
char存储的长度小于定义长度的话 用空格代替 varchar可随插入的数据而变化
char适合存储长度不变化的如手机号 varchar适合存储变化的 如收货地址
char的存取速率更快 datetime 8个字节 timestamp 4个字节
datetime时间是1000年到9999年 和时区无关
timestamp时间是1970年到2038年 与时区有关mysql的timestamp类型是4个字节 最大值是2的31次方减1
转换成北京时间就是2038年现象:千万级别数据很正常,比如数据流水、日志记录等,数据库正常的深度分页会很慢
慢的原因:select * from product limit N,M
MySQL执行此类SQL时需要先扫描到N行,然后再去取M行,N越大,MySQL扫描的记录数越多,SQL的性能就会越差
1、后端、前端缓存
2、使用ElasticSearch分页搜索
3、合理使用 mysql 查询缓存,覆盖索引进行查询分页
select title,cateory from product limit 1000000,100
4、如果id是自增且不存在中间删除数据,使用子查询优化,定位偏移位置的 id
select * from oper_log where type='BUY' limit 1000000,100; //5.秒
select id from oper_log where type='BUY' limit 1000000,1; // 0.4秒
select * from oper_log where type='BUY' and id>=(select id from oper_log where type='BUY' limit 1000000,1) limit 100; //0.8秒 分多个环境最终上线
有开发环境 测试环境 预发布环境 生产环境
开发人员更新程序和数据库到测试环境 测试人员通过
开发人员部署到预发布环境 测试和产品人员进行内部验收
然后开发人员提供脚本给DBA 开发人员和DBA分析后准许上线 DBA(数据库运维人员)
一般在夜间上线 先上线数据库 再上线程序

大厂一般都有数据库监控后台,里面指标很多,但是开发人员也必须知道
业务性能
1、应用上线前会审查业务新增的sql,和分析sql执行计划
比如是否存在 select * ,索引建立是否合理
2、开启慢查询日志,定期分析慢查询日志
3、监控CPU/内存利用率,读写、网关IO、流量带宽 随着时间的变化统计图
4、吞吐量QPS/TPS,一天内读写随着时间的变化统计图
数据安全
1、短期增量备份,比如一周一次。 定期全量备份,比如一月一次
2、检查是否有非授权用户,是否存在弱口令,网络防火墙检查
3、导出数据是否进行脱敏,防止数据泄露或者黑产利用
4、数据库 全量操作日志审计,防止数据泄露
5、数据库账号密码 业务独立,权限独立控制,防止多库共用同个账号密码
6、高可用 主从架构,多机房部署redo log重做日志
undo log 回滚日志 (innodb中的read commit 和repeatable read通过mvcc+undo log实现) mvcc(多版本并发控制)
slow query log 慢查询日志(记录执行时间长的sql)
binlog 二进制日志(用于主从复制 实现主从同步)
relay log 中继日志
error log 错误日志
general log 普通日志
=================================================================================
redo 重做日志
作用:确保事务的持久性,防止在发生故障,脏页未写入磁盘。重启数据库会进行redo log执行重做,到达事务一致性
undo 回滚日志
作用:保证数据的原子性,记录事务发生之前的数据的一个版本,用于回滚。
innodb事务的可重复读和读取已提交 隔离级别就是通过mvcc+undo实现
errorlog 错误日志
作用:Mysql本身启动、停止、运行期间发生的错误信息
slow query log 慢查询日志
作用:记录执行时间过长的sql,时间阈值可以配置,只记录执行成功
binlog 二进制日志
作用:用于主从复制,实现主从同步
relay log 中继日志
作用:用于数据库主从同步,将主库发送来的binlog先保存在本地,然后从库进行回放
general log 普通日志
作用:记录数据库操作明细,默认关闭,开启会降低数据库性能我们公司数据库不是单节点,是多节点的,有做主从复制三个主要线程 主库一个log dump线程 从库io线程和sql线程
数据写入后 记录变更到binlog
主库的log dump线程和从库io线程交互 将binlog读取并写入到从库的 relay log中
再由sql线程读取日志 写到从库
1容灾使用,用于故障切换
2业务需要,进行读写分离减少主库压力原因有:
1 主从复制是单线程操作 主库tps过高时 从库sql线程会有延迟
2 从库执行了大的sql操作 造成堵塞
3 硬件问题 cpu 磁盘 网络延迟
解决方法:
1 业务需求有容忍度的情况下 可以读的时候加一层缓存 降低读的压力 先命中缓存 再考虑数据库
2 提升硬件设施 cpu 磁盘 网络延迟
3 读写分离 一主多从 分散压力
4 分库分表 降低单机压力
=========================================
保证性能第一情况下,不能百分百解决主从同步延迟问题,只能增加缓解措施。
现象:主从同步,大数据量场景下,会发现写入主库的数据,在从库没找到。
原因:
1、主从复制是单线程操作,当主库TPS高,产生的超过从库sql线程执行能力
2、从库执行了大的sql操作,阻塞等待
3、服务器硬件问题,如磁盘,CPU,还有网络延迟等
解决办法:
1、业务需要有一定的容忍度,程序和数据库直接增加缓存,降低读压力
2、业务适合的话,写入主库后,再写缓存,读的时候可以读缓存,没命中再读从库
3、读写分离,一主多从,分散主库和从库压力
4、提高硬件配置,比如使用SSD固态硬盘、更好的CPU和网络
5、进行分库分表,减少单机压力
1、本身复制延迟导致
2、主库宕机或者从库宕机都会导致复制中断
3、把一个从库提升为主库,可能导致从库和主库的数据不一致性Mysql主从复制是基于binlog复制,难免出现复制数据不一致的风险,引起用户数据访问前后不一致的风险
所以要定期开展主从复制数据一致性的校验并修复,避免这些问题
解决方案之一,使用Percona公司下的工具
pt-table-checksum工具进行一致性校验
原理:
主库利用表中的索引,将表的数据切割成一个个chunk(块),然后进行计算得到checksum值。
从库也执相应的操作,并在从库上计算相同数据块的checksum,然后对比主从中各个表的checksum是否一致并存储到数据库,最后通过存储校验结果的表就可以判断出哪些表的数据不一致
pt-table-sync(在从库执行)工具进行修复不一致数据,可以修复主从结构数据的不一致,也可以修复非主从结构数据表的数据不一致
原理:在主库上执行数据的更改,再同步到从库上,不会直接更改成从的数据。在主库上执行更改是基于主库现在的数据,也不会更改主库上的数据,可以同步某些表或整个库的数据,但它不同步表结构、索引,只同步不一致的数据
注意:
默认主库要检查的表在从库都存在,并且同主库表有相同的表结构
如果表中没有索引,pt-table-checksum将没法处理,一般要求最基本都要有主键索引
pt-table-sync工具会修改数据,使用前最好备份下数据,防止误操作当pt工具在计算主库上某chunk的checksum时,主库可能在更新且从库可能复制延迟,那该怎么保证主库与从库计算的是”同一份”数据,答案把要checksum的行加上for update锁并计算,这保证了主库的某个chunk内部数据的一致性D M Q C (大码裤衩) D define man query control
DDL 数据定义语言 :建库 建表
DML 数据操控语言 :对表中的数据增删改操作
DQL 数据查询语言 : 对数据查询
DCL 数据控制语言 : 对用户的权限进行设置不使用preparedStatement的时候 比如密码 输入 or1=1 拼装sql 进行攻击浮点型有float单精度 double双精度
还有DECIMAL定点型
float和double会四舍五入 所以电商系统 等会使用DECIMALchar长度不可变 varchar可变
char速度快 但浪费空间
varchar适合存储可变的数据 char适合存储定长的数据如手机号
========================
char 长度不可变 varchar长度可变
char存储的长度小于定义长度的话 用空格代替 varchar可随插入的数据而变化
char适合存储长度不变化的如手机号 varchar适合存储变化的 如收货地址
char的存取速率更快 delete是删除数据 记录删除操作 方便回滚 不释放空间 不会删除定义
truncate不会记录删除操作 释放空间 不会删除定义
drop 是删除整张表 where - group by - having - order by表经量避免使用select * 尽量精确到结果
避免使用or
记得加上limit
用模糊查询时,%放在前面是会使索引失效
要小心条件字段类型的转换重复数据较多的列 比如性别
存储null的字段 因为排序机制or
联合索引 不使用第一个
类型强转
hash索引
like 以%开头分为两部分 一个是设计优化 一个是查询优化
设计优化
使用适当的字段类型和大小 比如性别01 使用tinyint
经量单表解决业务问题
适当字段添加索引 最好主键索引
普通索引和唯一索引这里 考虑changeBuffer的使用 非必要用普通索引 主键索引大于普通索引大于唯一索引
查询优化
避免使用select * 这样无法使用索引 而且增加io和cpu消耗
慎用join联表查询
慎用子查询和临时表
经量不使用limit 部分场景使用bewteen and
===========================================
SQL优化可分为两个部分,一个是设计阶段,另一个是查询阶段
设计阶段运用到的优化
使用适当的数据库列类型和大小
尽量从设计上采用单表查询解决业务问题
在适当字段加入索引,能用唯一索引用唯一索引
查询阶段涉及的优化
尽可能不用select *:让优化器无法完成索引覆盖扫描这类优化,而且还会增加额外的I/O、内存和CPU的消耗
慎用join操作:单张表查询可以减少锁的竞争,更容易应对业务的发展,方便对数据库进行拆分
慎用子查询和临时表:未带索引的字段上的group by操作,UNION查询,部分order by操作,例如distinct函数和order by一起使用且distinct和order by同一个字段
尽量不适用limit,部分场景可改用bewteen and
分页一般是未了防止一次加载太多数据导致内存 磁盘io开销过大
用limit关键字
数量很大时 深度分页性能的原因
比如where 条件 limit 语句 mysql是先把符合条件的语句放到buffer中排序 再分页 所以当数据量很大时 会耗费很多时间
解决方式
通过主键索引优化
比如自增id 可以把上一页最大的id 加入查询条件 and id>id值 让id之后的数据放入buffer中
还有就是通过Elastic Search搜索引擎
=====================================================
通过explain分析深度分页查询问题 explain select * from user where age>10 and age<90000000 order by age desc limit 8000000,10000;
执行计划Extra列可能出现的值及含义:
Using where:表示优化器需要通过索引回表查询数据。
Using index:即覆盖索引,表示直接访问索引就足够获取到所需要的数据,不需要通过索引回表,通常是通过将待查询字段建立联合索引实现。
Using index condition:在5.6版本后加入的新特性,即大名鼎鼎的索引下推,是MySQL关于减少回表次数的重大优化。
Using filesort:文件排序,这个一般在ORDER BY时候,数据量过大,MySQL会将所有数据召回内存中排序,比较消耗资源。
解决方案
通过主键索引优化
在查询条件中带上主键索引 explain select * from user where id>{maxId} age>10 and age<90000000 order by age desc limit 8000000,10000;
Elastic Search搜索引擎优化(倒排索引)
实际上类似于淘宝这样的电商基本上都是把所有商品放进ES搜索引擎里的(那么海量的数据,放进MySQL是不可能的,放进Redis也不现实)。但即使用了ES搜索引擎,也还是有可能发生深度分页的问题的,这时怎么办呢?答案是通过游标scrollB+树
B+树是 三层 可以存储上百万数据
只在叶子结点存储数据 每个叶子结点包含一个链指针 非叶子结点只存储索引数据 适合mysql这种关系型数据库二叉树
因为每个结点只能有两个子节点 所以他单层能够存储的数据很少 需要遍历多层才能定位到数据
hash索引
适合等值检索 hash值对应一个物理地址,等值检索很快 但是范围检索就不行了,因为hash是不连续的
B树
相比二叉树 效率更高 相比hash适合范围索引 (非关系数据库 存储key-value适合B树)
一个问题是每个结点既要检索数据又要存储数据 范围查找需要返回上层结点重复遍历 io操作繁琐
还有就是修改数据时候会对树进行分裂 合并 转移等操作来维持B树的性质 造成io频繁
B+tree就是对B树的缺点的改进
查找数据所在位置通过非叶子结点索引key 数据data只存在叶子结点 遍历范围时利用链指针找其他叶子来避免B树返回上层重复遍历的缺点MongDB每一个表空间TableSpace下有多个分段segment 每个分段下有多个Extent 1M大小 Extent下有64page
一个B+Tree结点分配一个page一个page里有多行记录 page 16kbmyisam中 使用B+Tree作为索引结构 叶子结点data存放的地址 主索引和辅助索引没任何区别 只是主索引是唯一的
再innoDB中 主键索引是聚簇索引 data存放完整的数据 辅助索引data存储的是主键的值,再根据主键索引找数据 这也是为什么用主键索引效率高的原因高可用容灾方面
容灾这里innoDB数据恢复方便 快速恢复 myisam困难
高可用但是总体差距不大 都可以通过搭建主从 多结点 多机房 容错
一致性方面
innoDB支持事物
高性能方面
由于innoDB主键是聚簇索引 它的主键性能更高
innoDB是行锁 myisam是表锁 innoDB更适合高并发场景
innoDb不支持行数 count()*需要遍历全表
使用考虑
innoDB支持外键 myisam不支持
innoDB不支持全文索引 可以用Elastic Search解决 多个索引情况下 优化器 会通过比较扫描行数 是否需要临时表 是否需要排序来判断使用哪个
一种情况是使用了 临时表或者order by排序 mysql临时表效率很低 一般不用 order by这种我们可以通过force index 来解决
还有一种情况就是删除更新操作导致数据空洞 explain分析的行数和实际的rows差距较大
这种解决方式是通过analyze table 重新统计索引信息唯一索引和普通索引在查询性能上没差别 注意考虑更新的性能
更新条件下 唯一索引需要先判断这个值在数据库是否存在 不能使用change Buffer机制 因此从性能考虑 尽可能使用普通索引 在一些必要的情况 比如手机号 用唯一索引第一个是缓存 后面是语法解析器 最后找到执行计划 再执行引擎 再从存储引擎检索数据
引擎是硬盘与缓存交互的那一步ACID
原子性 Atomicity 关注是操作是否全部成功或者失败 指事物不可再分割 要么同时成功 要么同时失败
一致性 consistency 关注的是数据库完整性是否得到维护 强调是从一个一致状态到另一个一致性状态 比如购买商品 支付 下单 有一个发生异常就不会commit事物
隔离性 isolation 事物之间不影响
持久性 durability 指的是提交之后永久存到磁盘 不会消失 事物隔离级别有
读未提交
读已提交
可重复读
串行化
脏读:就是读到了其他事物为提交的数据 比如名字改为anna 然后rollback 你读到了 就是脏读
不可重复读 :指的是事物读数据的时候 别的事物提交 导致当前事物读同一值不相同
幻读:mysql的innoDB引擎通过mvcc解决 这个是update层面的 比如插入数据a 当前事物查询的时候并不存在 但是插入的时候插入失败
因为mvcc解决幻读机制是读取采用快照读 插入是真实的数据 其他事物已经插入了 这就出现 查询不存在 但是插入失败 这就是幻读
补充幻读
我想通过解决幻读的机制来解释什么是幻读
幻读的原因是RR隔离级别下 mvcc快照读产生的问题 快照读仅仅解决了不可重复读
需要加上间隙锁来保证不出现幻读
比如a字段 前提是a不是唯一索引
a有10 到 15 范围
插入 12 会对对12前后左开又闭进行间隙锁 使12不会在当前事物下被update inset操作影响导致重复 重复的情况下 就是幻读
mysql中
读未提交会出现脏读
读已提交 解决脏读 但有不可重复读的问题
可重复读 再解决不可重复读的问题 但是部分幻读未解决 (读已解决(mvcc机制中 可以理解成快照形式保证可重复读) 但是update未解决 因为update修改的是真实的数据)
串行化 可解决幻读 但是效率很低 基本不使用
可重复读是用的最多的 其update幻读问题可以通过加锁实现
(select lock in share mode; select ...for update)是基于缓存实现高性能 undolog redolog mvcc机制保证事物
核心的是undo log redo log (undo log redo log保证了事物的一致性 原子性 持久性 (隔离性是mvcc))
undo log 是记录事物变更前的状态 用于快照恢复 出现错误 或者执行rollback 从undolog日志中恢复(—不涉及物理磁盘—)
redo log 是记录变更后的状态 这个是要写到物理文件redo log file里
redo log 同步机制
三种 master thread 1s刷新一次 将重做日志缓存刷新到redo log(指的是dataBuffer层)
commit refresh 事物提交时 将重做日志缓存刷新到redo log(值得是dataBuffer层)
size trigger 当缓存空间小于一半时 重做日志缓存被刷新到redo log(指的是dataBuffer层)
其中有checkpoing 防止redo log 过大 定期将databuffer的内容刷到磁盘datafile中 然后清楚checkpoint之前的redo log
恢复:InnoDB通过加载最新快照,然后重做checkpoint之后所有事务(包括未提交和回滚了的),再通过undo log回滚那些未提交的 事务,来完成数据恢复
还有一个重要的是缓冲池Buffer pool
Buffer pool是 数据库的一个组件 缓存磁盘上的真实内容 目的是加快读取数据的速度 默认是128g以page页为单位(table space segment extent page (16kb) 一行行数据) 其中采用LRU缓存淘汰策略
多版本并发控制
如何实现:
innoDB在每一行数据中添加了两个字段 data_transation_id data_rollback_ptr
transation_id 每次处理一个书屋 加一
roobackPTR指向undolog链表
作用:
每行数据都存在版本 用于事物处理
readview视图
三个字段 最大事物id 最小事物id id集合
读已提交是在每次读取前都生成一个readview
可重复读仅仅在第一次读取数据的时创建readview视图首先 了解mvcc只在读已提交和可重复读发挥作用
分为快照读和当前读
snapshot current
简单的select操作时快照读 快照读记录的是读时候的版本 不用加锁
简单select
当前读 需要加锁保证其他事物进行修改
select ...where ? lock in share mode
select ...where ? for update 就是select加S锁或者X锁的时候
insert delete update
注意 第一条是读锁 其他三个都是互斥锁 (写锁)解决了部分写失败
问题背景
写页数据到磁盘 一页是16k分4次写 如果写了两次突然中断 就用到了doublewrite机制
innoDB在讲页写入磁盘之前 首先写入doublewritebuffer缓冲区的存储区域
再顺序写到磁盘文件的doulewirte区域 因为知识顺序写 效率很高 牺牲这点性能保证数据页的完整性首先Read uncommited 读未提交总是读取最新的数据 不需要版本控制
read commited 用到了行锁(record锁)
RR读用mvcc和间隙锁解决不可重复读、幻读对数据操作类型来说
读锁(共享锁) 写锁(排他锁)
对数据操作粒度
表锁 行锁 页锁
并发角度
悲观锁 乐观锁
其他
间隙锁 防止幻读
意向锁 通知事物有其他事物的存在表锁 锁粒度大 性能开销小 不会出现死锁 锁冲突概率高 不适合高并发场景
行锁 锁粒度小 加锁性能慢 并发度高
只有命中索引 innoDB才使用行锁 命中不到 会使用表锁
因此要注意索引失效 比如类型强转死锁指的是资源相互竞争,相互等待
比如事物a持有这个事物 想要获取事物b的事物 事物b想要获取a 两个资源互相等待形成死锁
写锁:
select ..from update
读锁:select ..from my share mode
查看死锁日志
show egine innodb status
如何避免
操作多个表时 以相同顺序 避免形成环路
操作一个表示 以顺序进行 避免形成环路
大事物化为小事物 甚至不开启事物select for update==>insert==>update = insert into update on duplicate key
使用索引访问数据 避免where条件的操作 避免表锁
等值查询 而不是范围查询
避免在同一数据运行读写脚本间隙锁时可重复读下默认开启的 RR隔离级能保证可重复读 由于是mvcc机制保证可重复读是快照读 会出现幻读问题 于是诞生了间隙锁
间隙锁是对RR隔离级别下事物读取到的记录前后范围 加锁 左开又闭 比如10 15直接 读12 的话 加锁是在11 12 13 14 15都不可插入 解决了幻读
是这样解决幻读的
防止间隙内有新数据插入
防止已经存在的数据 更新后成为间隙内的数据
总结就是防止其他事物的插入操作,而导致的各种问题
什么情况下用间隙锁?
在RR隔离级别下 且 有通过索引查询
问题
性能消耗
死锁大表分为单表记录过大 单行记录过大 单字段过大
单表记录过大
深度分页
数据归档 时间分区 分库分表
单行记录过大
解释
与磁盘交互以page为单位 16k 如果字段太多 每次交互的就很少
策略
C端单独抽取 不用要的字段分到另一个表
单字段过大
拆分字段或者存储其他引擎单体数据库 存在很大风险 不能容灾
复制的意义
容灾 数据安全 分担主库压力 代替主库成为数据源
单点问题解决方案
主从同步mysql 主从同步是异步复制
master主库有dump线程 slave从库有io线程和sql线程
主库二进制文件binlog日志记录变更信息
dump线程主动把数据push推送到从库io线程
io线程写到中继日志relay log 这个相当于一个缓存
sql线程讲中继日志写入从库
为啥从库要用两个线程处理数据同步呢 mysql 1.1.5之后将同步复转转化成了异步复制
异步复制数据
master不需要等待slave同步完数据 而是放入relaylog 中继日志缓冲区
这样即使sql线程读取慢 也不会影响io线程读取数据
同时relay log 也写入了磁盘 一定程度保障了数据的完整性
二进制日志记录数据变更的事件
分为row复制 statement复制 mixed复制
row复制
将row变更转成二进制文件在从库中重放
statement复制
sql存入二进制日志在从库中重放
mixed复制
先基于sql复制 sql复制不准确的时候 再基于行复制row复制和statement复制对比
row是空间大 时间效率慢 安全性高
statement是 空间小 效率高 安全性低
一些DML语言无法精确不如使用不带order by 的limit语句是 结果会不一样
mixed模式是兼容上面两种模式
mysql现在默认使用row 因为内网同步宽带大
如果贷款小的话 采用mixed模式传统复制要记录复制到哪个二进制文件 和 复制到的位置
GTID就是全局事物id uuid区分事物来源哪个server + 事物id
一个id对应一个事务 代替传统复制 不需要指定二进制文件名和位置
通过GTID自动寻找对应的二进制文件记录 降低复制任务的难度
工作方式
binlog dump换成了GTID dump
mater更新数据时 生成的二进制文件会加上GTID
IO线程和之前一样 变更的binlog写入中继日志
sql线程的获取的时候先看GTID 获取过则会忽略
缺点
不支持非事物引擎
不适合+DDL语言的sql 总之就是只适合一个事物的sql这里总结来说就是安全和效率的兼容
mysql5.7之前用的传统异步复制 有数据丢失的风险
半同步复制 mysql5.7之后的插件模式
传统模式 主库execute 之后 dump 然后commit 和从库没关系
而半同步复制主库需要等待relay log阶段之后ack消息 再commit
ack未确认几秒也会commit 因为5.7之前采用的异步复制已经很成熟了