Part1:写在最前

当一张单表10亿数据量的表放在你面前,你将面临着什么?

Part2:背景介绍

为了提升数据库资源利用率,一个实例中,在不互相影响,保证业务高效的前提下,我们会将同一个大业务下的不同小业务放在一个实例中,我们的磁盘空间是2T,告警阈值为当磁盘剩余空间10%时发出短信告警。笔者接到某业务主库磁盘剩余空间告警的短信后,经过一番查探,发现从几天前开始,有一张表的数据量增长非常快,而在之前,磁盘空间下降率还是较为平缓的,该表存在大字段text,其大批量写入更新,导致磁盘消耗迅猛。

我们首先来看下该表的表结构:

mysql> CREATE TABLE `tablename_v2` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`No` varchar(64) NOT NULL DEFAULT '',`Code` varchar(64) NOT NULL DEFAULT '' ,`log` varchar(64) DEFAULT '' ,`log1` varchar(64) DEFAULT '' ,.....`Phone` varchar(20) DEFAULT '',`createTime` bigint(20) unsigned NOT NULL DEFAULT '0',`updateTime` bigint(20) unsigned NOT NULL DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `uk_mailNo` (`No`,`Code`),KEY `idx_Phone` (`Phone`)
) ENGINE=InnoDB AUTO_INCREMENT=9794134664 DEFAULT CHARSET=utf8;

与业务了解得知,该表几乎没有删除操作,由于数据量过大,我们模糊使用auto_increment来作为表数量预估值,避免count()操作对线上造成的影响。

Part3:案例分析

与业务沟通了解后得知,该表可以清理4个月以前的老旧数据,因此可以使用delete的方式清除,而我们通过表结构可以看出,该表在设计之初,并没有对updateTime列创建索引,因此以时间为范围去进行delete操作,这显然是不合理的。

经过与业务协商,我们确定了可以将id作为删除条件,删除id<2577754125之前的数据

也就是说,此时的delete语句变为了:

mysql> delete from tablename_v2 where id <2577754125;

且不说delete操作有多慢,直接执行这样的SQL也会有诸如长事务告警,从库大量延迟等并发症产生,因此绝不能在生产库上进行这种大批量的危险操作。

实战

Part1:监控

从监控图我们能看出磁盘下降的趋势:

监控显示,从6月14日-6月18日期间,磁盘消耗最为严重,与业务沟通得知,618期间大促引发该表存储量激增导致。

Part2:实战操作

我们通过查看binlog发现,集群中binlog的刷新量虽不说像笔者上个案例那样多么迅猛,但也绝不是老实本分

我们可以看出,在高峰期间,binlog的刷新间隔最短达到了2分钟写满1.1GB的binlog。因此笔者与业务沟通后,首先清理binlog日志,将 expire_logs_days从7天调整至3天。

同时,清理一些能够清理的无用日志、废旧文件等等。

我们也能在上面的监控图看到在做完这些清理操作后,磁盘空间剩余从4%提升至12%,但随后依旧保持原有速率下降。

Part3:pt-archiver

真凶找到了,我们怎么办,别急,使用pt-archiver。pt-archiver工具是percona工具集的一员,是归档MySQL大表数据的最佳轻量级工具之一。他可以实现分chunk分批次归档和删除数据,能避免一次性操作大量数据带来的各种问题。

闲话不多说,一向本着实战的原则,我们直接上命令:

pt-archiver --source
h=c3-helei-db01.bj,D=helei,t=tablename_v2,u=sys_admin,p=MANAGER
--where 'id<2577754125' --purge --progress 10000 --limit=10000
--no-check-charset --txn-size=10000 --bulk-delete --statistics --max-lag=20
--check-slave-lag c3-helei-db02.bj

简单说下常用的参数:

Warning:警告这里就又有个小坑了,的确,我们使用bulk-delete参数能够增加删除速率,相比不使用bulk-delete速度能够提升10倍左右,但问题也就显现出来,在使用上述命令期间,发现binlog每秒写入量激增,这又回到了我们说的,哪些情况会导致binlog转为row格式。

首先我们需要了解到使用bulk-delete时,sql是如下执行的:

mysql> delete from tablename_v2 where id >xxx and id < xxx limit 10000.

如果您之前关注过笔者的文章,应该知道,当使用了delete from xxx where xxx limit 语法时,会将binlog_format从mixed转为row,这样的话,删除的同时,binlog由于转为了row格式也在激增,这与我们的预期是不符的。

因此最终的命令为:

pt-archiver --source
h=c3-helei-db01.bj,D=helei,t=tablename_v2,u=sys_admin,p=MANAGER
--where 'id<2577754125' --purge --progress 10000 --limit=10000
--no-check-charset --txn-size=10000  --statistics --max-lag=20
--check-slave-lag c3-helei-db02.bj

