前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第 01 期 [事务] 事务的起源:事务池和管理器的初始化

第 01 期 [事务] 事务的起源:事务池和管理器的初始化

作者头像
爱可生开源社区
发布2024-01-04 12:51:57
1120
发布2024-01-04 12:51:57
举报
文章被收录于专栏:爱可生开源社区

作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。

正文

1. 事务池和管理器

作为 MySQL 中支持事务的默认存储引擎,InnoDB 对表中数据的读写操作都在事务中执行。

MySQL 被设计为支持高并发,支持很多客户端同时连接到数据库,这些连接可以同时执行 SQL。

如果这些 SQL 都要读写 InnoDB 表,InnoDB 会为每个连接启动一个事务,这意味着需要同时启动很多事务。

对于 TP 场景,通常情况下,事务都会很快执行完成。启动事务、执行 SQL、提交事务的整个流程只会持续很短的时间。

TP 是 OLTP 的简称,表示在线事务处理;与之相对的另一个常用术语 AP,是 OLAP 的简称,表示在线事务分析。

以这样一个场景为例:

  • 客户端连接到 MySQL。
  • 客户端执行 begin 语句。
  • 客户端执行一条 update 语句,按主键 ID 更新一条记录。 这个步骤中,InnoDB 会在执行 update 语句之前,真正启动一个事务。
  • 客户端执行 commit 语句。
  • 客户端关闭数据库连接。InnoDB 会在这一步释放事务。

在这个场景下,InnoDB 事务从启动到释放的整个生命周期,有可能只持续 1 ~ 2 毫秒(甚至更短)。

由于要存放事务 ID、事务状态、Undo 日志编号、事务所属的用户线程等信息,每个事务都有一个与之对应的对象,我们称之为事务对象

每个事务对象都要占用内存,如果每启动一个事务都要为事务对象分配内存,释放事务时又要释放内存,会降低数据库性能。

为了避免频繁分配、释放内存对数据库性能产生影响,InnoDB 引入了事务池(Pool),用于管理事务。

顾名思义,事务池是一个池子,这个池子存放的东西既不是水,也不是酒,而是事务对象。

对比我们生活中的各种池子,例如:水池、洗手池、池塘,都是有大小限制的。

事务池也一样有大小限制,不能无限制的存放事务对象。数据库繁忙的时候,有很多很多事务对象,需要多个事务池来管理。

事务池多了之后,又会引发另一些问题,例如:

  • 怎么创建新的事务池?
  • 客户端创建了一个新的数据库连接,要获取一个新的事务对象,从哪个事务池获取?
  • 其它问题...

为了解决这些问题,InnoDB 又引入了事务池管理器(PoolManager),用于管理事务池。

MySQL 启动过程中,InnoDB 先创建事务池管理器,然后,事务池管理器创建并初始事务池。

2. 创建事务池管理器

InnoDB 整个生命周期中,事务池管理器只有一个,它有个很重要的属性(m_size),用于指定每个事务池能用多大内存来存放事务对象。

这个属性值来源于一个硬编码的常量值,代码里是这样定义的:

代码语言:javascript
复制
/** Size of on trx_t pool in bytes. */
static const ulint MAX_TRX_BLOCK_SIZE = 1024 * 1024 * 4;

这意味着每个事务池能用来存放事务对象的内存是 4194304 字节,也就是 4M。

MySQL 启动过程中,事务池管理器只会创建并初始化一个事务池。

这个事务池会放入事务池管理器的 m_pools 属性。这个属性是个数组(vector),用于管理所有事务池。

创建事务池的过程中,InnoDB 会分配一块 4M 的内存用于存放事务对象。

每个事务对象的大小为 992 字节,4M 内存能够存放 4194304 / 992 = 4228 个事务对象。

3. 初始化事务池

事务池创建完成之后,就该初始化了。事务池的初始化,主要是为了得到一些事务对象。

事务池有一个队列,用于存放已经初始化的事务对象。我们称这个队列为事务队列

一个事务池有 4M 内存可以存放事务对象,这块内存会被分隔成 4228 个小块。每初始化一块小内存,就会得到一个事务对象,这个事务对象会被放入事务队列。

InnoDB 初始化事务池的过程中,不会初始化全部的 4228 块小内存,只会初始化最前面的 16 块小内存,得到 16 个事务对象并放入事务队列。

初始事务池完成之后,事务队列中只有 16 个事务对象。

那么,剩余的 4212 块小内存什么时候会被初始化?

它们会在这种情况下被初始化:启动过程中初始化的 16 个事务对象都被取走使用了,事务队列变成空队列了。

此时,需要再分配一个事务对象用于启动新事务,InnoDB 就会把剩余的 4212 块小内存全部初始化,得到 4212 个事务对象并放入事务队列。

有一点需要说明,不管是启动过程中初始化的 16 块小内存,还是运行过程中初始化的 4212 块小内存,都是在循环里一个一个初始化的。每一轮循环都要干两件事:

  • 初始化一块小内存,得到一个事务对象。
  • 把事务对象放入事务池的事务队列中。

初始化小块内存的过程中,会初始化事务对象的各个属性。这里我们就不一一介绍这些属性了,等到该它们出场的时候,再按需介绍。

4. 总结

InnoDB 只有一个事务池管理器,用于管理 N 个事务池(N >= 1),每个事务池可以管理 4228 个事务对象。

MySQL 启动过程中,InnoDB 会先创建事务管理器。事务管理器会创建一个事务池,初始化 16 个事务对象放入事务池的事务队列。

MySQL 运行过程中,如果这 16 个事务对象都正在被使用,InnoDB 需要一个新的事务对象时,会一次性初始化剩余的 4212 个事务对象并放入事务池的事务队列。

本期问题:运行过程中,创建一个新的事务池,会分配多少内存?初始化多少个事务对象? 关于本期主题,如果大家有任何疑问,欢迎留言交流!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 爱可生开源社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 事务池和管理器
  • 2. 创建事务池管理器
  • 3. 初始化事务池
  • 4. 总结
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档