MySQL日志系统知识点总结

本文详细介绍了MySQL日志系统,包括InnoDB引擎的redo日志(记录数据改动,循环写入,用于崩溃恢复),undo日志(确保事务原子性,分为insert和update两类),以及server层的binlog日志(归档用,逻辑日志,支持主从复制)。此外,还讨论了redo日志的两阶段提交机制,以保证binlog和redo日志的一致性。

目录

0 引言

1 redo日志

2 undo日志

3 binlog日志

4 redo日志的两阶段提交


0 引言

针对mysql日志系统的一些总结,主要是Innodb的redo日志和undo日志,然后就是server层的binlog日志,复习资料主要来自极客时间《Mysql实战45讲》和《MySQL是怎样运行的》

1 redo日志

redo日志是什么

redo日志记录了我们对于数据的改动操作。我们在对数据库进行操作的时,都是对buffer pool中的页面进行操作,当系统崩溃时这些页面也就会丢失从而使得数据库的数据出现丢失。所以我们需要将对数据库的改动操作记录到磁盘中,直接将buffer pool中的页面刷新到磁盘中是十分浪费时间和空间的,我们可以将对每次对数据库的改动记录成一条redo日志,这样只刷新较小的redo日志到磁盘中就更加节约资源。

Innodb引擎特有的

redo日志的写入过程

首先说明一点,就是我们的redo日志是按组写入的,也就是所谓的MTR,MTR表示对底层页面的一次原子访问,一次原子访问可能产生多条redo日志,这些redo日志就称为一个组。

我们的redo日志也是先写到缓存中,再写到磁盘上的。在内存中有一个redo log buffer的区用来存储我们的redo日志,这部分区域分为了一个个block,每个block占用了512字节。这些block占用的是一块连续的空间,我们向里面写redo日志就是按照组从第一个block开始顺序写入的

向磁盘中写redo日志的时机

  • log buffer不足时

  • 事务提交时

  • 将脏页flush会磁盘前需要先将redo日志刷新到磁盘

  • 后台有一个线程以大约每秒一次的频率刷新日志

  • 正常关闭服务器时

  • 做checkpoint时

几个关键的变量

  • buf_free 记录了log buffer中下一条要写入的redo日志的位置

  • lsn 记录了当前写入log buffer的redo日志数量

  • buf_next_to_write 标记当前log buffer中已经有哪些redo日志被刷新回磁盘了

  • flushed_to_disk_lsn 表示刷新到磁盘中的日志的全局变量

  • checkpoint_lsn 记录已经没有用的redo日志的量

    我们的redo日志最终会被循环写到磁盘中的一些redo日志文件中,这个日志文件是有固定大小的,为了防止追尾导致redo日志被覆盖的问题引入checkpint_lsn这个值记录了当前可以被覆盖的redo日志的最大lsn值。

某一个时刻,这几个属性的值的可能关系如下:

lsn = buf_free >= flush_to_disk_lsn = buf_next_to_write >= checkpoint_lsn

checkpoint_lsn的确定方法

要说checkpoint_lsn的确定方法,先来看我们flush链表中的两个属性,flush链表是buffer pool中的一个链表,维护了我们做了修改的页面,每个页面中有两个属性,一个是oldest_modification:该属性记录了第一次对这个页面进行修改的事务的lsn值,一个是newest_modification:该属性记录了最近修改这个页面的事务的lsn值。当我们对页面进行修改后就会将页面放入到flush链表的头部,若之后再对这个页面进行修改,不需要移动页面在链表中的位置,只需要修改其newest_modification的值就行了。

checkpoint_lsn记录了可以覆盖的redolog量,当我们redo日志对应的页面已经被刷新会磁盘中,那么这个页面对应的redo日志也就可以被覆盖了,checkpoint_lsn的值在进行checkpoint的时候进行更新,我们只需要获取系统中最早修改脏页的oldest_modification,那么lsn小于这个值的页面肯定就已经被刷新回了磁盘中,所以这个oldest_modification值就是checkpoint_lsn值。

崩溃恢复

根据checkpoint找到redo日志文件的恢复起点后就可以挨着读取redo日志进行数据恢复了

2 undo日志

undo日志是什么

