天天看點

關于 解決MySQL資料庫主從複制延遲的問題

像Facebook、開心001、人人網、優酷、豆瓣、淘寶等高流量、高并發的網站,單點資料庫很難支撐得住,WEB2.0類型的網站中使用MySQL的居多,要麼用MySQL自帶的MySQL NDB Cluster(MySQL5.0及以上版本支援MySQL NDB Cluster功能),或者用MySQL自帶的分區功能(MySQL5.1及以上版本支援分區功能),我所知道的使用這兩種方案的很少,一般使用主從複制,再加上MySQL Proxy實作負載均衡、讀寫分離等功能,在使用主從複制的基礎上,再使用垂直切分及水準切分;或者不使用主從複制,完全使用垂直切分加上水準切分再加上類似Memcached的系統也可以解決問題。

1.優酷的經驗

資料庫采用水準擴充,主從複制,随着從資料庫的增多,複制延遲越來越厲害,最終無法忍受。

最終還是采用資料庫的sharding,把一組使用者相關的表和資料放到一組資料庫上。

使用SSD來優化mysql的I/O,性能提升明顯,每塊16G,6塊SSD做RAID。

資料庫的類型選用MYISAM

資料庫的拆分政策,先縱向按照業務或者子產品拆分。對于一些特别大的表,再采用垂直拆分

根據使用者進行分片,盡可能不要跨篇查詢。如果确實要跨片查詢,可以考慮搜尋的方案,先索引再搜尋。

分布式的資料庫方案太複雜,否掉。

關于 解決MySQL資料庫主從複制延遲的問題

優酷使用的是資料庫分片技術,而抛棄了由于資料量的越來越多導緻複制延遲的問題。按照user_id進行分片,這樣必須有一個全局的表來管理使用者與shard的關系,根據user_id可以得到share_id,然後根據share_id去指定的分片查詢指定的資料。

假如此表的表名為sharding_manager,如果網站的使用者數太多,比如千萬級的或甚至更大比如億級的使用者,此時此表也許也會成為一個瓶頸,因為查詢會非常頻繁,所有的動态請求都要讀此表,這時可以用其它的解決方案,比如用Memcached、Tokyo Cabinet、Berkeley DB或其它的性能更高的方案來解決。

具體怎麼定位到哪台db伺服器,定位到哪個資料庫,定位到哪個shard(就是userN,msgN,videoN),優酷網的架構文檔中說得不是很仔細,這裡隻能猜測一下了。

根據優酷的架構圖,一共有2台db伺服器,每台db伺服器有2個資料庫,每個資料庫有3個shard,這樣一共是2 * 2 * 3 = 12個shard。

user_id一般是自增型字段,使用者注冊的時候可以自動生成,然後看有幾台db伺服器,假如有m台db伺服器,則用 user_id % m便可以配置設定一台db伺服器(例如0對應100,1對應101,以此類推,字段mysql_server_ip的值确定),假設每台伺服器有n個資料庫,則用user_id % n可以定位到哪個資料庫(字段database_name的值确定),假設每個資料庫有i個shard,則用user_id % i可以定位到哪個shard(字段shard_id的值确定),這樣就可以進行具體的資料庫操作了。

user_id share_id mysql_server_ip database_name

101      2           192.168.1.100   shard_db1

105      0           192.168.1.100   shard_db2

108      0           192.168.1.101   shard_db3(或shard_db1)

110      1           192.168.1.101   shard_db4(或shard_db2)

如上述user_id為101的使用者,連接配接資料庫伺服器192.168.1.100,使用其中的資料庫為shard_db1,使用其中的表系列為user2,msg2,video2

如果上述的m,n,i發生變化,比如網站的使用者不斷增長,需要增加db伺服器,此時則需要進行資料庫遷移,關于遷移,參見這兒。

因為表位于不同的資料庫中,是以不同的資料庫中表名可以相同

server1(192.168.1.100)

shard_db1

user0

msg0

video0

user1

msg1

video1

...

userN

msgN

videoN

shard_db2

因為表位于不同的資料庫伺服器中,是以不同的資料庫伺服器中的資料庫名可以相同

server2(192.168.1.101)

shard_db3(這裡也可以用shard_db1)

shard_db4(這裡也可以用shard_db2)

2.豆瓣的經驗

由于從主庫到輔庫的複制需要時間

更新主庫後,下一個請求往往就是要讀資料(更新資料後重新整理頁面)

從輔庫讀會導緻cache裡存放的是舊資料(不知道這個cache具體指的是什麼,如果是Memcached的話,如果更新的資料的量很大,難道把所有更新過的資料都儲存在Memcached裡面嗎?)

解決方法:更新資料庫後,在預期可能會馬上用到的情況下,主動重新整理緩存

不完美,but it works

豆瓣後來改為雙MySQL Master+Slave說是能解決Replication Delay的問題,不知道是怎麼解決的,具體不太清楚。

3.Facebook的經驗

下面一段内容引用自www.dbanotes.net

大量的 MySQL + Memcached 伺服器,布署簡示:

California (主 Write/Read)............. Virginia (Read Only)

主資料中心在 California ,遠端中心在 Virginia 。這兩個中心網絡延遲就有 70ms,MySQL 資料複制延遲有的時候會達到 20ms. 如果要讓隻讀的資訊從 Virginia 端發起,Memcached 的 Cache 資料一緻性就是個問題。

1 使用者發起更新操作,更名 "Jason" 到 "Monkey" ;

3 在 Virginia 有人檢視該使用者 Profile ;

4 在 Memcached 中找到鍵值,傳回值 "Jason";

5 複制追上更新 Slave 資料庫使用者名字為 "Monkey",删除 Virginia Memcached 中的鍵值;

6 在 Virginia 有人檢視該使用者 Profile ;

7 Memcache 中沒找到鍵值,是以從 Slave 中讀取,然後得到正确的 "Monkey" 。

Via

從上面3可以看出,也仍然存在資料延遲的問題。同時master中資料庫更新的時候不更新slave中的memcached,隻是給slave發個通知,說資料已經改變了。

那是不是可以這樣,當主伺服器有資料更新時,立即更新從伺服器中的Memcached中的資料,這樣即使有延遲,但延遲的時間應該更短了,基本上可以忽略不計了。

4.Netlog的經驗

對于比較重要且必須實時的資料,比如使用者剛換密碼(密碼寫入 Master),然後用新密碼登入(從 Slaves 讀取密碼),會造成密碼不一緻,導緻使用者短時間内登入出錯。是以在這種需要讀取實時資料的時候最好從 Master 直接讀取,避免 Slaves 資料滞後現象發生。還好,需要讀取實時資料的時候不多,比如使用者更改了郵件位址,就沒必要馬上讀取,是以這種 Master-Slaves 架構在多數情況下還是有效的。

 = = =

http://blogold.chinaunix.net/u3/116107/showart_2364757.html

0_php_whc 17:28:20

http://koda.javaeye.com/blog/682547

0_php_whc 17:29:51

http://blog.csdn.net/MPU/archive/2010/06/23/5689225.aspx

0_php_whc 17:29:58

http://apps.hi.baidu.com/share/detail/17180907

0_php_whc 17:32:19

我們現在采用的是

研究第四種