Spring Data Redis 讓 NoSQL 快如閃電 (1)

【編者按】本文作者為 Xinyu Liu,詳細(xì)介紹了 Redis 的特性聂喇,并輔之以豐富的用例辖源。在本文的第一部分,將重點概述 Redis 的方方面面授帕。文章系國內(nèi) ITOM管理平臺 OneAPM編譯呈現(xiàn)同木。
  建立在 Java企業(yè)版之上的多層體系結(jié)構(gòu)是強大的服務(wù)器端編程解決方案浮梢。作為一名從業(yè)多年的 Java 企業(yè)版開發(fā)人員跛十,我最滿意的就是三層企業(yè)開發(fā)法:最下方是 JPA/Hibernate 持久層,中間是 Spring 或 EJB 應(yīng)用層秕硝,最上方則是 web 層芥映。對于較為復(fù)雜的用例,我用 BPM(業(yè)務(wù)流程管理)、一個類似于 Drools的規(guī)則引擎和一個集成框架(例如 Camel)集成了一個工作流驅(qū)動的解決方案奈偏。
  但是坞嘀,筆者最近接到一個任務(wù),要設(shè)計一個擁有亞秒級響應(yīng)延遲并能支持成千上萬名并發(fā)用戶的系統(tǒng)惊来。我立即發(fā)現(xiàn)了自己常用的 Java 企業(yè)版棧區(qū)的局限性丽涩。基于關(guān)系數(shù)據(jù)庫管理系統(tǒng)的傳統(tǒng)型 web 應(yīng)用程序裁蚁,包括在 Hibernate/JPA 之上構(gòu)建的應(yīng)用程序矢渊,都有二階延遲,擴展效果不佳枉证。傳統(tǒng)的 Java 企業(yè)版持久性體系結(jié)構(gòu)無法滿足我當(dāng)時設(shè)計的系統(tǒng)的性能和處理能力要求矮男。然后我轉(zhuǎn)而嘗試 NoSQL,最后發(fā)現(xiàn)了 Redis室谚。
  作為一種內(nèi)存鍵值數(shù)據(jù)庫毡鉴,Redis 打破了數(shù)據(jù)庫的傳統(tǒng)定義(將數(shù)據(jù)保存在硬盤上)。反之秒赤,使用 Redis 時可結(jié)合持久性的 NoSQL 數(shù)據(jù)庫猪瞬,比如 MongoDB、HBase倒脓、Cassandra或 DynamoDB撑螺。Redis 以遠(yuǎn)程緩存服務(wù)器見長,對易揮發(fā)數(shù)據(jù)來說是極快型數(shù)據(jù)庫崎弃。
  在本文中甘晤,筆者會介紹一些有關(guān) Redis 的簡單用例和進(jìn)階用例以及性能調(diào)優(yōu)情況。當(dāng)然饲做,我還會做個簡單概述线婚,但我相信各位基本都了解 NoSQL 及其各種解決方案

Spring Data Redis   
Redis 幾乎擁有針對所有編程語言的各種客戶端庫盆均,其中就包括Java塞弊。Jedis可能是最受歡迎的 Java 客戶端庫了。本文中的示例都基于 Spring Data Redis泪姨,我把它作為一個較高層次的包裝程序 API游沿。Spring Data Redis 不僅配置方便,而且擁有各種友好的 API和實用插件肮砾。

Redis 概述

和大多數(shù) NoSQL 數(shù)據(jù)庫一樣诀黍,Redis 舍棄了表格、行列的關(guān)系概念仗处。而事實上眯勾,Redis 是一種鍵值數(shù)據(jù)庫枣宫,利用獨特的字符串鍵值來存儲和檢索每條記錄。Redis 支持把以下內(nèi)置數(shù)據(jù)結(jié)構(gòu)作為所有記錄的值:

  • STRING 保有單個字符串值吃环。
  • LIST也颤、SET 和 HASH 從語義上來說與 Java 中的相同數(shù)據(jù)結(jié)構(gòu)相一致。
  • ZSET 是由浮點分?jǐn)?shù)安排的字符串列表郁轻,類似于 Java 中的 PriorityQueue翅娶。