undo日志是为了保证我们事务的原子性而引入的,当我们开启一个事务时,我们可以通过回滚操作来将数据库恢复到原来某个时间点的状态,这就需要我们的undo日志;同时,当我们事务还未提交系统崩溃了,那么我们在该事务中进行的修改就不应当失效,这也需要用到undo日志的。undo日志记录了我们对页面中的记录进行了怎样的修改。

undo日志的存储方式

undo日志是直接存放在undo页面中的,undo日志又可分为两个大类,分别是insert undo日志和update undo日志,然后根据表的类型不同又可以进一步划分,分别是普通表的undo日志(insert 和 update)和临时表的undo日志(insert 和update),这些undo 日志页面是通过链表组织起来的,所以一个事务的undo日志被存放在以下四个链表中

  • 普通表的insert日志链表

  • 普通表的update日志链表

  • 临时表的insert日志链表

  • 临时表的insert日志链表

这些链表的头结点又全部被保存在回滚段的slot槽中(回滚段的一个slot槽指向一个undo日志链表)

需要注意的是,并不是一开始事务就给事务分配了这些undo链表,只有在需要记录相应的undo日志时才需要创建对应的链表

undo日志与记录之间的关系

聚簇索引中的记录有三个隐藏列,分别是row_id,trx_id,roll_pointer,其中的row_pointer就指向了该条记录最新的一条undo日志,undo日志中也有一个roll_pointer属性,指向该undo日志之前的一条undo日志,通过roll_pointer属性也就构成了一条记录的版本链,服务于MVCC。

3 binlog日志

binlog日志是什么

binlog是server层的日志,称为归档日志,只用作归档用,和redo日志的区别

  • redo日志是Innodb引擎特有的,binlog是server层提供的

  • redo日志是物理日志,记录了我在哪个数据页上做了什么修改,binlog是逻辑日志,记录的是执行语句的原始逻辑

  • redo日志是循环写,binlog日志是追加写,所以binlog不存在覆盖问题

binlog日志的分类

mysql的高可用架构都是基于binlog来实现的,我们的binog是归档所用,主要两种格式,分别是statements和rows格式,两个格式的区别如下:

  • statements

    改格式下的binlog记录的是我们直接执行的语句,比如执行

    delete * from t where id = 1;

    这是产生的binlog记录的就是这条执行的语句。但是这类binlog存在一个问题就是我们的语句在主库和从库中有可能会通过不同的索引执行,这样就可能会导致中裤和从库的不一致性

  • rows

    改格式下的binlog记录的是我们对哪个表的哪一行做了什么样的修改,比如上面的那条delete语句,在生成rows格式的binlog时就是记录了删除表t的id=1的行。这种格式的binlog记录的信息更加完整。

4 redo日志的两阶段提交

来看一下我们一条更新语句的执行过程,首先在内存中进行数据页的更新,然后就开始写redo日志,这时候处于prepare状态,然后写binlog日志,最后提交事务处于commit状态。所谓的两阶段提交就是将写redo日志分为了prepare和commit两个状态。那么为什么需要两阶段提交呢?我们来看不用两阶段提交会产生什么后果

  • 先提交redo log 然后提交binlog,若我们提交redolog后系统崩溃,那么后面的binlog就没有被写入,由于redo日志是完整的,所以可以完全恢复数据库中的数据,但是由于binlog没有写,那么当我们用binlog来备份临时库的时候由于缺少这条binlog而导致和原库数据不一致的情况

  • 先提交binlog然后redolog,若我们提交binlog后系统崩溃,由于redolog没有写入所以系统恢复后的数据库缺少该条redolog对应的数据,但是当我们用binlog备份临时库的时候由于binlog存在记录下了系统崩溃前的操作,所以最后得到的临时库与主库中的数据不一致

所以采用两阶段提交主要是为了保证binlog和redolog两者的一致性。

