《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 通信與網(wǎng)絡(luò) > 設(shè)計應(yīng)用 > Redis在高速緩存系統(tǒng)中的應(yīng)用
Redis在高速緩存系統(tǒng)中的應(yīng)用
來源:微型機(jī)與應(yīng)用2013年第12期
曾超宇1, 李金香2
(1. 中國電子信息產(chǎn)業(yè)集團(tuán)有限公司第六研究所, 北京100083; 2. 渤海大學(xué) 教育與體育學(xué)院
摘要: 隨著互聯(lián)網(wǎng)的發(fā)展,各種類型的應(yīng)用層出不窮,網(wǎng)站訪問量越來越大、內(nèi)容越來越多,用戶與系統(tǒng)的交互不斷增強(qiáng),訪問集中,造成數(shù)據(jù)庫負(fù)載過大,網(wǎng)站顯示延遲等影響。緩存技術(shù)就是解決此問題的一種方案,緩存技術(shù)以其簡單的設(shè)計、高效的存儲性能得到了越來越廣泛的應(yīng)用,而內(nèi)存數(shù)據(jù)庫則是一種優(yōu)秀的緩存解決方案。主要介紹Redis的特性以及在系統(tǒng)中的應(yīng)用。
Abstract:
Key words :

摘  要: 隨著互聯(lián)網(wǎng)的發(fā)展,各種類型的應(yīng)用層出不窮,網(wǎng)站訪問量越來越大、內(nèi)容越來越多,用戶與系統(tǒng)的交互不斷增強(qiáng),訪問集中,造成數(shù)據(jù)庫負(fù)載過大,網(wǎng)站顯示延遲等影響。緩存技術(shù)就是解決此問題的一種方案,緩存技術(shù)以其簡單的設(shè)計、高效的存儲性能得到了越來越廣泛的應(yīng)用,而內(nèi)存數(shù)據(jù)庫則是一種優(yōu)秀的緩存解決方案。主要介紹Redis的特性以及在系統(tǒng)中的應(yīng)用。
關(guān)鍵詞: Redis; 高速緩存; 內(nèi)存數(shù)據(jù)庫

     隨著 Internet 技術(shù)的快速發(fā)展,網(wǎng)絡(luò)接入速度不斷提高,各種類型的應(yīng)用層出不窮,網(wǎng)站訪問量越來越大、內(nèi)容越來越多,用戶交互不斷增強(qiáng),訪問集中,造成數(shù)據(jù)庫負(fù)載過大、網(wǎng)站顯示延遲等影響,而造成影響用戶體驗的主要瓶頸集中在數(shù)據(jù)庫服務(wù)器承載能力方面。要讓數(shù)據(jù)庫服務(wù)器快速響應(yīng)并能夠承受越來越大的負(fù)載, 緩存技術(shù)就是解決此問題的一種方案。Cache性能高效,設(shè)計簡單,可以對數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行緩存,降低數(shù)據(jù)庫負(fù)載;可以對Web頁面進(jìn)行緩存,提高Web頁面響應(yīng)速度;對復(fù)雜計算結(jié)果進(jìn)行緩存,可以減少網(wǎng)站服務(wù)器的傳輸負(fù)荷和計算速度和對用戶的響應(yīng)速度,有效地提高網(wǎng)站性能及可擴(kuò)展性。本文主要介紹開源內(nèi)存數(shù)據(jù)Redis的特性及其應(yīng)用。
1 Redis簡介
    Redis是一種 Key-Value類型的內(nèi)存數(shù)據(jù)庫產(chǎn)品,全名為遠(yuǎn)程字典服務(wù)(REmote DIctionary Server),與Memcache 相似,但Redis 支持更多的數(shù)據(jù)類型,包括字符串(String)、鏈表(List)、集合(set)、有序集合(Zset)、哈希(Hash)等。與Memcached一樣,為了保證效率,Redis數(shù)據(jù)都是緩存在內(nèi)存中,但與Memcache 只是用來做緩存相比,Redis適用的場景更多,并且可以直接用于數(shù)據(jù)存儲服務(wù)。
2 Redis特性
    雖然Redis與Memcaehed具有很多相似的特征,可替代Memcaehed做為緩存,但它又具有更多優(yōu)秀的特性,如支持多種數(shù)據(jù)結(jié)構(gòu)、支持簡單事務(wù)控制、支持持久化、支持主從復(fù)制、Virtual Memory功能等。
2.1 Redis數(shù)據(jù)類型
    Redis除了提供常規(guī)的數(shù)值或字符串外還提供4種數(shù)據(jù)類型:List、Set、Zset(Sorted Set)和Hset(Hash Set)。
    (1)String(字符串)
    Strings數(shù)據(jù)結(jié)構(gòu)是簡單的Key-Value類型,Value其實不僅是String,也可以是數(shù)字。使用Strings類型,可以完全實現(xiàn)目前 Memcached 的功能,并且效率更高;還可以享受Redis的定時持久化、操作日志及Replication等功能。
    (2)List(雙向鏈表)
    Lists就是鏈表,使用Lists結(jié)構(gòu)可以輕松地實現(xiàn)最新消息排行等功能。Lists的另一個應(yīng)用就是消息隊列,可以利用Lists的PUSH操作將任務(wù)存在Lists中,隨后工作線程再用POP操作將任務(wù)取出進(jìn)行執(zhí)行。Redis還提供了操作Lists中某一段的API,可以直接查詢、刪除Lists中某一段的元素。
    (3)Set(集合)
    Sets是一個集合,集合的概念就是一堆不重復(fù)值的組合。Set是String類型的無序集合。Redis還為集合提供了求交集、并集、差集等操作,可以非常方便地實現(xiàn)如共同關(guān)注、共同喜好、二度好友等功能,對上面的所有集合操作還可以使用不同的命令選擇將結(jié)果返回給客戶端還是存集到一個新的集合中。
    (4)Zset(有序集合)
    Zset與Set相似,但在Set的基礎(chǔ)上增加了一個Score的屬性。這一屬性在添加修改元素時進(jìn)行指定,每次指定后,Zset會自動按新的值重新調(diào)整順序。
    (5)Hash(hash表)
    在Memcached中,經(jīng)常將一些結(jié)構(gòu)化的信息打包成hashmap,在客戶端序列化后存儲為一個字符串的值,比如用戶的昵稱、年齡、性別、積分等,在需要修改其中某一項時,通常需要將所有值取出反序列化后,修改某一項的值,再序列化存儲回去。這樣不僅增大了開銷,也不適用于一些可能并發(fā)操作的場合(比如兩個并發(fā)的操作都需要修改積分)。而Redis的Hash結(jié)構(gòu)可以實現(xiàn)像在數(shù)據(jù)庫中Update一個屬性一樣只修改某一項屬性值。
2.2 Redis事務(wù)控制
    Redis可以通過MULTI/EXEC來支持簡單的事物控制。Redis只能保證事務(wù)中的所有命令串行執(zhí)行,在事務(wù)的執(zhí)行過程中不會為其他客戶端發(fā)起的請求提供服務(wù)。當(dāng)一個client使用multi命令時,這個連接會進(jìn)入一個事務(wù)上下文,該連接后續(xù)的命令會放在一個隊列中,當(dāng)此連接收到exec命令后,Redis會順序地執(zhí)行隊列中的所有命令,但是如果事務(wù)中的一個命令失敗了,并不回滾其他命令。
2.3 Redis持久化機(jī)制
    Redis是一個能支持持久化的內(nèi)存數(shù)據(jù)庫,它通過將內(nèi)存中的數(shù)據(jù)保存到磁盤來持久化。Redis有兩種持久化方式,一種是Snapshotting(快照),另一種是append-only file(縮寫aof)的方式。下面分別介紹:
    (1)Snapshotting方式
    快照是默認(rèn)的持久化方式。這種方式是將內(nèi)存中數(shù)據(jù)以快照的方式寫入到二進(jìn)制文件dump.rdb中??梢酝ㄟ^配置redis.conf來設(shè)置自動做快照持久化的方式。
    (2)aof方式
    如果對數(shù)據(jù)要求很高,可以采用aof持久化方式。因為在使用aof持久化時,Redis會將每個命令都追加到appendonly.aof文件中,當(dāng)Redis出現(xiàn)意外關(guān)閉后,重啟后會通過執(zhí)行appendonly.aof文件中的命令來在內(nèi)存中重建整個數(shù)據(jù)[1]。
2.4 主從復(fù)制
    Redis主從復(fù)制配置非常簡單,可以通過配置redis.conf文件中的Replication段來實現(xiàn)主從復(fù)制。 Redis主從復(fù)制特點:
    (1)支持一個master可以擁有多個slave,同時slave還可以接收其他的slave。
    (2)主從復(fù)制不會阻塞master和slave,在同步數(shù)據(jù)時,master和slaver都可以接收client請求。
    通過主從復(fù)制的特性可以做到以下3個方面:
    (1)可以做到讀寫分離,提供系統(tǒng)伸縮性和系統(tǒng)性能,如master主服務(wù)用來寫數(shù)據(jù),slave服務(wù)用來讀數(shù)據(jù)。
    (2)可以做到備份數(shù)據(jù)分離,如slave服務(wù)器群中的一個或兩個服務(wù)器用來備份數(shù)據(jù)。
    (3)雖然Redis宣稱主從復(fù)制無阻塞,但是由于Redis使用單線程服務(wù),而與slave的同步是由線程統(tǒng)一處理,因此,對性能有影響。在slave第一次與master做同步時,如果master快照文件較大,相應(yīng)快照文件的傳輸將耗費較長時間,文件傳輸過程中master會造成訪問延遲。
2.5 Virtual Memory 功能
    Redis的Virtual Memory(虛擬內(nèi)存)通過配置可以讓用戶設(shè)置最大使用內(nèi)存,當(dāng)超出這個內(nèi)存時,通過LRU類似算法,將一部分?jǐn)?shù)據(jù)存入文件中,在內(nèi)存中只保存使用頻率高的數(shù)據(jù)來提高Redis性能。