不同于關(guān)系數(shù)據(jù)庫管理系統(tǒng)中的表,Redis 數(shù)據(jù)結(jié)構(gòu)是即時實例化的好唯。如果用戶查詢的內(nèi)容不存在于 Redis 中故觅,系統(tǒng)只會返回空值。雖然 Redis 不允許嵌套結(jié)構(gòu)渠啊,但用戶可以執(zhí)行自定義的 Java 或 JSON 串行器/解串器输吏,從而將 POJO 映射到字符串。通過這種方式替蛉,就可以把任意 Java bean 保存為 STRING贯溅,或者將其放置在 LIST、SET 中躲查,等等它浅。

性能和可擴展性

對于 Redis,人們注意到的第一個特點可能就是它的速度極快镣煮。根據(jù)記錄的大小和連接的數(shù)量姐霍,性能基準(zhǔn)會有所不同,但延遲通常為單數(shù)位毫秒典唇。在大多數(shù)用例中镊折,Redis 每秒最多可支持 50000 次請求。如果用戶使用較高端的硬件介衔,處理能力更可高達(dá)每秒 700000 次請求(但這一數(shù)值可能會被網(wǎng)卡帶寬扼制)恨胚。
  作為一種內(nèi)存數(shù)據(jù)庫,Redis 的存儲容量有限炎咖; AWS EC2 中的最大實例為 r3.8xlarge赃泡,內(nèi)存 244 GB。由于數(shù)據(jù)結(jié)構(gòu)的索引和性能都經(jīng)過優(yōu)化乘盼,Redis 消耗的內(nèi)存比所存儲的數(shù)據(jù)量大得多升熊。切分 Redis 有助于克服這一局限性。要把內(nèi)存數(shù)據(jù)備份到硬盤上绸栅,可以在預(yù)定作業(yè)中進(jìn)行時間點轉(zhuǎn)儲级野,也可以根據(jù)需要運行dump 命令。

用 Spring 進(jìn)行遠(yuǎn)程數(shù)據(jù)緩存

要想提升應(yīng)用程序服務(wù)器的性能阴幌,數(shù)據(jù)緩存可能是性價比最高的辦法了勺阐。利用 Spring 的緩存抽象注釋(@Cacheable、@CachePut矛双、@CacheEvict渊抽、@Caching 和 @CacheConfig)可以毫不費力地啟用數(shù)據(jù)緩存。在 Spring 配置下议忽,用戶還可以把 Ehcache懒闷、Memcached或 Redis 當(dāng)作基本緩存服務(wù)器。
  Encache 通常被配置成本地緩存層栈幸,具有嵌套結(jié)構(gòu)愤估,在應(yīng)用的 JVM 上運行。 Memcached 和 Redis 都能作為獨立的緩存服務(wù)器運行速址。要想把 Redis 緩存集成到基于 Spring 的應(yīng)用中玩焰,需要使用 Spring Data Redis的 RedisTemplate 和 RedisCacheManager。
  在 Redis 中訪問已緩存的對象芍锚,耗時通常不到數(shù)毫秒昔园,和關(guān)系數(shù)據(jù)庫查詢相比,這大幅提升了應(yīng)用程序的性能并炮。

延遲和收益
  亞馬遜公司在很大程度上依賴緩存服務(wù)器來最大程度地減少其零售網(wǎng)站的延遲默刚,該公司甚至曾經(jīng)發(fā)布過一份案例分析,其中記錄了延遲和收益之間的關(guān)系逃魄。

本地緩存與遠(yuǎn)程緩存

