mysql在线修改表结构大数据表的风险与解决办法归纳

整理这篇文章的缘由:

互联网应用会频繁加功能,修改需求。那么表结构也会经常修改,加字段,加索引。在线直接在生产环境的表中修改表结构,对用户使用网站是有影响。

以前我一直为这个问题头痛。当然那个时候不需要我来考虑,虽然我们没专门的dba,他们数据量比我们更大,那这种问题也会存在。所以我很想看看业界是怎么做的,我想寻找有没有更高级的方案,呵呵,让我觉得每次开发一个新功能,我在线加字段都比较纠结。后来只知道,不清楚在什么时候,无意中看到一个资料介绍online-schema-change这个工具,于是顺便搜出了不少东西。后来逐渐发现腾讯,淘宝他们都会存在这种问题,我发现解决思路都差不多。具体看完我这篇归纳的文章

由于mysql在线ddl(加字段、加索引等修改表结构之类的操作)过程如下:

A.对表加锁(表此时只读)
B.复制原表物理结构
C.修改表的物理结构
D.把原表数据导入中间表中,数据同步完后,锁定中间表,并删除原表
E.rename中间表为原表
F.刷新数据字典,并释放锁

在这个过程中会锁表。造成当前操作的表无法写入数据,影响用户使用。由于需要复制原表的数据到中间表,所以表的数据量越大,等待的时候越长,卡死在那里(用户被拒绝执行update和insert操作,表现就是延迟了一直在等待)。

其实就是对表加了个排它锁,这个时候其他用户只能读表的数据,不能写。想具体体验一下是什么效果,我以前测验对mysql的表加锁,操作的时候是如何的:http://www.cnblogs.com/wangtao_20/p/3463435.html

平时进行修改表的结构,更改字段,新增字段,更改字段名称一般都是通过ALTER TABLE  TABLENAE 语法进行修改的。对于测试库,在线小表或者并发访问不是很大的情况是OK。但是如果是在线大表。那就很麻烦。由于表数据量大,复制表需要比较长的时间,在这个时间段里面,表是被加了锁的(写锁),加写锁时其他用户只能select表不能update、insert表。表数据量越大,耗时越长。

所以,对于数据量大的表,数量很大。在线修改表结构一直是一个头痛的问题,因为互联网应用的一大特点不能影响用户正常使用,否则用户会慢慢流失掉。

有些公司碰到的表数据很小,几万到几十万行数据一张表,可能还不会遇到应用卡死的问题。所以我们网站在跑,开发个新功能,需要加个新字段,经常是直接操作不会影响什么(何况只是延迟写入操作而已,呵呵)

看这几篇文章就知道了:

1、http://wiki.hexnova.com/pages/viewpage.action?pageId=2031684 mysql在线修改表字段造成的锁表

2、http://hidba.org/?p=795

3、比如就有人专门在加字段之前进行测验mysql是否复制表,以减低应用卡死的风险:http://www.cnblogs.com/zuoxingyu/archive/2013/03/28/2986715.html

拷贝表结构,然后插入少量的数据。去修改表结构。看影响的行。如果为0,则表示不会拷贝中间表的方式

目前业界实践出了一些成熟的解决办法

1、很多公司以前的做法是:停掉mysql服务器来修改表结构。然后进行滚动式更新。比如很多台mysql服务器。先修改主服务器的表结构,把这台服务器停掉来更新(一般多台主服务器,让其他主服务器提供服务)。等到更新完,就滚动到从服务器(在此之前是其他从服务器提供服务的)。其实想想发现有个弊病:修改表结构要等到很长时间才能生效。mysql服务器越多,就需要的时间越长。那我可以理解:假设需要几天,那只有等到更新完毕。才能把代码丢上去,因为表结构没有更新完毕,新的程序操作新的字段会出错的。

从冯大辉那篇文章那里听说,Facebook数千台MySQL服务器在过去增加个索引需要几个月的滚动升级(后来他们自己开发了后面提到的工具,只需要几天)

能够停掉mysql服务器来修改字段,这就好办,时间长也无所谓,呵呵,至少用户不会使用你网站的时候卡死吧。但是互联网应用往往不能影响用户使用,所以很多公司尽量是在凌晨的时候进行操作(这个时候访问用户少,对用户影响就小)

比如像这个例子:http://www.mysqlops.com/2011/03/30/myisam-innodb.html

表的数据量上亿。要把表的存储引擎从myisam改为innodb(我觉得存储结构都不同了,转换需要时间更长),但是他是停掉mysql服务器操作的