3 Redis應(yīng)用分析
    通過上述Redis 的特征分析,可以看到當(dāng)作Cache工具時,Redis與其他Cache相比更多的優(yōu)勢性能和內(nèi)存使用效率相差無幾卻擁有更多的數(shù)據(jù)結(jié)構(gòu)并支持更豐富的數(shù)據(jù)操作,同時還支持持久化。例如在某博客系統(tǒng)中,整個系統(tǒng)結(jié)構(gòu)圖如圖1所示,客戶端通過Redis proxy訪問Redis。目前的Redis本身都不具備分布式集群特性,當(dāng)有大量 Redis時,通常只能通過客戶端的一些數(shù)據(jù)分配算法(比如一致性哈希)來實現(xiàn)集群存儲。而 Twemproxy 通過引入一個代理層,可以將其后端的多臺 Redis實例進(jìn)行統(tǒng)一管理與分配,使應(yīng)用程序只需要在 Twemproxy 上進(jìn)行操作,而不用關(guān)心后面具體有多少個真實的 Redis存儲,這樣就可以通過平行擴(kuò)展Redis Master服務(wù)器來無限擴(kuò)展Redis。

 

 

    Redis-Master1與Redis-slave11通過主從復(fù)制連接。同時,Redis-Slaver11通過aof負(fù)責(zé)持久化。Twemproxy可以配置結(jié)點故障問題,當(dāng)某一個結(jié)點出現(xiàn)故障后,用Redis Master相應(yīng)的Redis Slave切換成Master。
    在系統(tǒng)運行中要處理各種業(yè)務(wù)邏輯,因而需要訪問大量的數(shù)據(jù)庫資源,在數(shù)據(jù)庫上進(jìn)行讀寫操作,數(shù)據(jù)庫壓力會較大,性能較低。通常把更新不頻繁的數(shù)據(jù)進(jìn)行緩存。例如下面幾種操作。
    (1)根據(jù)條件得到最新數(shù)據(jù)的操作,以時間為權(quán)重
    比較典型的取最新博文的數(shù)據(jù)代碼如圖2所示。可以將最新的5 000條博客的ID放在Redis的雙向鏈表(list)集合中,使用LPUSH globle:blogpostids命令向雙向鏈表(list)集合中插入數(shù)據(jù),插入完成后再用LTRIM global.latest.blogs 0 5000命令使其永遠(yuǎn)只保存最近5 000個ID,然后在客戶端獲取最新博文時可以用下面的邏輯(偽代碼)了。如果還有其他的取最新數(shù)據(jù)需求,比如“模擬技術(shù)”分類的最新50條數(shù)據(jù),則可以再建一個按此分類的雙向鏈表(list),將博文的ID插入此雙向鏈表(list)中。

    (2)根據(jù)條件得到排行榜應(yīng)用,相當(dāng)于數(shù)據(jù)中取TOP N操作,例如訪問量最高的博文、用戶的相互關(guān)注等。
    以某個條件為權(quán)重得到數(shù)據(jù),如果博文按瀏覽的次數(shù)排序,這時可以使用sorted set將瀏覽次數(shù)值設(shè)置成sorted set的score,將具體的博文ID設(shè)置成相應(yīng)的value,每次新增博文時只需要執(zhí)行一條ZADD blog:getblogpostrank 0 1000,每當(dāng)博文被瀏覽時,使用ZINCRBY blog:getblogpostrank 1 1000,取訪問量最高的博文時就可以使用ZREVRANGE blog:getblogpostrank 0 -1,來按照瀏覽次數(shù)高低排行了。
    (3)網(wǎng)站計數(shù)的應(yīng)用,比如在博客系統(tǒng)中瀏覽次數(shù)、評論數(shù)等。
    Redis的命令都是原子性的,可以使用INCRBY、ZINCRBY命令來增加計數(shù),使用DECRBY、ZINCRBY命令來減少計數(shù)。如果給博文ID號為1 000的增加一次瀏覽,則使用INCRBY blogpost:1000 1命令。
    (4)構(gòu)建反垃圾信息(spam)系統(tǒng),比如評論系統(tǒng)中的反垃圾信息等。
    在博客系統(tǒng)中評論是必不可少的,同時各種攻擊spam也少不了(如垃圾評論、廣告、刷排名等),可以針對這些spam制定一個規(guī)則,例如一分鐘評論不得超過2次,5分鐘不能評論多于5次。這可以使用Redis的Sorted Set來將最近一天用戶操作記起來。使用系統(tǒng)時間為score,這樣執(zhí)行一條ZADD user:1000:operation 54561227854“發(fā)表評論”,得到用戶最近一分鐘的操作如下ZRANGEBYSCORE user:1000: operation 54561227854 +inf。這樣如果一分鐘有兩次評論,就可以判定為spam(每個網(wǎng)站的規(guī)則不一樣)。
    (5)可以使用Redis系統(tǒng)中Pub/Sub和Ajax長鏈接來構(gòu)建實時消息系統(tǒng)。
    Redis的Pub/Sub系統(tǒng)作為一種消息通信模式,類似于設(shè)計模式中的觀察者模式,發(fā)布和訂閱機(jī)制可以很方便地實現(xiàn)簡單的聊天功能,可以應(yīng)用于實時聊天(通過與Ajax長鏈接)、異步消息處理(如注冊后給用戶郵件通知)等場景。將不同的頻道分布到不同服務(wù)器上,也可以很方便地實現(xiàn)服務(wù)器的擴(kuò)展以應(yīng)對用戶量的增長。
    (6)使用List或者Zset構(gòu)建隊列系統(tǒng)。
    可以使用List構(gòu)建隊列系統(tǒng),加入隊列可以使用rpush global:queue addblogpost,退出隊列使用lpop global:queue。使用Zset來構(gòu)建有優(yōu)先級的隊列系統(tǒng),加入普通級別的列隊命令zadd global:zqueue 1 addblogpost,加入高優(yōu)先級的列隊可以通過提高score的值來提高優(yōu)先級。
    為了高速緩存在系統(tǒng)應(yīng)用的不同需求,對Redis 的主要特征進(jìn)行了分析,同時對其作為緩存解決方案的應(yīng)用進(jìn)行了舉列說明。隨著Redis的發(fā)展,官方roadmap在Redis 3版本中將加入集群功能,Redis作為內(nèi)存數(shù)據(jù)庫,可以通過水平擴(kuò)展來延伸系統(tǒng)的物理內(nèi)存,同時又支持持久化,完全可以將所有數(shù)據(jù)存放在Redis內(nèi)存數(shù)據(jù)庫中,這樣才能充分發(fā)揮內(nèi)存數(shù)據(jù)庫的優(yōu)勢。
參考文獻(xiàn)
[1] Xhan.redis學(xué)習(xí)筆記之持久化[EP/OL].[2011-02-07](2013-03-15).http://www.cnblogs.com/xhan/archive/
     2011/02/07/1949640.html.

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。