引言
隨著互聯網應用的廣泛普及,海量數據的存儲和訪問成為了系統設計的瓶頸問題。對于一個大型的互聯網應用,每天幾十億的PV無疑對數據庫造成了相當高的負載。對于系統的穩定性和擴展性造成了極大的問題。通過數據切分來提高網站性能,橫向擴展數據層已經成為架構研發人員首選的方式。
- 水平切分數據庫:可以降低單臺機器的負載,同時最大限度的降低了宕機造成的損失;
- 負載均衡策略:可以降低單臺機器的訪問負載,降低宕機的可能性;
- 集群方案:解決了數據庫宕機帶來的單點數據庫不能訪問的問題;
- 讀寫分離策略:最大限度了提高了應用中讀取數據的速度和并發量;
為什么要數據切分
上面對什么是數據切分做了個概要的描述和解釋,讀者可能會疑問,為什么需要數據切分呢?像Oracle這樣成熟穩定的數據庫,足以支撐海量數據的存儲與查詢了?為什么還需要數據切片呢?
的確,Oracle的DB確實很成熟很穩定,但是高昂的使用費用和高端的硬件支撐不是每一個公司能支付的起的。試想一下一年幾千萬的使用費用和動輒上千萬元的小型機作為硬件支撐,這是一般公司能支付的起的嗎?即使就是能支付的起,假如有更好的方案,有更廉價且水平擴展性能更好的方案,我們為什么不選擇呢?
我們知道每臺機器無論配置多么好它都有自身的物理上限,所以當我們應用已經能觸及或遠遠超出單臺機器的某個上限的時候,我們惟有尋找別的機器的幫助或者繼續升級的我們的硬件,但常見的方案還是橫向擴展,通過添加更多的機器來共同承擔壓力。我們還得考慮當我們的業務邏輯不斷增長,我們的機器能不能通過線性增長就能滿足需求?Sharding可以輕松的將計算,存儲,I/O并行分發到多臺機器上,這樣可以充分利用多臺機器各種處理能力,同時可以避免單點失敗,提供系統的可用性,進行很好的錯誤隔離。
綜合以上因素,數據切分是很有必要的。 我們用免費的MySQL和廉價的Server甚至是PC做集群,達到小型機+大型商業DB的效果,減少大量的資金投入,降低運營成本,何樂而不為呢?
在大中型項目中,在數據庫設計的時候,考慮到數據庫最大承受數據量,通常會把數據庫或者數據表水平切分,以降低單個庫,單個表的壓力。這里介紹兩個項目中常用的數據表切分方法。當然這些方法都是在程序中?使用一定的技巧來路由到具體的表的。首先我們要確認根據什么來水平切分?在我們的系統(SNS)中,用戶的UID貫穿系統,唯一自增長,根據這個字段分表,再好不過。
方法一:使用MD5哈希
做法是對UID進行md5加密,然后取前幾位(我們這里取前兩位),然后就可以將不同的UID哈希到不同的用戶表(user_xx)中了。
function getTable( $uid ){
$ext = substr ( md5($uid) ,0 ,2 );
return "user_".$ext;
}
通過這個技巧,我們可以將不同的UID分散到256中用戶表中,分別是user_00,user_01 ...... user_ff。因為UID是數字且遞增,根據md5的算法,可以將用戶數據幾乎很均勻的分別到不同的user表中。
但是這里有個問題是,如果我們的系統的用戶越來越多,勢必單張表的數據量越來越大,而且根據這種算法無法擴展表,這又會回到文章開頭出現的問題了。
方法二:使用移位
具體方法是:
public function getTable( $uid ) {
return "user_" . sprintf( "d", ($uid >> 20) );
}
這里,我們將uid向右移動20位,這樣我們就可以把大約前100萬的用戶數據放在第一個表user_0000,第二個100萬的用戶數據放在第二個表user_0001中,這樣一直下去,如果我們的用戶越來越多,直接添加用戶表就行了。由于我們保留的表后綴是四位,這里我們可以添加1萬張用戶表,即user_0000,user_0001 ...... user_9999。一萬張表,每張表100萬數據,我們可以存100億條用戶記錄。當然,如果你的用戶數據比這還多,也不要緊,你只要改變保留表后綴來增加可以擴展的表就行了,如如果有1000億條數據,每個表存100萬,那么你需要10萬張表,我們只要保留表后綴為6位即可。
上面的算法還可以寫的靈活點:
/**
* 根據UID分表算法
* @param int $uid //用戶ID
* @param int $bit //表后綴保留幾位
* @param int $seed //向右移動位數
*/
function getTable( $uid , $bit , $seed ){
return "user_" . sprintf( "%0{$bit}d" , ($uid >> $seed) );
}
小結
上面兩種方法,都要對我們當前系統的用戶數據量做出可能最大的預估,并且對數據庫單個表的最大承受量做出預估。
比如第二種方案,如果我們預估我們系統的用戶是100億,單張表的最優數據量是100萬,那么我們就需要將UID移動20來確保每個表是100萬的數據,保留用戶表(user_xxxx)四位來擴展1萬張表。
又如第一種方案,每張表100萬,md5后取前兩位,就只能有256張表了,系統總數據庫就是:256*100萬;如果你系統的總數據量的比這還多,那你實現肯定要MD5取前三位或者四位甚至更多位了。
兩種方法都是將數據水平切分到不同的表中,相對第一種方法,第二種方法更具擴展性。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。如果你想了解更多相關內容請查看下面相關鏈接
您可能感興趣的文章:- 詳解數據庫_MySQL: mysql函數
- MySQL數據庫中CAST與CONVERT函數實現類型轉換的講解
- mysql 8.0.15 安裝圖文教程及數據庫基礎
- SQL SERVER 數據庫備份代碼實例
- PostgreSQL數據庫中窗口函數的語法與使用
- 如何合理使用數據庫冗余字段的方法
- Mysql主從數據庫(Master/Slave)同步配置與常見錯誤
- PHP單例模式數據庫連接類與頁面靜態化實現方法
- MySQL數據庫大小寫敏感的問題
- 數據庫語言分類DDL、DCL、DML詳解