在沒有網(wǎng)絡(luò)開銷的系統(tǒng)中荤西,本地緩存快于遠(yuǎn)程緩存。本地緩存的缺點是伍俘,同一個對象的多個拷貝在服務(wù)器集群中的各個不同節(jié)點之中會同步得更快邪锌。正因如此,本地緩存僅適用于靜態(tài)數(shù)據(jù)癌瘾,例如可容忍短期滯后和不一致現(xiàn)象的系統(tǒng)級設(shè)置秃流。如果為易揮發(fā)的業(yè)務(wù)數(shù)據(jù)(例如用戶數(shù)據(jù)和交易數(shù)據(jù))使用本地緩存,很有可能會以運行應(yīng)用程序服務(wù)器的單個實例而告終柳弄。
  遠(yuǎn)程緩存服務(wù)器就沒有這一局限性舶胀。在同一個鍵的情況下,可保證緩存服務(wù)器上的對象只有一個拷貝碧注。只要用戶讓緩存中的對象及其數(shù)據(jù)庫值彼此保持同步嚣伐,就無需處理過期數(shù)據(jù)。
  列表 1 給出了一個 Spring 數(shù)據(jù)緩存的示例萍丐。
  列表 1:在基于 Spring 的應(yīng)用中啟用緩存
 
@Cacheable(value="User_CACHE_REPOSITORY", key = "#id")
public User get(Long id) {
return em.find(User.class, id);
}
@Caching(put = {@CachePut(value="USER_CACHE_REPOSITORY", key = "#user.getId()")})
public User update(User user) {
em.merge(user);
return user;
}
@Caching(evict = {@CacheEvict(value="USER_CACHE_REPOSITORY", key = "#user.getId()")}) public void delete(User user) {
em.remove(user);
}
@Caching(evict = {@CacheEvict(value="USER_CACHE_REPOSITORY", key = "#user.getId()")}) public void evictCache(User user) {
}
  這里的讀取操作被 Spring 的 @Cacheable 注釋圍繞轩端,作為 AOP 幕僚而執(zhí)行。Spring 中的存活時間設(shè)置也規(guī)定了這些對象可在緩存中停留的時間逝变。調(diào)用 get() 方法后基茵,Spring 就會試著先從遠(yuǎn)程緩存讀取和返回對象奋构。如果未找到對象,Spring 會執(zhí)行方法主體拱层,然后將數(shù)據(jù)庫結(jié)果放在遠(yuǎn)程緩存中弥臼,之后再返回結(jié)果。
  但如果另一個過程(例如另一個服務(wù)器節(jié)點)甚至同一個 JVM 中的另一個線程在數(shù)據(jù)庫中更新了同一個對象根灯,又會怎樣呢径缅?如果只運用 @Cacheable 注釋,你可能會從遠(yuǎn)程緩存服務(wù)器收到過期拷貝烙肺。
  為了防止發(fā)生這種情況纳猪,可以給所有數(shù)據(jù)庫更新操作添加一個 @CachePut 注釋。每次調(diào)用這些方法時桃笙,返回值就會替換掉遠(yuǎn)程緩存中原先的對象氏堤。在數(shù)據(jù)庫讀取和寫入上都更新緩存,可以讓緩存服務(wù)器和后臺數(shù)據(jù)之間的記錄保持同步搏明。

容錯

