接上文。
Cache Money真正牛X的地方是在Vector Cache。在生產環境中,它不僅相對Object Cache命中率較更高,帶來的效能飛躍更是可觀。
在MoSonic的效能測試中,得到了有10倍的效能提高。
Vector Cache效能恐怖,但它對錶結構,查詢類型,有相當的嚴格的要求;列舉如下:
- 表必須以自增數字(int / long)id為主鍵
- 查詢的where中必須是 = 等於條件,如where user_id=1
- 多個where條件的話,相互關係必須是And,如where user_id=1 and id_deleted=0
- 查詢結果僅能是資料id,如 select id from users where ... 不可以是 select user_name from users where ...
- 也可以是 select count(*) from users where ...
- 查詢結果支援分頁
- 查詢結果必須以id排倒序,也就是order by id desc
只有完全符合上面五個條件,Vector Cache才可以生效;幸運的是,在web 2.0網站中,這類結構/查詢正好是最常見的。
以部落格為例,部落格文章列表顯示,分類文章數量,評論顯示等等,基本都符合上述的查詢。
比方說,要獲得等級為1的使用者時,需要使用下面的兩個查詢:
- select id from users where level=1
- select * from users where id in (....)
兩個查詢cache money都可以完全緩衝,如果直接使用:
- select * from users where level=1
的話,cache money則會完全失效。
對於兩種風格的查詢孰優孰劣,可以參考JavaEye老大Robin之前寫的:為什麼ORM效能比iBATIS好?
=============
因為要求了查詢結果必須是id,並且排倒序,Vector Cache實際上是可以做到即時自動更新,而不是自動到期。
考慮這樣的調用:
- select count(id) from photos where album_id=1 order by id desc limit 1, 100
- select id from photos where album_id=1 order by id desc limit 1, 100
- insert into photos (album_id)values(1)
- select count(id) from photos where album_id=1 order by id desc limit 1, 100
- select id from photos where album_id=1 order by id desc limit 1, 100
顯示列表,插入資料,再次顯示列表;這是相當典型調用。
第1/2步查詢會有緩衝(即便是沒有緩衝,查詢之後,緩衝也會自動被產生,也就是所謂的直讀)。
第3步插入資料時,獲得資料庫自增的ID後,可以直接將此id追加到第1/2步查詢快取結果中。
第4/5步查詢直接命中第3步寫資料時更新的緩衝;完全無需查詢資料庫。
在查詢、應用情境符合的理想情況下,有了Vector Cache,資料庫讀可以變成恐怖的0讀取。
資料庫僅需要承擔寫壓力,100%的讀都有Memcache的自動緩衝。
這才是Cache Money的Vector Cache帶來讀效能飛躍的原因。
所有的資料庫查詢都變成了memcache get;memcache單機時在讀能力,並發負荷能力上都要比傳統關係型資料庫高一個數量級;而且其shared nothing的架構,又可以水平擴張。
在高並發,多機緩衝的情況下,可以預料Cache Money帶來的讀效能提高遠不止10倍。
==============
Twitter的工程師對Cache Money的實現相當巧妙,他們針對一個限制多多的情境做到了100%的讀緩衝;而這個“限制多多”又恰恰是web 2.0網站中的最典型情境。
我在MoSonic中實現Vector Cache時,完全照搬了Cache Money的實現演算法;就是C#的代碼量比ruby膨脹了幾倍。
下篇會繼續講MoSonic對FriendFeed分散式資料庫設計的引用。