<think>好的,用户想做一个微信小程序,主题是愚公移山,每个人每秒钟生成10个子。我需要先理解用户的需求。首先,愚公移山的故事是关于坚持不懈的精神,所以小程序可能希望用户通过不断“生子”来象征移山的努力。 用户提到每秒钟生成10个子,这可能意味着用户需要一种自动增长的机制,但每秒10个的速度非常快,需要考虑实际可行性。微信小程序的性能是否支持这么高的生成频率?可能需要调整速度,比如每秒1个或每分钟几个,以避免卡顿或数据过载。 接下来,用户可能需要功能设计方面的建议。比如用户如何开始生成子嗣,是否需要点击按钮,还是自动进行。界面设计可能需要显示当前子嗣数量、移山进度,以及可能的成就系统来激励用户持续参。 数据存储方面,用户的进度需要保存在本地或服务器。本地存储简单但容易丢失,云开发可以持久化数据但涉及成本。用户可能没有技术背景,需要推荐易用的解决方案,比如微信云开发。 动画效果方面,简单的粒子效果或图标移动可以增强体验,但复杂动画可能影响性能。需要平衡美观和流畅度。 合规性方面,微信小程序有严格的内容规范,确保主题不涉及敏感内容,比如“生子”是否符合规定,可能需要调整用词,比如改为“帮手”或“工人”。 用户可能希望加入社交元素,比如排行榜或分享功能,让朋友之间竞争,增加活跃度。但需要用户授权和隐私保护。 最后,用户可能需要技术实现步骤的指导,比如使用setInterval或WebSocket进行实时更新,前端框架的选择,以及后端如何处理高并发请求。如果用户是新手,可能需要更详细的教程或推荐开发工具。 总结,用户的核心需求是做一个以愚公移山为主题的微信小程序,核心机制是自动生成子嗣来移山。需要从功能设计、技术实现、合规性和用户体验等方面提供建议,同时考虑实际可行性和用户的技术水平,给出合适的解决方案。</think>好的!如果要设计一个以“愚公移山”为主题的微信小程序,核心机制是“每秒钟生成10个子”来模拟愚公家族不断壮大的过程,以下是分步实现的思路和建议: --- ### **一、核心机制设计** 1. **子嗣生成逻辑** - **自动增长**:每秒自动生成10个子嗣(需考虑实际性能,建议用虚拟数值而非实时渲染大量对象)。 - **手动触发**:添加按钮让用户点击加速生成(例如“召集村民帮忙”)。 2. **数值平衡** - **初始速度**:1秒/10个子(默认速率)。 - **加速规则**:通过道具或成就提升速度(如“神话加成”使速度翻倍)。 --- ### **二、技术实现方案** #### **前端(微信小程序框架)** 1. **计时器控制** ```javascript let timer = null; let childrenCount = 0; // 启动生成 function startGenerating() { timer = setInterval(() => { childrenCount += 10; // 每秒+10 this.setData({ count: childrenCount }); }, 1000); } // 停止生成 function stopGenerating() { clearInterval(timer); } ``` 2. **动画效果** - 使用CSS3动画或`<canvas>`绘制简单粒子效果(如小人物图标从底部向上飘动)。 #### **后端(可选)** - 如需保存用户进度,可使用微信云开发(云数据库): ```javascript const db = wx.cloud.database(); // 存储数据 db.collection('users').add({ data: { count: childrenCount, timestamp: new Date() } }); ``` --- ### **三、功能扩展建议** 1. **移山进度可视化** - 设计一个山脉图标,子嗣数量越多,山脉逐渐被“挖空”(通过进度条或图形变化体现)。 2. **成就系统** - 里程碑奖励(如“1000子嗣解锁新工具”)。 - 彩蛋事件(如“玉帝感动,瞬间生成10000子”)。 3. **社交互动** - 排行榜:对比好友的移山进度。 - 分享助力:邀请好友加速生成。 --- ### **四、注意事项** 1. **性能优化** - 避免高频更新UI导致卡顿,可改为每秒更新一次数值。 - 粒子动画需限制最大数量(如仅显示最后100个子嗣的动画)。 2. **合规性** - 避免使用“生子”等敏感词汇,可替换为“帮手”“工人”等。 3. **用户留存** - 加入离线收益(关闭小程序后按时间计算子嗣增长)。 --- ### **五、示例界面设计** 1. **主页布局** ``` [山脉图标(动态减少)] [当前子嗣数量:10000] [加速按钮] [分享按钮] [成就列表] ``` 2. **动效灵感** - 子嗣图标从屏幕底部向上滑动,象征“移山”。 --- 如果需要具体代码片段或更详细的技术实现步骤,可以告诉我您想深入的部分(如动画、云存储等)! 🌄
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值