聽起來簡直完美丽猬,對吧?事實當(dāng)然不是這樣熏瞄。利用列表 1 中的配置脚祟,負(fù)載較低時可能不會遇到任何問題,但隨著服務(wù)器集群上的負(fù)載逐漸增加强饮,遠(yuǎn)程緩存上就會出現(xiàn)過期數(shù)據(jù)由桌。要做好準(zhǔn)備應(yīng)對服務(wù)器節(jié)點爭用甚至更糟的情況。即使成功寫入數(shù)據(jù)庫邮丰,最后也可能會因為網(wǎng)絡(luò)故障而使得緩存服務(wù)器 PUT 以失敗告終行您。另外,NoSQL 通常不支持在關(guān)系數(shù)據(jù)庫中存在完整事務(wù)語義剪廉,因為這會導(dǎo)致部分提交娃循。為了讓代碼容錯,可以考慮給數(shù)據(jù)模型增加版本號斗蒋,實現(xiàn)樂觀鎖捌斧。
  在收到 OptimisticLockingFailureException 或 CurrentModificationException(具體取決于持久性解決方案)時,可以調(diào)用帶有 @CacheEvict 注釋的方法泉沾,從緩存中清除過期拷貝捞蚂,然后重試同一個操作:
  列表 2:解決緩存中的過期對象
  try{
User user = userDao.get(id); // user fetched in cache server
userDao.update(user, oldname, newname);
}catch(ConcurrentModificationException ex) { // cached user object may be stale
userDao.evictCache(user);
user = userDao.get(id); // refresh user object
userDao.update(user, oldname, newname); // retry the same operation. Note it may still throw legitimate ConcurrentModificationException.}

結(jié)合 Elasticache 使用 Redis  
Amazon Elasticache 是一款內(nèi)存緩存服務(wù),可結(jié)合 Memcached 或Redis 作為緩存服務(wù)器使用跷究。雖然Elasticache不在本文介紹范圍內(nèi)姓迅,但筆者還是想給各位開發(fā)人員介紹一個結(jié)合 Redis 使用 Elasticache的技巧。對于大多數(shù) Redis 參數(shù),使用其默認(rèn)值并無大礙丁存,但 tcp-keepalive 和timeout的默認(rèn)Redis設(shè)置并不會移除已無效的客戶連接肩杈,最后還會耗盡緩存服務(wù)上的套接口。結(jié)合Elasticache使用Redis時解寝,務(wù)必每次都明確設(shè)置這兩個值扩然。

在本文的第二部分,將介紹 Redis 的6大用例编丘,敬請期待。
  本文系 OneAPM工程師編譯整理彤悔。OneAPM 能為您提供端到端的 Java 應(yīng)用性能解決方案嘉抓,我們支持所有常見的 Java 框架及應(yīng)用服務(wù)器,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸晕窑,定位異常根本原因抑片。分鐘級部署,即刻體驗杨赤,Java 監(jiān)控從來沒有如此簡單敞斋。想閱讀更多技術(shù)文章,請訪問 OneAPM 官方技術(shù)博客疾牲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末植捎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阳柔,更是在濱河造成了極大的恐慌焰枢,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舌剂,死亡現(xiàn)場離奇詭異济锄,居然都是意外死亡,警方通過查閱死者的電腦和手機霍转,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門荐绝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人避消,你說我怎么就攤上這事低滩。” “怎么了岩喷?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵委造,是天一觀的道長。 經(jīng)常有香客問我均驶,道長昏兆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮爬虱,結(jié)果婚禮上隶债,老公的妹妹穿的比我還像新娘。我一直安慰自己跑筝,他們只是感情好死讹,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著曲梗,像睡著了一般赞警。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虏两,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天愧旦,我揣著相機與錄音,去河邊找鬼定罢。 笑死笤虫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的祖凫。 我是一名探鬼主播琼蚯,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惠况!你這毒婦竟也來了遭庶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤稠屠,失蹤者是張志新(化名)和其女友劉穎罚拟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體完箩,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赐俗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了弊知。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阻逮。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖秩彤,靈堂內(nèi)的尸體忽然破棺而出叔扼,到底是詐尸還是另有隱情,我是刑警寧澤漫雷,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布瓜富,位于F島的核電站,受9級特大地震影響降盹,放射性物質(zhì)發(fā)生泄漏与柑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望价捧。 院中可真熱鬧丑念,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至莉掂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工植榕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掌测。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓内贮,卻偏偏與公主長得像产园,于是被迫代替她去往敵國和親汞斧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 【編者按】本文作者為 Xinyu Liu什燕,詳細(xì)介紹了 Redis 的特性粘勒,并輔之以豐富的用例。在本文的第一部分屎即,將...
    OneAPM_Official閱讀 898評論 1 11
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理庙睡,服務(wù)發(fā)現(xiàn),斷路器技俐,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • 6/19四十一天乘陪,周一,沒干什么雕擂,收拾好教室啡邑,休息會兒,做飯井赌,下午上課谤逼,又一天過去了。 不知不覺...
    八月微央閱讀 121評論 0 0
  • 所有的不甘與不舍 都將隨著時間慢慢遠(yuǎn)去 清楚地知道無法重頭來 結(jié)局是可預(yù)見的 卻為何仍要掙扎 掙扎在這躁動的不安中...
    sherly茜閱讀 196評論 0 0