在公司內部項目實現過程中團隊對SubSonic增加了分布式儲存,透明對象緩衝,透明查詢快取的支援;內部使用了兩三年,並且在持續改進中。
MoSonic支援海量資料存放區,在web 2.0常見情境中其透明緩衝層亦可帶來10倍以上的讀取效能提高。
這裡寫blog記述一下。
改進參考/使用了:
- FriendFeed Schemaless Database Design
- Twitter: Cache Money
- Facebook:Thrift
其中Cache Money影響較大,故內部命名為MoSonic,Money-SubSonic。
=============
SubSonic是.net中一個相當流行ORM庫,號稱零代碼。與其它ORM相比,SubSonic在易用性方面相當突出。
但這也不意味著SubSonic,或者說ActiveRecord風格的ORM僅能局限於中小網站的開發使用。
ActiveRecord實際上僅是Martin Fowler在《公司專屬應用程式架構模式》一書中的一個小章節提出的,兩三頁紙而已。
但在Web 2.0時代,隨著被Ruby On Rails,Django等流行架構採用,而大放異彩。
Twitter建站之初也是採用Ruby On Rails,使用的也是RoR內建的ActiveRecord風格ORM。
隨著Twitter的發展,資料庫效能這塊也必然成為瓶頸。而Twitter對此的回答是Cache-Money,一個透明的ActiveRecord緩衝層。
Cache-Money能夠透明的支援兩類緩衝,Object Cache 跟 Vector Cache。
(當然Cache-Money的作用不止這兩類緩衝。)
=============
都是ActiveRecord,上層API風格一致,Twitter可以在RoR的ORM中做的實現,也一定可以在SubSonic上用c#做實現。
Object Cache比較好理解,它僅僅是基於對象主金鑰快取對象內容。Object.FetchById(XXX) 這類函數中做下手腳,先查詢快取,緩衝不存在時,再去查詢資料庫。這也是所謂的Read-Through直讀緩衝。
而Object.Save()在資料庫儲存成功之後,也隨即更新Cache。這也是所謂的Write-Through直寫緩衝。
Object的直讀/寫緩衝實現非常簡單,對SubSonic的FetchById添加Object Cache的話,僅需要十來行代碼就可以使用單機記憶體做緩衝。
單機記憶體非常有限,Web 2.0網站一般使用memecached做分布式緩衝,解決單機緩衝記憶體有限的問題;這基本是標配了。
就.Net而言,找個靠譜的memcached client的要比實現SubSonic的Object Cache更加重要。
我使用的是BeIt出品的memcached用戶端;據說效能更好的有EnyimMemcached,但我沒有詳細測試過,不好評論。
使用了Memcached做緩衝的話,對象的序列化問題就變得非常突出了。
.Net內建的BinaryFormatter效能非常差,必須另尋序列化方案。
考察過諸多序列化方案後,我最終選擇的是Facebook開源出來的Thrift;它的設計完備,跨語言/平台支援能力非常好,效能不比Google開源出來的ProtoBuf差,也可以擴充為進程間RPC通訊方案。
為SubSonic添加對象Thrift序列化相對來說就比較麻煩些,但也不難,在SubSonic的代碼產生模板中修改即可。
Thrift本身實際上也有提供c#的對象序列化的代碼產生工具;但直接使用的話,意味著需要在Thrift對象/SubSonic對象間多增加一次轉換;修改代碼量雖然會少些,但不如直接修改SubSonic的代碼產生模板,直接將Thrift序列化的方法跟SubSonic對象做徹底的整合效率來得高。
使用Thrift做序列化跟使用.net預設的BinaryFormater效能差別是巨大的。公司兩台Web伺服器,在使用BinaryFormater時CPU近乎100%,但改用Thrift做序列化後立刻下降至20%。
(團隊倒不是在出現伺服器效能問題後才做了Thrift序列化;提前一年就做了;只是因故做了次實際的效能測試。)
==========
既然修改了SubSonic的代碼產生模板,我也順便將其Object new()的API幹掉了;強迫開發人員必須使用FetchById風格API獲得對象。
同時也增加了FetchByIds的新函數,支援同時獲得多個對象,對應select * from tables where id in (..., ...)的查詢,以及memcached multi_get的命令。
通過添加透明的Object cache在不增加額外的商務邏輯代碼情況下,已經可以獲得顯著的效能改善,但它還不是本質性的改進。
Cache Money真正的神器是其Vector Cache,實際上,Twitter團隊在開發Cache Money時,是優先考慮了Vector Cache的實現,然後再考慮Object Cache;因為他們認為Vector Cache會效能影響更大,事實也證明他們判斷正確。
下篇會繼續講Vector Cache的實現。