去掉了bulk-delete,这样的话就能够保证正常的delete,而不加limit,binlog不会转为row格式导致磁盘消耗继续激增。

对于Innodb引擎来说,delete操作并不会立即释放磁盘空间,新的数据会优先填满delete操作后的“空洞”,因此从监控来看就是磁盘不会进一步消耗了,说明我们的pt-archiver工具删除是有效的。

Part4:困惑

首先我们要知道,当你面对一张数据量庞大的表的时候,有些东西就会受限制,例如:

  1. 不能alter操作,因为这会阻塞dml操作。
  2. 对于本案例,空间本就不足,也不能使用pt-online工具来完成。

对于不能alter其实是比较要命的,比如开发要求在某个时间段尽快上线新业务,而新业务需要新增列,此时面对这么庞大的量级,alter操作会异常缓慢。

因此,笔者与研发沟通,尽快采用物理分表的方式解决这个问题,使用物理分表,清理表的操作就会很容易,无需delete,直接drop 老表就可以了。其次,物理分表让alter语句不会卡住太久,使用pt-online工具也不会一次性占据过多的磁盘空间诱发磁盘空间不足的告警。

再有就是迁移TiDB,TiDB相较MySQL更适合存储这类业务。

Part5:再谈binlog_format

我们选取其中高峰期的binlog发现其update操作转为了row格式,记录了所有列变更前后的所有信息,而binlog中并未出现update xxx limit这种操作,那又会是什么引发的row格式记录呢?

这里这篇文章又抛出一个新的案例,在官网那篇何时mixed转row格式中又一个没有记录的情况

官方文档:

When running in MIXED logging format, the server automatically switches from statement-based to row-based logging under the following conditions:
When a DML statement updates an NDBCLUSTER table.
When a function contains UUID().
When one or more tables with AUTO_INCREMENT columns are updated and a trigger or stored function is invoked. Like all other unsafe statements, this generates a warning if binlog_format = STATEMENT.
When any INSERT DELAYED is executed.
When a call to a UDF is involved.
If a statement is logged by row and the session that executed the statement has any temporary tables, logging by row is used for all subsequent statements (except for those accessing temporary tables) until all temporary tables in use by that session are dropped.
This is true whether or not any temporary tables are actually logged.
Temporary tables cannot be logged using row-based format; thus, once row-based logging is used, all subsequent statements using that table are unsafe. The server approximates this condition by treating all statements executed during the session as unsafe until the session no longer holds any temporary tables.
When FOUND_ROWS() or ROW_COUNT() is used. (Bug #12092, Bug #30244)
When USER(), CURRENT_USER(), or CURRENT_USER is used. (Bug #28086)
When a statement refers to one or more system variables. (Bug #31168)

我们这个案例中又出现了一个新的因素就是:

当表结构中存在多个唯一索引(包括主键id),本案例中存在主键和UNIQUE KEY `uk_mailNo`这个唯一索引,且使用了

INSERT ... ON DUPLICATE KEY UPDATE

这时,mysql binlog_format就会被转为row格式,这个内容也是记录在官网的其他章节:

https://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html

也就是说,只要业务解决了使用这种语法插入的话,磁盘空间下降迅猛的原因也能够缓解不少。我们统计发现,qps更高的其他业务中,binlog保留7天的磁盘消耗量在60GB

而该业务我们仅仅保留3天binlog,却依旧消耗了430GB的磁盘空间,这已经超过了我们整个2T磁盘空间的5分之一了。

总结

通过这个案例,我们能够了解到什么情况下binlog_format会由MIXED格式转为ROW格式,以及触发的一系列并发症和解决办法,还有pt工具pt-archiver的使用。由于笔者的水平有限,编写时间也很仓促,文中难免会出现一些错误或者不准确的地方,不妥之处恳请读者批评指正。喜欢笔者的文章,可以点一波关注,谢谢!

推荐阅读:

n南末余笙:“精神”小伙,开发三年,四面华为,豪横迈进华为​zhuanlan.zhihu.com

n南末余笙:历时三个月,我成功拿到了阿里、美团和京东的offer​zhuanlan.zhihu.com

磁盘剩余空间策略_MySQL磁盘消耗迅猛掌握这点就够了,包你事半功倍相关推荐

  1. 磁盘剩余空间策略_如何无损扩展C盘空间大小,这一招足够!

    小编身边常会有朋友问:电脑用久了,因为一开始预留空间不足就会出现C盘不够用的情况,每次打开电脑看到红色的条条真的很来气. 数据存储了很多,软件装了一大堆,不想重装系统,那么怎么实现无损扩容系统盘空间大 ...

  2. 查询linux磁盘剩余空间脚本,linux磁盘空间报警脚本

    今天分享个简单的监控磁盘空间脚本.其实shell脚本写起来不难,关键是你有整个脚本的思路! 好.大概思路是这样: 我现在想要监控/分区的空间使用量,若超过10%的话,发送一个报警短信! 首先,我们要如 ...

  3. SQL Server自动化运维系列——监控磁盘剩余空间及SQL Server错误日志(Power Shell)...

    原文:SQL Server自动化运维系列--监控磁盘剩余空间及SQL Server错误日志(Power Shell) 需求描述 在我们的生产环境中,大部分情况下需要有自己的运维体制,包括自己健康状态的 ...

  4. VC++获取磁盘剩余空间(附源码)

      VC++开发常用功能一系列文章 (欢迎订阅,持续更新...) 第23章:VC++获取磁盘剩余空间(附源码) 源代码demo已上传到百度网盘:永久生效  ,代码实现了获取任一磁盘的剩余空间,返回MB ...

  5. linux系统盘需要空间,Linux操作系统要怎么查看磁盘剩余空间

    在linux要怎么查看硬盘剩余空间呢?接下来是小编为大家收集的Linux操作系统要怎么查看磁盘剩余空间,希望能帮到大家. Linux操作系统要怎么查看磁盘剩余空间 这里我们用Df命令查看,Df命令是以 ...

  6. Qt linux获取cpu使用率、内存、网络收发速度、磁盘读写速度、磁盘剩余空间等

    Qt linux获取cpu使用率.内存.网络收发速度.磁盘读写速度.磁盘剩余空间等,实际上大部分都和qt无关的,用其他语言也可以获取. code: .h #ifndef RESOURCE_MINITO ...

  7. 通过zabbix数据库批量查询服务器最新磁盘剩余空间

    主要涉及两个sql sql1: select t1.hostid,t1.name from hosts t1 join hosts_groups t2 on t1.hostid=t2.hostid w ...

  8. linux fdisk 磁盘空间使用率,linux查看磁盘剩余空间以及cpu使用情况

    1.查看CPU个数 cat /proc/cpuinfo | grep "physical id" | uniq top可以实时的查看cpu的使用情况 2.查看CPU核数 cat / ...

  9. mysql 空间不够_mysql磁盘空间不够怎么办.md

    虚拟机vmware上硬盘空间不足怎么办? 两种方式: 1.增加一块硬盘,将一些大的数据存到转移到此硬盘上 2.扩充磁盘大小,不过空间只能增加不能减小 第一种方式我试过了,比较固定,扩展性不好 现在尝试 ...

最新文章

  1. php调用C代码的方法详解
  2. MIT公布“著名黑客之死”调查报告
  3. 基于Qt的OpenGL可编程管线学习(9)- X射线
  4. vim编辑环境设定[Linux]
  5. xml gridview控件增删改查_Mybatis之XML如何映射到方法
  6. seaborn 画堆叠柱状图_Seaborn-基于matplotlib的更强力制图库
  7. VS2015调试时没有启动IIS Express Web服务器 或者停止调试时 IIS Express 跟着关闭
  8. Spring入门与常用配置
  9. CCIE理论-第十五篇-IPV6-重分布+ACL+前缀列表
  10. 编程界的“二向箔”——Dart元编程
  11. linux shell基础
  12. 用 3 只“鸽子”,告诉你闪电网络如何改变加密消息传递方式!
  13. 第三周课程总结&实验报告一
  14. mysql 批量数据循环插入
  15. 【电路仿真】基于matlab Simulink光伏太阳能电池板仿真模型【含Matlab源码 771期】
  16. 在html中函数无效,无法在按钮点击HTML中调用JavaScript函数
  17. jap里的java文件代码_jap里的java文件代码
  18. 股基交易额市场份额(VMS)
  19. 翻译狗文档免费下载手册(补充版)
  20. python系统开发_证券交易系统设计与开发

热门文章

  1. QC无法启动,实战记录
  2. lwip连续发数据卡死_Mysteel:12月全球铁矿石发运量稳中微增 进口矿咋走?
  3. Mybatis的mapper标签 namespace属性说明
  4. MySQL与MongoDB的区别
  5. 找不到android的sdk,CircleCI – 找不到Android Studio项目的SDK位置
  6. spring mvc响应数据方式
  7. php 根号2计算过程,根号2以及π的计算--关于无理数的畅想
  8. 【C语言进阶深度学习记录】十四 C语言中 三目运算符和逗号表达式
  9. linux日常常用命令分析
  10. 阿旺wifi智能系统源码