阿里巴巴的冯大辉分享中也提到,业务应用大,需求就会频繁变化。所以就经常涉及到修改数据库字段,在线的调整字段是要考虑很多的问题的。作者认为,目前没有特别的方法来解决这个问题(技术是适应需求变化,支撑运营的)。他说豆瓣对此也很头痛,只能把服务器短暂的停一下。

2、测验法。加字段,加索引,先在测试环境模拟测试一下需要多长时间。免得服务器生产环境正式加的时候,应用卡死了,好有个预期准备。

我记得以前在a公司,表数据量也上千万,压根就没这种测验吧,大白天,就直接加字段和索引,反正我也不知道前台影响如何,当时我也没这个经验,何况我也不是技术负责人,呵呵,技术负责人都没不清楚这个,我那就更加没了,那个技术经理是做企业级开发的,跟web开发环境和思维方式是不同的,他不清楚会存在这些影响吧,再说,当时在加的时候没法凑巧用户投诉说,网站无法下单了啊,没这么巧的情况。其实从我现在理解角度来看,我绝对会更加严格点。

前面也提到了,国外有人研究修改表结构会不会复制一张临时表,就看"rows affected “的值。如果为0,则表示不会拷贝中间表的方式,这样子就很快的。我没试过

3、使用专门的辅助工具。一些公司开发了自己的内部工具来辅助进行。比如facebook。

另外腾讯的技术也介绍了他们自己定制的tmysql进行在线加字段的实现原理:

http://www.zhdba.com/mysqlops/2013/09/14/mysql-innodb-online-ddl/

facebook自己开发的工具,官网:

http://bazaar.launchpad.net/~mysqlatfacebook/mysqlatfacebook/tools/files/head:/osc

----------------------------------------------------------------------

我记得好像最先是facebook进行了方案创新(呵呵,当你的遇到的是复杂问题,没有人解决过就只能先创造新的技术方案了),当时冯大辉专门写了一篇,其他文章介绍他们的创新。其他工具都是跟这个思路差不多的。不过我下载了facebook官网的,是用php实现的。没具体看。因为下载的包里面都是php文件。

总的来说,这些工具大致的理大同小异:表结构的修改在创建的一张新表中执行(这样不需要锁定原表了,也就不会影响mysql提供服务),更为关键的是解决了一个问题,当这个间隔时间内,用户在使用mysql,对表数据进行了更新怎么办?

工具的解决办法思路是,在原表中创建几个触发器针对uptate、delete 、insert操作都记录下来,这样子把对原表的操作记录下来,方便更新到新建立的临时表中中去。

听过豆瓣网的架构变迁分享会中提到,他们以前在这方面也吃过苦头的,一张很大的表(比如上千万),在线加个索引,由于数据量大,整个应用就卡死了。

其实有时候卡几个小时可能都很正常。死锁了嘛。另外对临时表要进行复制数据,建立这个临时表也需要时间嘛。

他们现在用的办法是:先拷贝一张一模一样的表,数量也是差不多,先在这张表上面测试,看看需要多长时间。如果几分钟,是在可以接受的时间范围内,就可以。如果几个小时就不行了。这样子提早预先知道。

另外,也使用了online-schema-change这个工具。

关于online-schema-change

是percona推出的一个针对mysql在线ddl的工具

percona是一个mysql分支维护公司,专门提供mysql技术服务的。我的理解,类似于linux的分支redhat公司

官网下载地址为:http://www.percona.com/redir/downloads/percona-toolkit/2.2.1/percona-toolkit-2.2.1.tar.gz

腾讯,淘宝,百度这些公司多少都有自己开发的工具来解决这个头痛的问题。

另外,mysql5.5企业版是支持在线ddl了,不过企业版要收费嘛

MySQL 5.6改进了安全功能,例如对关键配置文件和用户密码的加密方式,但是对InnoDB的提升才是大新闻。使用该存储引擎的最后一个主要障碍便是缺少全文索引,但是现在这个问题已经不复存在了。

该版本还为InnoDB引入了在线DDL,DBA一定会非常喜欢这个功能。增加、重命名和删除列等常用的操作可以和并发查询同时执行。尽管可能涉及到一些数据的复制或重组,但是大多数在线DDL操作都能够就地执行。

上一篇:java数组的拷贝四种方法:for、clone、System.arraycopy、arrays.copyof


下一篇:mysql 5.6 在线 DDL