1. 程式人生 > >架構師之路--從業務角度談緩存的選型

架構師之路--從業務角度談緩存的選型

inno 基於 時間限制 更新 負載 聚集 穿透 同步 寫入

  想起來幾年前挺火的前島國國民女神學霸-小島方晴子。當時替她說話的人都很慘,導師被逼自殺。她收到的壓力侮辱不是常人可以想象的。但是她卻堅強的活著,去年還出了書。我去日本的時候,下了新幹線,前面有一群女學生,她們看到我了,立刻聚集成一團,一邊看我一邊說悄悄話。我才發現日本人穿的衣服基本就是黑,白,灰。他們也不穿羽絨服,女孩子大冬天都是光著腿。而我穿著黃綠色的羽絨服,確實像個怪胎。為什麽來之前沒人告訴我[大哭][大哭]。8年過去了,想起來還覺得尷尬。日本人是很愛背後說別人壞話的。所以我感謝我是個很普通的女孩子,而且生在中國。沒人閑的沒事去扒我之前做過的壞事。比如我很久前看不慣一個自己沒能力還勢利的混蛋,所以寫了個程序刷爆了他的郵箱。再比如我自己寫了個小程序循環註冊一個網站參加抽獎,得了好多小東西。

  但是女孩子天生就是很堅強的,女孩子為愛而活,其他的什麽都扛的下。寫《傲慢與偏見》的女作家簡.奧斯汀,大家看到她寫的書的女主角們大概都能想象到作者本人是個聰明,智慧,自己漂亮且有一個更漂亮的姐姐,又很幽默的女孩。但是她卻在自己心愛的男孩子傍了個富婆之後終生未嫁,高富帥向她求婚她沒同意。一生寄人籬下,與戀人死去不願做他人婦的姐姐相依為命,心中的痛苦又與誰人說。30多歲開始患有嚴重的憂郁癥,直到她得知自己心愛的男孩去世的消息,自己也郁郁而終。感恩自己運氣好,可以快快樂樂做個普通人。

  本文首發於靜兒1986的博客,原文地址是http://www.cnblogs.com/xiexj/p/6897806.html。

  我們部門並發量最大的接口服務前段時間發生了幾次業務端的流量猛增,扛不住的情況。瓶頸在緩存上。根本性的改造正在進行中。談一談這段時間由這個問題引發的思考。

  首先說之前的架構確實很老了,現在直接負責這個服務的男神哥哥也很年輕,有問題是正常的。緩存選用的是樂視統一的couchbase集群,是個memcached升級版,已經實現了持久化,本質是一個文檔型的數據庫,有人評價其性能要超過mangoDB。然後樂視網封裝了它,自己起名叫cbase,前面用moxi代理。實際上使用覺得其性能讓人擦汗。  

  接口服務將數據庫裏的全量視頻和專輯刷入緩存。緩存扛不住了都不會穿透DB。這裏我只想說:如果咱們要是發現數據庫可能要雪崩,做熔斷,做隔離都是可取的。但是完全不用,要它作甚[汗]. 媒資接口是一個多維度的查詢服務,緩存直接當DB用,而這個緩存的結構對數據的計算是很不利的。從數據庫裏取數據耗時一般也就是幾ms。從緩存中取數據量級並沒有減少,還會過量使用緩存造成cbase集群的高負載。而且mysql是有自己的緩存的,查詢一點兒都不慢,加上索引,線上已經有的讀寫分離,其他成熟的技術,性能也不差。業務復雜性大大增加,業務處理的CPU計算量大大增加,實際性的緩存的高速也微乎其微。

  話說到此,先比較一下mysql和memcached。

  之前普遍的理解是關系型數據庫自身龐大,處理過程非常耗時。但是隨著mysql的優化,解析sql語句的時間還好。一般耗時的就是讀,由於讀寫分離的技術,也還好。重要的是控制並發線程數,也就是連接數在100個以下。這個我自身在一個系統沒上線的時候用線上服務器實際試驗過。QPS可承受的壓力在1w多。

  來看看我們項目,接口服務前臺11臺服務器,平均每臺QPS2k多,峰值在3k多,合起來不會超過4w。寫的主庫是單節點,壓力很小。從庫是三個節點的集群。DBA說從庫可以承受QPS4w(我們用的是mariadb)。但是我們都直接訪問memcached了。memcached集群運維說用一個key去壓QPS可達到2.5w。實際上壓測value大小在5k的,也就幾k[狂汗],而我們項目中超過1k的占絕大多數。看文章說mysql5.7中使用InnoDB Memcached插件可實現QPS100w。阿裏雲開發了一個AliSQL,也是mysql官方版本的一個分支,說是性能還要好。

  所以,要是我,寧願不用memcached緩存,也不能不用DB啊。所以一般大家的使用方法是memcached緩存計算結果,采用最近最少使用算法或者是最不經常使用算法等失效策略,盡量少的緩存。第一次去取數據的時候查詢DB,將結果緩存到memcached中。有數據更新或者刪除,就刪除memcached的相關記錄。經典用法有經典用法的設計理念。

 我們的cbase集群分配了500G內存,實際上只用到了80G。且不說在這種使用率的情況下的哈希分布,實際上memcache內存管理的原理是將內存分成大大小小的片段,

