1 頁 (共 1 頁)

LOW_PRIORITY

發表於 : 2012-03-28 14:50:10
yehlu
http://ithelp.ithome.com.tw/question/10 ... g=nl.daily

youtube每個影片都有顯示多少人看過,有的到好幾千萬的數字都有
很好奇,到底是怎麼做的
假設環境是php+MySQL

就我知道的方法有以下的方式:

方法一

資料庫使用innodb,而影片table有一個Count的欄位,資料型態使用unsigned int
每次當使用者load一次這個頁面時,就做
update 影片 set Count=Count+1 where VideoIndex='xxx';
使用innodb可以有row lock的功能,而不會用到table lock

方法二
把Count存到一個.txt的檔案
一樣每次讀取影片時,去抓取txt然後+1
(抓取寫入有包含lock的功能設計)

方法三
每次load影片時,就insert一筆資料到 (VideoLogTable)
裡面基本包含[index, VideoID, UserIP]等資訊
然後當要算出某一個Video的點選次數時
就使用
select count(*) as Number from VideoLogTable where VideoID='xxx';

方法四
去計算http_access_log
計算某一個page被access幾次


上面這幾中方式裡面,目前我選擇「方法一」,但是不知道像youtube那種
大量存取的網站,是怎麼做到這個「計數器」的功能的?

方法一有個好處,就是不會有一大堆的紀錄
不過壞處是,全部人都要針對同一筆資料去做update

方法二感覺還滿差的

方法三的好處是,不會有wait的狀況,因為全部都是做insert
但是壞處是,假設有幾百萬人瀏覽過某一篇文章,那不就會有一堆記錄
而且如果全部的資料都只在一個表單,那應該很容易就暴表
如果針對不同影片就擁有不同表單,那資料庫的table也會暴表
也不知道使用count(*)時,會不會因為資料筆樹太多而影響速度

方法四,看起來不用去對資料庫作操作會減少資料庫的負擔
但是access_log的檔案也會因為太大而影響效率,而且單檔也會有4GB的限制
到時候也是會有一堆access_log

想問一下,大型網站是用什麼樣的方式解決這個小問題的呢?


大型網站,基本上就是用你的第一種方法。
因為資料庫有 access queue,可以同時接受多方存取,而且會依序執行,不會 block 住,也不會有 race condition 問題。
方法三也差不多,也是藉資料庫的能力去解決 concurrent access 問題,不過大型網站通常是為了記錄每一次存取的來源,才會記這些 log,如果是計數,不太可能用算 Log 的方式,因為實在太多。
方法二不用考慮了。沒有處理 concurrent access 問題,只用 lock 的話,若同時 100 個人存取,只會記 1 次,其它 99 個全部 drop。或者其它 99 個得 block 住,不管哪一種都不優。我用過,結果完全失控。
方法四也不必考慮。你不可能留著所有的 access log 來計算。


我就喜歡回答像 sunz5010 這樣會自己思考解決之道的邦友。自己思考過才學得到東西。

你的想法很好。不過你的解法,其實資料庫都幫你思考過了。資料庫的存在,就是想幫 programmer 解決這些枝微末節的地方,讓 programmer 真的就把這個計數功能當做是 $count++ 一樣來看待就好了。

資料庫設計者一定思考過大量 client 去存取同一筆資料的問題,這是它的專業所在,所以它會處理這種問題。你做了一個 TempOperateTable 來定時算數量,對資料庫不見得是減輕負擔的工作,它得多管理一個 TABLE,而且你還把原本的設計複雜化了。

我的建議,還是第一種就好。就是單純的 update 影片 set Count=Count+1。
或者你可以利用 MySQL 的語法,加上 LOW_PRIORITY 關鍵字,變成:

代碼: 選擇全部

update LOW_PRIORITY 影片 set Count=Count+1
讓 select 先取,由資料庫自己找空檔去做 update 的工作。你完全不必花腦筋在替它擔心它會不會太忙。