背景
在日常业务使用中,经常遇到由于日志增长非常快速,而磁盘空间预留不足,导致磁盘空间被打满的情况,从而影响业务正常运转。
今天就说说,遇到此类问题如何处理和正常使用的姿势。
针对环境:
RDS SQL Server 基础版、高可用版本。
日志使用原理
在讲解如何处理日志增长问题之前,先说说日志设计原理与机制。
日志的用途
- 每个 SQL Server 数据库都有独立的事务日志文件,用于记录所有事务所做的数据库修改。
- 事务日志是数据库的一个关键组件。 如果系统出现故障,你将需要依靠该日志将数据库恢复到一致的状态。
事务日志的循环性质
事务日志是一种回绕的文件。 例如,假设有一个数据库,它包含一个分成四个 VLF 的物理日志文件。 当创建数据库时,逻辑日志文件从物理日志文件的始端开始。 新日志记录被添加到逻辑日志的末端,然后向物理日志的末端扩张。 日志截断将释放记录全部在最小恢复日志序列号 (MinLSN) 之前出现的所有虚拟日志。 MinLSN 是成功进行数据库范围内回滚所需的最早日志记录的日志序列号。 示例数据库中的事务日志的外观与下图所示相似。
当逻辑日志的末端到达物理日志文件的末端时,新的日志记录将回绕到物理日志文件的始端。
这个循环不断重复,只要逻辑日志的末端不到达逻辑日志的始端。 如果经常截断旧的日志记录,始终为到下一个检查点前创建的所有新日志记录保留足够的空间,则日志永远不会填满。 但是,如果逻辑日志的末端真的到达了逻辑日志的始端,将发生以下两种情况之一:
FILEGROWTH
如果为日志启用了该设置,并且磁盘上有可用空间,则该文件将按FILEGROWTH
参数中指定的数量进行扩展,并将新日志记录添加到扩展中。 有关设置的详细信息FILEGROWTH
,请参阅FILEGROWTH
。- 如果未启用该
FILEGROWTH
设置,或保存日志文件的磁盘的可用空间小于FILEGROWTH
中指定的数量,则会生成9002错误。
日志截断
日志截断主要用于阻止日志填充。 日志截断从 SQL Server 数据库的逻辑事务日志中删除不活动的虚拟日志文件,释放逻辑日志中的空间以便物理事务日志重用这些空间。 如果事务日志从不截断,它最终将填满分配给物理日志文件的所有磁盘空间。 但是,在截断日志前,必须执行检查点操作。 检查点将当前内存中已修改的页(称为“脏页”)和事务日志信息从内存写入磁盘。 执行检查点时,事务日志的不活动部分将标记为可重用。 此后,日志截断可以释放不活动的部分。
下列各图显示了截断前后的事务日志。 第一个图显示了从未截断的事务日志。 当前,逻辑日志使用四个虚拟日志文件。 逻辑日志开始于第一个逻辑日志文件的前面,并结束于虚拟日志 4。 MinLSN 记录位于虚拟日志 3 中。 虚拟日志 1 和虚拟日志 2 仅包含不活动的日志记录。 这些记录可以截断。 虚拟日志 5 仍未使用,不属于当前逻辑日志。
第二个图显示了日志截断后的情形。 已释放虚拟日志 1 和虚拟日志 2 以供重新使用。 现在,逻辑日志开始于虚拟日志 3 的开头。 虚拟日志 5 仍未使用,它不属于当前逻辑日志。
活动日志
日志文件中从 MinLSN 到最后写入的日志记录这一部分称为日志的活动部分,或者称为活动日志。 这是进行数据库完整恢复所需的日志部分。 永远不能截断活动日志的任何部分。 所有的日志记录都必须从 MinLSN 之前的日志部分截断。
下图显示了具有两个活动事务的结束事务日志的简化版本。 检查点记录已压缩成单个记录。
LSN 148 是事务日志中的最后一条记录。 在处理 LSN 147 处记录的检查点时,Tran 1 已经提交,而 Tran 2 是唯一的活动事务。 这就使 Tran 2 的第一条日志记录成为执行最后一个检查点时处于活动状态的事务的最旧日志记录。 使 LSN 142(Tran 2 的开始事务记录)成为 MinLSN。
长时间运行的事务
活动日志必须包括所有未提交事务的每一部分。 如果应用程序开始执行一个事务但未提交或回滚,将会阻止数据库引擎推进 MinLSN。 这可能会导致两种问题:
- 如果系统在事务执行了许多未提交的修改后关闭,以后重新启动时,恢复阶段所用的时间将比“恢复间隔” 选项指定的时间长得多。
- 因为不能截断 MinLSN 之后的日志部分,日志可能变得很大。 即使数据库使用的是简单恢复模式,这种情况也有可能出现,在简单恢复模式下,每次执行自动检查点操作时通常都会截断事务日志。
日志截断两种方法
- 日志备份
- 更改简单恢复模式
查看日志使用
查看日志状态的三个命令:
- sys.dm_db_log_info:查看日志详细使用信息
- sys.dm_db_log_stats:查看日志状态统计信息
- sys.dm_db_log_space_usage:查看日志空间使用信息
1. sys.dm_db_log_info
-- db02 为示例数据库名称select*from sys.dm_db_log_info(DB_ID('db02'));
下图为执行结果剪切截图
2. sys.dm_db_log_stats
select*from sys.dm_db_log_stats(DB_ID('db02'));
3. sys.dm_db_log_space_usage
use db02;SELECT*FROM sys.dm_db_log_space_usage;
总结
- 主要查看vlf_status 字段,此字段0不活跃,2为活跃。状态为0的可以重用。
- 可以看出,总共有78个VLF 虚拟日志文件。
- 其中有27个是活跃的,51个为可以使用的状态。
- 日志空间已使用比例 14%
- 此时的27个活跃VLF 虚拟日志文件,并非是有活跃事务,只是没有进行日志备份进行截断。
注:虽然现在日志空间只使用了14%,若执行日志收缩操作,不会释放任何空间。因为释放空间,只会释放在文件尾部VLF 状态连续为 0 状态的部分。
合理日志备份
如上面说明,日志备份是为了及时进行日志截断,达到可以重复使用日志空间。
此时进行日志备份,然后在看日志状态。备份通过RDS 30分钟日志备份自动完成。
- 日志备份之后,活跃VLF 只有一个。
- 目前还是有78个VLF 虚拟日志文件,并不会减少。
- 此时min_lsn 和 end_lsn 都集中在 140 号的VLF 上。
- 目前日志空间只有 0.5% 使用率,基本都是空闲的。
执行日志文件收缩操作
use db02;DBCC SHRINKFILE (N'db02_log',0, TRUNCATEONLY)
在日志状态
- 日志文件,VLF 140 之后未活跃部分VLF 全部都释放掉了。
- 然后VLF 循环使用,VLF end_lsn 移动到了开头的部分。
- 日志空间,已经从3GB释放到了300MB。
- 此若还需要进行一释放空间,就是要进行日志备份,移动尾部活跃 VLF 位置。
- 然后在进行重复收缩操作。
紧急截断收缩操作
背景
有的时候,日志备份增长的非常大了,导致空间被打满,从而严重影响到了业务。
这个需要在等备份和收缩操作,可能由于空间满不无成功,或者需要等待非常久的时间。
就需要紧急截断+收缩空间,恢复业务。
操作
- 修改简单恢复模式
- 进行收缩日志文件
注:此操作,非必要,不要进行。
影响:
- 截断日志,会打断备份链,会影响恢复数据库操作。
- 高可用版本,还需要额外的重搭镜像流程。(此流程需要进行备份+备库还原操作,期间处于非高可用状态)
查看当前的日志状态
1. 修改简单恢复模式
RDS SQL Server 基础版本
可以直接修改
USE [master]GO ALTER DATABASE [db02]SET RECOVERY SIMPLE WITH NO_WAIT GO
RDS SQL Server 高可用版本
需要先关闭镜像,才可以修改简单恢复模式
高可用版本不关闭镜像会报错
修改简单恢复模式时,会抛出异常报错,是因为RDS 有触发器进行限制,禁止设置简单恢复模式。
触发器原理是在修改简单恢复模式时,会自动更回FULL模式
2. 通过查看错误日志可以看触发器操作逻辑
EXEC sp_rds_read_error_logs0,1,'db02';
3.此时在查看日志状态,只有一个活跃VLF
4. 此时进行收缩日志文件
use db02;DBCC SHRINKFILE (N'db02_log',0, TRUNCATEONLY)
5.此时查看日志文件,只剩下8MB大小
参考文档
查看SQL Server 错误日志:
https://help.aliyun.com/document_detail/95645.html