這種結構內存浪費本身就比較嚴重。如果我們的數據大數據比較多的話,這種內存的浪費就更明顯。另外,如果數據塊比較大,大數據比較多的時候,計算哈希地址發生碰撞的幾率會增加。碰撞的地址需要rehash,增加了計算時間。

  

  那將redis換成memcached會怎樣?

  Redis有一些高級功能,但是Redis是單線程,高級功能占據CPU, I/O操作會被阻塞,所以還是比較建議只作為一個k/v的緩存。舉個例子,Redis不是支持有序集合嘛,如果取有序集合的一定範圍的元素,它內部使用了skiplist,關於跳表的詳細描述請看我的另一篇博客<看Lucene源碼必須知道的基本規則和算法>。時間復雜度是log(n),還是需要計算的。而且由於這個單線程,Redis在處理100K以上1M以下的大數據的時候比memcached還是稍顯遜色的。這個1M以下是怎麽來的呢?memcached內存結構規定最大的value值只能達到1M了,而Redis可達到512M。

  Redis不僅僅支持簡單的k/v類型的數據,同事還提供list,set,zset,hash等數據結構的存儲。這一點確實很有用。

  Redis支持數據的備份,即master-slave模式的數據備份。不管是備份也好,集群間的數據同步也好,宕機後的aof恢復也好,現在主流的解決方法使用的都是操作日誌。實現原理和mysql采用binlog的方式是一樣的。在使用的時候要註意其延時狀況。

  Redis會在內存中長期存儲所有的key。但它采用數據回收機制,能夠將陳舊value從內存中刪除以提供新value所必需的緩存空間。舊的數據只是內存中被刪除,磁盤上還有。不會因為回收而影響命中。所以Redis沒有最大過期時間限制。Memcached最大過期時間是一個月,否則會寫入失敗。

  聽說Redis是支持身份驗證的,實際開發中沒用過這個功能。

  Redis的作者和我是一個風格的,什麽都不想用現成的。去年夏天我自己剪了一次頭發,剪得比較成功。後來又剪了一次,慘不忍睹,但是為了紀念這次失敗,好幾個月沒換發型。Redis的作者管理IO用的不是memcached那樣現成的libevent,而是自己封裝了一個簡單的AeEvent事件處理框架。內存管理也是一樣,自己寫了一個zmalloc.h和zmalloc.c,將內存大小存入內存塊頭部。用zmalloc代替malloc,zcalloc代替calloc,zrealloc代替realloc,zfree代替free。做C開發的就是高大上,想怎麽分配內存就怎麽分配內存。

  

  綜上所述,Redis可能可以解決部分問題,但不是終極解決方案。因為接口服務是基於多個維度來查找的,更合適用只存儲和索引,不分詞的搜索引擎,可以有多少內存吃多少內存,速度優勢的原理和上面介紹的緩存都是一樣的。

  

  感謝這半年多,一直不斷有朋友來我這邊推薦工作的,挖人的,有推薦工作兼挖人的。正好有這個平臺,問問大家最近有想動一動的麽?在北京的童鞋有想去阿裏,螞蟻金服,美團點評,美團金融,貓眼電影,京東,樂視網我們部門也在招人,還有東直門的創業公司,燕郊的創業公司。總之,都可以找我,簡歷發我郵箱 [email protected]

  

  大家幫忙提提意見,是不是我的博客設計的不太好看?我一向審美觀不太好。是不是頁首橫幅上面的照片比較醜?好吧,這個我媽要承擔50%的責任。

架構師之路--從業務角度談緩存的選型