筆者工作中處理過包括視頻、圖片和業(yè)務元數(shù)據(jù)在內的cache處理,也遇到了一些比較常見的坑,做個筆記。希望能拋磚引玉。
cache的主要指標
- 命中率 命中率越高,回源率越少。cache的主要職責之一是減少回源,保護存儲層。實際項目中,要想法設法,比如加大內存、加長過期時間去維持高命中率。如果有些業(yè)務確實回源了仍然miss而無法cache,這時也是可以考慮cache miss_key的。
- 實時性 實時性體現(xiàn)在cache的及時更新或淘汰上??梢詤⒖嘉业牧硗庖黄恼?a href="http://www.lxweimin.com/p/c1121530e65b" target="_blank">基于mysql binlog解析的數(shù)據(jù)更新通道。
踩過的坑
- 隔離,重要的cache資源,或者量大的要進行物理隔離。降低耦合,減少互相影響。
- 做local cache,有時候可以解決熱點問題,而且走unix sock更快,尤其單次請求大量key的時候更靠譜。當然實時性看怎么保證,如果時間太短可能會影響命中率。
- db和cache很難做成事務,所以可能會存在各種各樣的不一致的坑。比如當需要異步更新cache數(shù)據(jù)時,如果是del cache的方式,須優(yōu)先更新數(shù)據(jù)源,再更新cache。否則先del可能會造成,此時讀請求cache miss后讀到臟數(shù)據(jù)而回寫cache。一般如果希望保證最終一致,可以丟給mq做異步更新保證時序和可靠性,或者走mysql binlog通道更新。
- 使用redis的INCR、SADD、HSET、zadd等操作前,須先expire判斷該key是否存在,否則可能會因為key過期導致錯誤的value。
- 類似計數(shù)相關的cache操作,盡量寫絕對值而不是增量寫。否則一次cache失敗很容易造成永久的臟數(shù)據(jù)。比如可以新增一個技術表,與具體記錄表做成事務寫,然后每次緩存更新直接讀計數(shù)更新。
- 對于非結構化數(shù)據(jù),比如大于100k的value,redis的性能是下降比較厲害的,優(yōu)先存memcache。再大一些的比如1M以上的,建議放其他的緩存系統(tǒng),比如nginx proxy_cache、couchbase、groupcache等。
- 對于命中率低的業(yè)務場景,要分析原因。有些是大量查詢不存在的數(shù)據(jù)(db里也不存在),這種可以做空緩存。有些是大量冷數(shù)據(jù),也叫長尾數(shù)據(jù),可以加大緩存和延長緩存周期,或者做預判和預加載。
- nginx proxy_cache 我們線上存儲服務維護確實遇到一些坑,比如某次發(fā)生cpu wa%特別高,nginx的日志相對比較少,所以發(fā)個strace跟蹤看看:
rename("/usr/local/nginx/proxy_temp/0/55/0943989550", "/mnt/storage00/ngx_cache/7/82/5c8b3d15f415b3e0007cd01ddc914827") = -1 EXDEV (Invalid cross-device link) open("/usr/local/nginx/proxy_temp/0/55/0943989550", O_RDONLY) = 46 fstat(46, {st_mode=S_IFREG|0600, st_size=2176, ...}) = 0 open("/mnt/storage00/ngx_cache/7/82/5c8b3d15f415b3e0007cd01ddc914827.0943989551", O_WRONLY|O_CREAT, 0600) = 55 read(46, "\3\0\0\0\0\0\0\0}\202}X\0\0\0\0>\10CW\0\0\0\0\375GtX\0\0\0\0"..., 2176) = 2176 write(55, "\3\0\0\0\0\0\0\0}\202}X\0\0\0\0>\10CW\0\0\0\0\375GtX\0\0\0\0"..., 2176) = 2176 close(55) = 0 close(46) = 0
明顯的報錯:Invalid cross-device link,proxy_cache在miss后回寫數(shù)據(jù)到磁盤,先寫到tmp文件,然后rename的,這樣可以避免并發(fā)讀寫同個文件。而這里當rename失敗后,open->read->write->close就走了好一大段彎路......終究原因是配置proxy_cache的時候忽視了proxy_temp_path,而可能就導致上面的不一致問題。還有一次也是cpu wa%特別高,當時是批量導數(shù)據(jù),上千萬張數(shù)據(jù)很多miss了。perf top看xfs的一些系統(tǒng)調用大量阻塞了cpu,導致機器負載陡增,程序性能也急劇下降!最后推測原因,由于讀寫海量小文件,可能觸發(fā)了ssd的一些頻繁GC等各種不熟悉、未預期的行為,也可能是踩到了xfs系統(tǒng)的瓶頸,導致實際上的io wa還是非常高。最終呢,我們是升級到了ATS。讀者有興趣可以了解下ats,是基于大文件存儲的架構,特別適合海量小文件緩存。
一些經驗
- cache節(jié)點的部署,盡量跨機器,多節(jié)點??梢员苊鈉ache節(jié)點掛掉而導致回源對db的沖擊。
- cache的監(jiān)控,除了日常的資源監(jiān)控,還要包括tps、命中率、會不會有過熱的key等。特別熱門的大key要做冗余存儲。