CRM系統|加入收藏|小博客
18560384436
>> 返回 您當前所在位置:首頁 >> 支持中心 >> 詳細內容

Netlog 的數據庫及 LAMP 架構

更新時間:2015-09-29 08:05:46點擊次數:4736次字號:T|T
Database [email protected] 詳細的描述了 Netlog 數據庫架構的演變過程,文章淺顯易懂,非常值得學習。本文數據、圖片均來自:Database Sharding at Netlog, with MySQL and PHP 數據 約4000萬活躍用戶 每月約5000萬獨立訪問 每月約50億 PV 和 每月 60億 online minutes 在數據庫 sharding 以前,高峰時期每秒3000次以上數據庫查詢 26種語言,30多個國家,5個最活躍的國家主要集中在歐洲 技術平臺 S

Database [email protected] 詳細的描述了 Netlog 數據庫架構的演變過程,文章淺顯易懂,非常值得學習。本文數據、圖片均來自:Database Sharding at Netlog, with MySQL and PHP

數據

約4000萬活躍用戶
每月約5000萬獨立訪問
每月約50億 PV 和 每月 60億 online minutes
在數據庫 sharding 以前,高峰時期每秒3000次以上數據庫查詢
26種語言,30多個國家,5個最活躍的國家主要集中在歐洲

技術平臺

Squid
Lighttpd, Apache
PHP
MySQL
Debian
Memcached
Sphinx
and many more.

Netlog 數據庫架構的歷史

netlog 從7年前的一個 hobby project 發展而來,數據庫從單臺服務器擴展到樹型多臺服務器。

DB Setup 1: Master (W)

讀寫都在一臺服務器上。
netlog-arch

DB Setup 2: Master (W) + Slaves (R)

讀寫分離,寫操作(INSERT/UPDATE/DELETE)在 Master 上執行,讀操作(SELECT)在1個或者多個 Slaves 上執行。這種方案適合讀比寫多的情況,比如讀寫比例4:1的情況,不適合寫比讀多的情況,比如讀寫比例1:4。Slaves 通過同步 Master 的 binlog 文件,并且執行其中所有的寫操作來同步數據庫。這樣會帶來數據同步的問題,可能會造成數據滯后,比如一個數據剛寫在 Master 上,Slaves 還來不及同步就被讀取,讀取的數據實際上是以前的數據,造成數據滯后。如果數據恰好很重要,比如用戶剛換密碼(密碼寫入 Master),然后用新密碼登錄(從 Slaves 讀取密碼),會造成密碼不一致,導致用戶短時間內登錄出錯。所以在這種需要讀取實時數據的時候最好從 Master 直接讀取,避免 Slaves 數據滯后現象發生。還好,需要讀取實時數據的時候不多,比如用戶更改了郵件地址,就沒必要馬上讀取,所以這種 Master-Slaves 架構在多數情況下還是有效的。

netlog-arch

DB Setup 3: Vertical Partitioning

DB Setup 2 的架構有個問題,就是能有效應付讀多寫少的情況,如果讀少寫多比如讀寫1:4就不是那么有效了,Slaves 不停的從 Master 那里同步寫操作,只是充當數據復制的機器而已, Slaves 沒有有效的參與到分擔負載的重任中來。所以為了能分擔寫操作的負載,這個時候需要做 vertical partitioning,把那些沒什么聯系、不需要 JOINS 操作的表分到不同的服務器上來減輕負擔。比如,把一個用戶的相關信息(photos, blogs, videos, polls, …)分散到不同的數據庫服務器上,然后給每個分散的數據庫里都配上1個帶有重復信息的表(userids, nicknames, …),這個時候你仍然可以訪問用戶的相關信息或者按照要求執行 JOINS 操作。下面的圖就是這種結構,Messages 和 Friends 配置成 Slaves,以便從 Top Maser 那里同步復制那些帶有有用信息的表(userids, nicknames, …)

netlog-arch

DB Setup 4: Vertical Partitioning / Replication Tree

把 DB Setup 2 和 DB Setup 3 結合起來就成了 DB Setup 4,只要負載過大就配一個或多個 Slaves 給服務器分擔負載,這就成了下面的樹形結構。

netlog-arch

DB Setup 5: Hitting Limits

按照 DB Setup 4 不斷深入到應用程序往下加 Slaves,到最后就會變得越來越困難,因為你不斷 partition 數據庫后你就會發現執行 JOIN 操作就會越來越困難,因為你分出了更多的表。有時候某個表可能會變得超級大以至于服務器處理不了,比如 Friendship 表(用來處理用戶關系的表)增長得太快,如果只放在1個 Master 上太危險了,如果 Master 服務器 down 了怎么辦?單個 Master 處理性能怎么樣?你可以給服務器 scale up,購買更強大更昂貴的服務器,更快的CPU,更大的內存,不過總歸不是個辦法,遲早還會遇到瓶頸(DB Setup 5)。所以需要更好的 scale out 策略。

netlog-arch

DB Setup 6:Sharding

DB Setup 4 的 vertical partitioning 已經幫了很大忙,但是網站繼續增長流量繼續增大怎么辦? Master-Master 行得通不?Cluster 呢?這些方法都是為高可靠性和高性能設計的,對于現在這種需要分載寫操作流量的情況不適合。Cache 呢?Cache 可以分擔讀操作流量,但是對于寫操作不會有太大幫助。如果不能 vertical partitioning 了,那能不能 horizontal partitioning 呢?把 DB Setup 4 那張增長迅速、包含1億條記錄的巨大的表(Friendship)水平切成10份,每份1千萬條記錄,放在10個不同的服務器上。這種技術又可以叫做 sharding,被廣泛用于大規模流量的網站上,如 Flickr, LiveJournal, Sun, Netlog 等。

netlog-arch

上圖把一個 photo 表 shard 到了10臺不同的數據庫服務器上。但是如何訪問這些不同服務器上的數據呢,怎么能知道某個數據放在哪個服務器上呢?用一個小算法(userid % 10),只要知道了用戶 userid,就可以知道用戶的 photo 放在哪個數據庫服務器上,然后連接那臺數據庫查詢。

舉一個簡單例子,創建一個巨大的 photo 表,其中包含 photoid, title, description, dateadded, authorid,url 列,其中 authorid 是另外一個 user 表(userid, name, …) 的 foreign key。我們將把這張巨大的 photo 表 shard 到2臺不同的數據庫服務器上,用戶 authorid 為奇數的就訪問數據庫1,authorid 為偶數就訪問數據庫2。

如果只有1臺數據庫服務器,不做 shard,訪問數據庫應該是這個樣子:

PHP:
$db = DB::getInstance();
$db->prepare(“SELECT title, url, description FROM photo WHERE userid = {userID}”);
$db->assignInt(‘userID’, $userID);
$db->execute();
$results = $db->getResults();

如果用2臺數據庫服務器來做 shard,我們需要傳一個參數給 DB 類,以便 DB 類知道連接到哪個數據庫,比如傳 $userID 給 DB::getInstance(),然后 getInstance() 計算 $userID % 2 后返回數據庫的連接信息:

PHP:
$db = DB::getInstance($userID);
$db->prepare(“SELECT title, url, description FROM photo WHERE userid = {userID}”);
$db->assignInt(‘userID’, $userID);
$db->execute();
$results = $db->getResults();

Netlog 提到了 shard 數據需要注意的兩點:
1、根據數據表的哪個列(如上面的 userid)來切分數據,使數據存到對應的數據庫;
2、用什么算法來判斷(如上面的 userid % 2)數據存到哪個服務器上。

如何根據數據表來切分數據主要依據程序來決定,Netblog選擇的是用戶 ID。以下有4種切分數據的方式可以參考:
1、Vertical Partitioning:如 DB Setup 3 那樣;
2、Range-based Partitioning:如前1000個用戶的信息存在服務器1,1001-2000存在服務器2,…;
3、Key or Hash based Partitioning:如上面的 userid % 2 的例子就是最簡單的 key/hash;
4、Directory based Partitioning:最靈活的方式,把 key 和數據庫服務器的對應關系保存下來,通過查找的方式找到對應的服務器。

DB Setup 7:Now

Netlog 在應用和數據庫之間加了一個中間層,從 PHP 角度看有兩部分組成,一部分是用來管理和維護,增加、刪除、編輯 shards,數據庫,lookup 系統;另一部分用來給數據庫層和緩存層提供可以訪問的 API。

netlog-arch

Shards live in databases, databases live on hosts

Netlog 用的是方式4:Directory based Partitioning,用一個單獨的 MySQL 表存放目錄 lookup 信息,用來把 $userID(shard keys)映射到對應的 $shardIDs 上,然后通過一些配置文件把 $shardIDs 映射到對應的數據庫服務器上(得到相關數據庫服務器的連接信息),以便后續操作在對應的數據庫上執行。

舉個例子來說明如何在 shards 上獲取 userid 為26的 photo 信息 :

Query: Give me the photos from author with id 26.

Where is user 26?
User 26 is on shard 5 (26 % 10 -1).
On shard 5; Give me all the $photoIDs ($itemIDs) of user 26.
That user’s $photoIDs are: array(10,12,30);
On shard 5; Give me all details about the items array(10,12,30) of user 26.
Those items are: array(array(‘title’ => “foo”, ‘description’ => “bar”), array(‘title’ => “milk”, ‘description’ => “cow”));

總結

“Don’t do it, if you don’t need to!” (37signals.com)
“Shard early and often!” (startuplessonslearned.blogspot.com)

作者在原文談到了這兩個看上去矛盾的觀點。能不 shard 就盡量不 shard,因為 shard 會帶來復雜性,數據庫變復雜,服務器變多,難以維護、監測等。過分 shard 數據后,關系型數據庫帶來的好處就沒了。盡量用簡單的辦法解決負載問題,比如:better hardware, more hardware, server tweaking and tuning, vertical partitioning, sql query optimization 等,如果這些能解決問題就不要shard。

另一方面,如果確定有 shard 的必要就要盡早開始設計,并且經常 shard,在設計數據庫的時候牢記 shard 的兩個關鍵點 sharding/partitioning key 和 sharding/partitioning scheme。

which property of the data (which column of the table) will I use to make the decisions on where the data should go?

And what will the algorithm be?

? 美洲野牛免费试玩 bb电子注册 广东快乐10分开奖助手 广东十一选五遗漏数据彩乐乐 三分彩实时开奖 江苏快三预测 今晚国足比赛直播视频 怎样炒股入门知识 占星术赚钱 麻将技巧口诀 黑龙江36选7开奖结果 黑龙省11选五走势图 彩票开奖结果江苏快3 精选24码期期中 棋牌游戏百人牛牛漏洞 全民麻将扑克 安徽11选5遗漏2017官网