整理這篇文章的緣由:
互聯網應用會頻繁加功能,修改需求。那么表結構也會經常修改,加字段,加索引。在線直接在生產環境的表中修改表結構,對用戶使用網站是有影響。
以前我一直為這個問題頭痛。當然那個時候不需要我來考慮,雖然我們沒專門的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在線修改表字段造成的鎖表
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操作都能夠就地執行。