分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

MVCC&PURGE&分布式事务

发布时间:2023-09-06 01:55责任编辑:胡小海关键词:MVC

Ⅰ、MVCC介绍

举个栗子

session1:(root@localhost) [test]> select * from t;+------+| a ???|+------+| ???1 |+------+1 row in set (0.00 sec)(root@localhost) [test]> begin;Query OK, 0 rows affected (0.00 sec)(root@localhost) [test]> update t set a = a + 1 where a = 1;Query OK, 1 row affected (0.01 sec)Rows matched: 1 ?Changed: 1 ?Warnings: 0(root@localhost) [test]> select * from t;+------+| a ???|+------+| ???2 |+------+1 row in set (0.00 sec)session2:(root@localhost) [test]> begin;Query OK, 0 rows affected (0.00 sec)(root@localhost) [test]> select * from t;+------+| a ???|+------+| ???1 |+------+1 row in set (0.00 sec)

第一个会话开启事务更新记录,不提交,此时记录是被锁住的

新开一个会话去select 这条记录,并不会因为有锁而阻塞,读到的是原来的记录

这就是MVCC——多版本并发控制,实现原理就是undo,没有额外开销,读到这条记录被更新则读这条记录之前的版本

此时commit之后,之前版本的undo是不能被马上回收的,因为其他线程可能还在引用之前版本的undo,真正的回收undo是purge线程做的

Ⅱ、purge线程

2.1 purge介绍

purge的作用是删除undo,真正删除一条记录(完成update和delete)

delete from table where pk=1;在page中只是标记为删除,page上并没有真正的删除相关参数:innodb_purge_threads ???默认是1,5.7中设大一点,4或者8,都是ssd性能比较好
  • 5.5之前所有的purge操作都是master thread做的

    默认只有一个purge thread

    innodb_purge_threads={0|1}
  • 5.6

    N purge thread

    innodb_purge_threads={4}

2.2 purge具体过程

1024个槽------1024个undo回滚段,每个槽对应不同的undo日志

一旦事务提交,undo就放到hitory list中

tips:

因为记录不是有序的,所以purge操作需要大量离散读取操作

2.3 线上常见问题

undo不断增大,不能有效回收,导致系统空间不断增大,

最主要的原因有两个:

  • 索引没有添加

    检查slow log
  • 存在大事务

    拆大为小

其实就一点,一个事务执行时间很长,那对应的undo就不能回收,至少要commit完成后才能回收

另外回滚比提交慢非常多,commit很快,rollback需要的时间就是事务执行的时间,逻辑回滚

tips:

目前MySQL已经支持在线回收undo,详见阿里数据库内核月报

Ⅲ、分布式事务

之前我们谈到binlog和redo的一致性是通过一个内部的xa事务保证的,这里简单聊下外部的分布式事务

3.1 看下简单语法

(root@localhost) [test]> xa start ‘a‘; ???-- 开启一个分布式事务Query OK, 0 rows affected (0.00 sec)(root@localhost) [test]> insert into t values(2000);Query OK, 1 row affected (0.09 sec)(root@localhost) [test]> insert into t values(3000);Query OK, 1 row affected (0.00 sec)(root@localhost) [test]> xa end ‘a‘; ?-- 结束Query OK, 0 rows affected (0.00 sec)(root@localhost) [test]> xa prepare ‘a‘; ?-- 写prepareQuery OK, 0 rows affected (0.03 sec)(root@localhost) [test]> xa recover; ?-- 看一眼,有一个分布式事务+----------+--------------+--------------+------+| formatID | gtrid_length | bqual_length | data |+----------+--------------+--------------+------+| ???????1 | ???????????1 | ???????????0 | a ???|+----------+--------------+--------------+------+1 row in set (0.00 sec)(root@localhost) [test]> xa rollback ‘a‘; -- 回滚Query OK, 0 rows affected (0.01 sec)(root@localhost) [test]> xa recover; ?-- 再看下,没了Empty set (0.00 sec)

这是再单实例上模拟的,意义不大

真正应用程序中两个实例做分布式事务,需要两边的prepare都成功才能最终提交

3.2 分布式事务的不完美

  • client退出导致prepare成功事务丢失
  • MySQL Server宕机导致binlog丢失
  • 外部XA prepare成功不写日志

Ⅳ、事务编程

4.1 不好的事物习惯

  • 在循环中提交事务,(fsync次数太多)
  • 使用自动提交
  • 使用自动回滚
create procedure load1(count int unsigned)begindeclare s int unsigned default 1;declare c char(80) default repeat(‘a‘,80); ?while s <= count do ???insert into t1 select NULL,c; ???set s = s+1; ?end while;endcall load1(1000)

上面这个存储过程的调用,auto commit导致了insert会处罚一千次fsync

正确姿势:

begin;call load1(1000)commit;
  • 错误的那种如果中间失败回滚都回不了,做不到原子性
  • 将事务写到存储过程里面也不好,出错了就不好弄,不能自动回滚,所以存储过程只写逻辑,事务控制应用程序来做

4.2 大事务

事务拆大为小,原因就是binlog在搞鬼,其实不一定是大事务,大的操作都要拆吧

计算利息,拆了批量执行

update accountset account_total = account_total + (1 + interest_rate)

为什么要拆?老生常谈的、

  • 写binlog成本大,导致主从延迟
  • 避免过大的undo

题外话:

binlog是有点讨厌不像oracle用redo,历史原因,不好说

也有好处,做大数据平台集成非常简单,把MySQL的的数据实时推到大数据平台上太简单,github上一搜一大把项目直接用

MVCC&PURGE&分布式事务

原文地址:https://www.cnblogs.com/---wunian/p/9074760.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved