驚現支撐1億pv/天的超級資料庫解決方案

來源:互聯網
上載者:User

捨得網支撐1億pv/天構架,開源了
說是支援1億pv/天,也許有點誇張,也是為了吸引您能點進來,如果您能認真看完相信也不會讓您失望,當然,肯定有很多“高手”會對此會嗤之以鼻,沒關係,有很多眼高手低的人總喜歡評論別人卻從不會看清自己。

如果大家真想支援我、支援中國人開源項目,請把該文貼到自己的部落格中或者收藏本文,記得包含文檔的!!!!!!!謝謝。

我說的系統主要是構建在hibernate之上的高效資料庫緩衝系統,其中包含了分布式解決方案,該系統已經應用在捨得網上了,沒有發現大問題,本人也相信該系統已經足夠強大,應付數百萬IP/天的應用都不是問題,我這麼說肯定有人會對此表示懷疑,其實系統到底能撐多少IP/天不在於系統本身而是在於使用該系統的人。

代碼看上去很簡單,其實卻是兩年經驗的總結,整過過程也遇到了很多痛點,最後一一解決了,所以也請各位珍惜他人的勞動成果。本系統非常簡潔易用,主程式BaseManager.java不到1000行代碼,用“精悍”來形容絕對不為過,1000行代碼卻包含了資料庫物件的緩衝、列表和長度的緩衝、按欄位散列緩衝、update延時更新、自動清除列表緩衝等功能,用它來實現像論壇、部落格、校友錄、交友社區等絕大部分應用網站都足夠了。

我在理想狀態下做了壓力測試,在沒有資料庫操作的jsp頁面(捨得網新首頁)裡可以完成2000多requests每秒(正常情況可能有1/1000的request有資料庫查詢,其餘999/1000都是直接從緩衝裡讀取),物品詳情頁每秒可完成3000多 requests,純靜態html頁面也只能完成7000多requests/秒,我對首頁進行了三個小時的壓力測試,完成了24850800個 requests,java一點事都沒有,記憶體沒有上漲。按照2000個requests/秒算,一天按15小時計算,那麼每天能完成 3600*15*2000=1億零8百萬requests,當然這是理想狀態,實際狀態就算打一折,還能完成1000萬pv/天,要知道,這隻是一個普通 1萬3千塊錢買的伺服器,記憶體4G,CPU2個,LinuxAS4系統,apache2.0.63/resin2.1.17/jdk6.0的環境。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。現在進入正題。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

為什麼要用緩衝?如果問這個問題說明你還是新手,資料庫輸送量畢竟有限,每秒讀寫5000次了不起了,如果不用緩衝,假設一個頁面有100個資料庫操作,50個使用者並發資料庫就歇菜,這樣最多能支撐的pv也就50*3600*15=270萬,而且資料庫伺服器累得半死,搞不好什麼時候就累死了。我的這套緩衝系統比單獨用memcached做緩衝還要強大,相當於在memcached上再做了兩級緩衝,大家都知道memcached很強了,但是輸送量還是有限,每秒20000次get和put當遇到超大規模的應用時還是會歇菜,本地HashMap每秒可執行上百萬次put和get,在這上面損耗的效能幾乎可以忽略不記了。溫馨提示:能不用分布式的時候就不要用分布式,非用分布式的時候再考慮用memcached,我的緩衝系統在這方面都已經實現了,改個配置就可以了,有興趣的可以仔細測試測試!

一般資料庫緩衝在我看來包含四種。第一種:單個對象的緩衝(一個對象就是資料庫一行記錄),對於單個對象的緩衝,用HashMap就可以了,稍微複雜一點用LRU演算法封裝一個HashMap,再複雜一點的分布式用memcached即可,沒什麼太難的;第二種:列表緩衝,就像論壇裡文章的列表;第三種:長度的緩衝,比如一個論壇板塊裡有多少個文章,這樣才方便實現分頁。第四種:複雜一點的 group,sum,count查詢,比如一個論壇裡按點擊數排名的最HOT的貼文清單。第一種比較好實現,後面三種比較困難,似乎沒有通用的解決辦法,我暫時以列表緩衝(第二種)為例分析。

mysql和hibernate的底層在做通用的列表緩衝時都是根據查詢條件把列表結果緩衝起來,但是只要該表的記錄有任何變化(增加/刪除/修改),列表緩衝要全部清除,這樣只要一個表的記錄經常變化(通常情況都會這樣),列表緩衝幾乎失效,命中率太低了。

本人想了一個辦法改善了列表緩衝,當表的記錄有改變時,遍曆所有列表緩衝,只有那些被影響到的列表緩衝才會被刪除,而不是直接清除所有列表緩衝,比如在一個論壇版(id=1)裡增加了一個文章,那麼只要清除id=1這個版對應的列表緩衝就可以了,版id=2就不用清除了。這樣處理有個好處,可以緩衝各種查詢條件(如等於、大於、不等於、小於)的列表緩衝,但也有個潛在的效能問題,由於需要遍曆,CPU符合比較大,如果列表緩衝最大長度設定成10000,兩個 4核的CPU每秒也只能遍曆完300多次,這樣如果每秒有超過300個insert/update/delete,系統就吃不消了。

在前面兩種解決辦法都不完美的情況下,本人和同事經過幾個星期的思索,總算得出了根據表的某幾個欄位做散列的緩衝辦法,這種辦法無需大規模遍曆,所以CPU 符合非常小,由於這種列表緩衝按照欄位做了散列,所以命中率極高。思路如下:每個表有3個緩衝Map(key=value索引值對),第一個Map是對象緩衝A,在A中,key是資料庫的id,Value是資料庫物件(也就是一行資料);第二個Map是通用列表緩衝B,B的最大長度一般1000左右,在B 中,key是查詢條件拼出來的String(如start=0,length=15#active=0#state=0),Value是該條件查詢下的所有id組成的List;第三個Map是散列緩衝C,在C中,key是散列的欄位(如根據userId散列的話,其中某個key就是userId=109這樣的String)組成的String,value是一個和B類似的HashMap。其中只有B這個Map是需要遍曆的,不知道說明白了沒有,看完小面這個例子應該就明白了,就用論壇的回複表作說明,假設回複表T中假設有欄位id,topicId,postUserId等欄位(topicId就是文章的 id,postUserId是發行者id)。

第一種情況,也是最常用的情況,就是擷取一個文章對應的回複,sql語句應該是象
select id from T where topicId=2008 order by createTime desc limit 0,5
select id from T where topicId=2008 order by createTime desc limit 5,5
select id from T where topicId=2008 order by createTime desc limit 10,5
的樣子,那麼這種列表很顯然用topicId做散列是最好的,把上面三個列表緩衝(可以是N個)都散列到key是topicId=2008這一個Map中,當id是2008的文章有新的回複時,系統自動把key是topicId=2008的散列Map清除即可。由於這種散列不需要遍曆,因此可以設定成很大,例如100000,這樣10萬個文章對應的所有回複列表都可以緩衝起來,當有一個文章有新的回複時,其餘99999個文章對應的回複列表都不會動,緩衝的命中率極高。

第二種情況,就是後台需要顯示最新的回複,sql語句應該是象
select id from T order by createTime desc limit 0,50
的樣子,這種情況不需要散列,因為後台不可能有太多人訪問,常用列表也不會太多,所以直接放到通用列表緩衝B中即可。

第三種情況,擷取一個使用者的回複,sql語句象
select id from T where userId=2046 order by createTime desc limit 0,15
select id from T where userId=2046 order by createTime desc limit 15,15
select id from T where userId=2046 order by createTime desc limit 30,15
的樣子,那麼這種列表和第一種情況類似,用userId做散列即可。

第四種情況,擷取一個使用者對某個文章的回複,sql語句象
select id from T where topicId=2008 and userId=2046 order by createTime desc limit 0,15
select id from T where topicId=2008 and userId=2046 order by createTime desc limit 15,15
的樣子,這種情況比較少見,一般以topicId=2008為準,也放到key是topicId=2008這個散列Map裡即可。

那麼最後的緩衝結構應該是下面這個樣子:

緩衝A是:
Key鍵(long型) Value值(類型T)
11 Id=11的T對象
22 Id=22的T對象
133 Id=133的T對象
……

列表緩衝B是:
Key鍵(String型) Value值(ArrayList型)
from T order by createTime desc limit 0,50 ArrayList,對應取出來的所有id
from T order by createTime desc limit 50,50 ArrayList,對應取出來的所有id
from T order by createTime desc limit 100,50 ArrayList,對應取出來的所有id
……

散列緩衝C是:
Key鍵(String型) Value值(HashMap)
userId=2046 Key鍵(String型) Value值(ArrayList)
userId=2046#0,5 id組成的List
userId=2046#5,5 id組成的List
userId=2046#15,5 id組成的List
……

userId=2047 Key鍵(String型) Value值(ArrayList)
userId=2047#0,5 id組成的List
userId=2047#5,5 id組成的List
userId=2047#15,5 id組成的List
……

userId=2048 Key鍵(String型) Value值(ArrayList)
userId=2048#topicId=2008#0,5 id組成的List
userId=2048#5,5 id組成的List
userId=2048#15,5 id組成的List
……

……

總結:這種緩衝思路可以儲存大規模的列表,快取命中率極高,因此可以承受超大規模的應用,但是需要技術人員根據自身商務邏輯來配置需要做散列的欄位,一般用一個表的索引鍵做散列(注意順序,最散的欄位放前面),假設以userId為例,可以儲存N個使用者的M種列表,如果某個使用者的相關資料發生變化,其餘N- 1個使用者的列表緩衝紋絲不動。以上說明的都是如何緩衝列表,緩衝長度和緩衝列表思路完全一樣,如緩衝象select count(*) from T where topicId=2008這樣的長度,也是放到topicId=2008這個散列Map中。如果再配合好使用mysql的記憶體表和memcached,加上F5裝置做分布式負載平衡,該系統對付像1000萬IP/天這種規模級的應用都足夠了,除搜尋引擎外一般的應用網站到不了這種規模。

再次申明:系統到底是不是強大不在系統本身而在於使用該系統的人!!!

這個緩衝系統是我和同事幾年經驗的總結,看似簡單,其實也沒那麼簡單,把它作為開源有下面幾個目的:第一,真的希望有很多人能用它;第二:希望更多的人能夠完善和改進它;第三:希望大家能聚到一起為通用高效資料庫緩衝構架作出貢獻,畢竟,資料庫操作是各種應用最常用的操作,也是最容易產生效能瓶頸的地方。

Zip包中包含了配置方法和測試用的jsp,只要把它配置成一個web應用就可以快速調試並看到緩衝的力量了,文檔和是http://shedewang.com/akaladocs/api/com/akala/dbcache/core/BaseManager.html。

配置說明檔案在docs/開始配置.txt裡有說明。

最後囉嗦一句,如果大家真想支援我、支援中國人開源項目,請把該文貼到自己的部落格中或者收藏本文,記得包含文檔的!!!!!!!謝謝。thank you and Good luck。

QQ群:24561583

複製過來格式有點亂了,還是自己下載一個下來看看吧,裡面有個word文檔,寫得比較清晰。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.