记一次线上亿级表数据库合服
合服
我们的项目线上运营了三年多,经历了很多次开新服,合服的过程,至此有一些服已经多次合服,并入了大量的数据,这些数据中大部分已经成为僵尸数据,已经影响了服务启动速度和普通玩家体验。现在运营要求将两个已经拥有海量数据的服合并,如果这种级别的两个库合并的话无疑会造成很多隐患,也许会无法支持业务,所以在跟运行协商后决定将库中一些只进行了新手阶段体验且没有进行充值的大量僵尸玩家删除,如果这些玩家回来,重新创建角色差别也不是很大。这不是最好的解决方法,但是鉴于项目整体条件和环境,也算是一个可行的方案。
由于一些历史遗留原因和设计与实际生产产生的偏差,单个数据库实例中某些表已经变的非常庞大,数据量超过亿条,已经出现一些200ms的慢查询。将两张亿级的数据表进行合并肯定不是一个好的选择,只能将一些僵尸数据进行转移或者删除,这里在跟运营协商后直接删除了,编写了python脚本在线上环境中删除数据,尽量保证删除过程不会对表进行长时间写锁定,保证线上项目的稳定。 长时间的数据删除结束后,表数据应该减少了3/4左右,但是数据库表文件的文件大小并没有改变。 原来mysql在删除数据后并不会进行磁盘整理,这些被删掉的数据空间会被下次写入时复用。 如果需要整理碎片要进行手动操作:
alter "ENGINE=InnoDB" D=db_name,t=tbl_name
表本身存储引擎就是InnoDB,执行这样一个类似空转的语句可以让mysql对数据表进行碎片整理。但是这个语句肯定会锁表,在维护期间执行的话时间恐怕也不够,所以用pt来做这件事情
安装和使用pt-osc
wget https://www.percona.com/downloads/percona-toolkit/3.0.13/binary/redhat/6/x86_64/percona-toolkit-3.0.13-1.el6.x86_64.rpm
yum install -y percona-toolkit-3.0.13-1.el6.x86_64.rpm
pt-online-schema-change --user=root --password='your_mysql_pwd' --socket=/tmp/mysql_4306.sock --alter "ENGINE=InnoDB" D=db_name,t=tbl_name --execute
经过漫长的等待后执行完毕,表文件占用空间减少了很多。解决了所有表的空间占用后,两个本身数据量非常大的库瘦身了很多,之后再合服压力就没那么大了,基本在可控范围内。