写在前面
隔了很久没有更新博客了,这两周一直在忙着处理线上的一个存储故障,设计新的存储方案。现将大概的处理方式记录到博客中,真实的故障情况和新的存储设计文档,不便公开。
写设计文档过程中,真实感觉到自己从开始写博客这几个月来,有了进步。文档排版、组织、问题描述等等明显比之前好了很多。技术文档也像写代码一样,需要精心设计、组织~
事故起因
业务数据库(阿里云RDS)磁盘每天增长50G+,而且持续增长,总空间占用达到85%以上,急需扩容。
分析磁盘占用情况
- 通过分析RDS binlog定位到写入量比较大的四张表;
- 通过阿里云DMS控制台,统计占用磁盘空间最大的几张表,跟binlog中定位的表一致;
大概定位占用空间比较大的几个表,接着就开始分析这几张表的结构
表结构分析
针对这几张大表,分析其字段,发现表结构存在以下几个问题
1)字段太多
一张表将近40个字段
2)字段类型选择不合适
类似枚举类型的状态字段,使用int类型
3)业务库存在Text类型字段
其实页面上没有使用
4)数据庸余太严重
这个最为严重,为了一个需要统计的数据,而把整条记录这么多字段,并且有Text大字段,写两份,造成至少一倍的空间浪费
临时解决方案
首先,可以确定第4个问题,是最浪费空间,解决掉就可以释放一半的磁盘空间。
于是,想办法将两条相同的业务数据(分两个表存储的),通过分析整合到一条上,删除另一个表中的记录。这样,离线操作就可以实现,又对线上业务基本没有影响。
本想先将磁盘空间降下来,腾出时间,再针对其他问题做进一步的优化。
接下来的问题
通过上面的临时方案,业务端删掉了将近一半的数据。问题是MySQL的Delete操作并不会释放磁盘空间,需要对表执行Optimize操作,才能清理磁盘碎片,将空间释放。
于是我们就准备对表执行Optimize操作,由于Optimize会锁表,所以需要停止写操作。
从库上执行Optimize操作释放了300G+的空间,但主库上Optimize执行14个小时都没有完成,也没有释放出多少空间来,一直卡在那。
通过跟阿里云技术咨询,MySQL对表执行Optimize操作整理碎片,需要临时空间,而我们主库的空间不够,所以一直卡在那。
数据压力
主库Optimize操作执行不动,后端数据又源源不断的有新数据进入。而且主库iops很高,sql执行比较慢。
这个时候,为了不影响业务,我们想到两种方案:
- 1)新建一个实例,把从库同步到新的实例上,然后drop掉原来的主库。
这样,由于业务端&后端还有新的数据进入,所以需要先做一次主从切换,然后同步数据完成后,再将主从切换回原来的状态
- 2)将主库再扩容,等新的存储方案设计并实现后,主库drop表来释放空间
问题解决—空间释放
起初是打算先将主库的磁盘空间释放,为新的设计开发争取时间,但Optimize执行不动,之前清理的庸余数据的空间释放不了,所以,只能采用上面列出的方案。
第一种方案是可以彻底解决问题,但需要重新创建实例,并且同步从库全部数据(将近600G)也需要比较长的时间。再者,本身现在的方案是临时解决问题的方案,没有必要做这么复杂的数据同步和主从切换。
于是,选择第二种方案,先维持现状,不能影响线上业务,扩容主库磁盘空间,为新的存储设计方案争取大概2周的时间。由于主库的磁盘iops比较高,sql执行比较慢,目前iops最大600,主库的iops使用一直处在700到800之间,处于超负荷的状态,所以这次也升级了下iops到1200。
接下来,好消息到了。扩容了磁盘,升级了iops,当前后端数据可以放心入库了。并且由于剩余空间大了,iops也升级了,Optimize表执行也(“出乎意料的”)成功了,最终庸余的磁盘空间也释放掉了,终于可以安心设计新的存储方案了。