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

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

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

 

 

    Redis-Master1與Redis-slave11通過(guò)主從復(fù)制連接。同時(shí),Redis-Slaver11通過(guò)aof負(fù)責(zé)持久化。Twemproxy可以配置結(jié)點(diǎn)故障問(wèn)題,當(dāng)某一個(gè)結(jié)點(diǎn)出現(xiàn)故障后,用Redis Master相應(yīng)的Redis Slave切換成Master。
    在系統(tǒng)運(yùn)行中要處理各種業(yè)務(wù)邏輯,因而需要訪問(wèn)大量的數(shù)據(jù)庫(kù)資源,在數(shù)據(jù)庫(kù)上進(jìn)行讀寫(xiě)操作,數(shù)據(jù)庫(kù)壓力會(huì)較大,性能較低。通常把更新不頻繁的數(shù)據(jù)進(jìn)行緩存。例如下面幾種操作。
    (1)根據(jù)條件得到最新數(shù)據(jù)的操作,以時(shí)間為權(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個(gè)ID,然后在客戶(hù)端獲取最新博文時(shí)可以用下面的邏輯(偽代碼)了。如果還有其他的取最新數(shù)據(jù)需求,比如“模擬技術(shù)”分類(lèi)的最新50條數(shù)據(jù),則可以再建一個(gè)按此分類(lèi)的雙向鏈表(list),將博文的ID插入此雙向鏈表(list)中。

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