本文和大家分享的主要是redis
特點及應(yīng)用場景相關(guān)內(nèi)容,一起來看看吧,希望對大家
學(xué)習(xí)redis有所幫助。
REmote DIctionary Server(Redis)
是一個由
Salvatore Sanfilippo
寫的
key-value
存儲系統(tǒng)。
Redis
是一個開源的使用
ANSI C
語言編寫、遵守
BSD
協(xié)議、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、
Key-Value
數(shù)據(jù)庫,并提供多種語言的
API
。
它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,因為值(value
)可以是 字符串
(String),
哈希
(Map),
列表
(list),
集合
(sets)
和 有序集合
(sorted sets)
等類型。
Redis的特點:
Redis
與其他
key - value
緩存產(chǎn)品有以下三個特點:
· Redis
支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時候可以再次加載進行使用。
· Redis
不僅僅支持簡單的
key-value
類型的數(shù)據(jù),同時還提供
list
,
set
,
zset
,
hash
等數(shù)據(jù)結(jié)構(gòu)的存儲。
· Redis
支持?jǐn)?shù)據(jù)的備份,即
master-slave
模式的數(shù)據(jù)備份。
Redis的優(yōu)勢:
·
性能極高
– Redis
能讀的速度是
110000
次
/s,
寫的速度是
81000
次
/s
。
·
豐富的數(shù)據(jù)類型
– Redis
支持二進制案例的
Strings, Lists, Hashes, Sets
及
Ordered Sets
數(shù)據(jù)類型操作。
·
原子
– Redis
的所有操作都是原子性的,同時
Redis
還支持對幾個操作全并后的原子性執(zhí)行。
·
豐富的特性
– Redis
還支持
publish/subscribe,
通知
, key
過期等等特性。
Redis與其他key-value存儲有什么不同?
· Redis
有著更為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)并且提供對他們的原子性操作,這是一個不同于其他數(shù)據(jù)庫的進化路徑。
Redis
的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結(jié)構(gòu)的同時對程序員透明,無需進行額外的抽象。
· Redis
運行在內(nèi)存中但是可以持久化到磁盤,所以在對不同數(shù)據(jù)集進行高速讀寫時需要權(quán)衡內(nèi)存,因為數(shù)據(jù)量不能大于硬件內(nèi)存。在內(nèi)存數(shù)據(jù)庫方面的另一個優(yōu)點是,相比在磁盤上相同的復(fù)雜的數(shù)據(jù)結(jié)構(gòu),在內(nèi)存中操作起來非常簡單,這樣
Redis
可以做很多內(nèi)部復(fù)雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產(chǎn)生的,因為他們并不需要進行隨機訪問。
Redis應(yīng)用場景
1. 顯示最新的項目列表
下面這個語句常用來顯示最新項目,隨著數(shù)據(jù)多了,查詢毫無疑問會越來越慢。
SELECT *
FROM foo
WHERE ...
ORDER
BY
time
DESC
LIMIT 10
在Web
應(yīng)用中,
“
列出最新的回復(fù)
”
之類的查詢非常普遍,這通常會帶來可擴展性問題。這令人沮喪,因為項目本來就是按這個順序被創(chuàng)建的,但要輸出這個順序卻不得不進行排序操作。
類似的問題就可以用Redis
來解決。比如說,我們的一個
Web
應(yīng)用想要列出用戶貼出的最新
20
條評論。在最新的評論邊上我們有一個
“
顯示全部
”
的鏈接,點擊后就可以獲得更多的評論。
我們假設(shè)數(shù)據(jù)庫中的每條評論都有一個唯一的遞增的ID
字段。我們可以使用分頁來制作主頁和評論頁,使用
Redis
的模板:
·
每次新評論發(fā)表時,我們會將它的
ID
添加到一個
Redis
列表:
LPUSH latest.comments
·
我們將列表裁剪為指定長度,因此
Redis
只需要保存最新的
5000
條評論:
LTRIM latest.comments 0 5000
·
每次我們需要獲取最新評論的項目范圍時,我們調(diào)用一個函數(shù)來完成(使用偽代碼):
FUNCTION get_latest_comments(start,num_items): id_list = redis.
lrange("latest.comments",start,start+num_items-1) IF id_list.length < num_items id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...") END RETURN id_list END
這里我們做的很簡單。在Redis
中我們的最新
ID
使用了常駐緩存,這是一直更新的。但是我們做了限制不能超過
5000
個
ID
,因此我們的獲取
ID
函數(shù)會一直詢問
Redis
。只有在
start/count
參數(shù)超出了這個范圍的時候,才需要去訪問數(shù)據(jù)庫。
我們的系統(tǒng)不會像傳統(tǒng)方式那樣“
刷新
”
緩存,
Redis
實例中的信息永遠(yuǎn)是一致的。
SQL
數(shù)據(jù)庫(或是硬盤上的其他類型數(shù)據(jù)庫)只是在用戶需要獲取
“
很遠(yuǎn)
”
的數(shù)據(jù)時才會被觸發(fā),而主頁或第一個評論頁是不會麻煩到硬盤上的數(shù)據(jù)庫了。
2. 刪除與過濾
我們可以使用LREM
來刪除評論。如果刪除操作非常少,另一個選擇是直接跳過評論條目的入口,報告說該評論已經(jīng)不存在。
有些時候你想要給不同的列表附加上不同的過濾器。如果過濾器的數(shù)量受到限制,你可以簡單的為每個不同的過濾器使用不同的Redis
列表。畢竟每個列表只有
5000
條項目,但
Redis
卻能夠使用非常少的內(nèi)存來處理幾百萬條項目。
3. 排行榜相關(guān)
另一個很普遍的需求是各種數(shù)據(jù)庫的數(shù)據(jù)并非存儲在內(nèi)存中,因此在按得分排序以及實時更新這些幾乎每秒鐘都需要更新的功能上數(shù)據(jù)庫的性能不夠理想。
典型的比如那些在線游戲的排行榜,比如一個Facebook
的游戲,根據(jù)得分你通常想要:
·
列出前100
名高分選手
·
·
列出某用戶當(dāng)前的全球排名
·
這些操作對于Redis
來說小菜一碟,即使你有幾百萬個用戶,每分鐘都會有幾百萬個新的得分。
模式是這樣的,每次獲得新得分時,我們用這樣的代碼:
ZADD leaderboard
你可能用userID
來取代
username
,這取決于你是怎么設(shè)計的。
得到前100
名高分用戶很簡單:
ZREVRANGE leaderboard 0 99
用戶的全球排名也相似,只需要:
ZRANK leaderboard
4. 按照用戶投票和時間排序
排行榜的一種常見變體模式就像Reddit
或
Hacker News
用的那樣,新聞按照類似下面的公式根據(jù)得分來排序:
score = points / time^alpha
因此用戶的投票會相應(yīng)的把新聞挖出來,但時間會按照一定的指數(shù)將新聞埋下去。下面是我們的模式,當(dāng)然算法由你決定。
模式是這樣的,開始時先觀察那些可能是最新的項目,例如首頁上的1000
條新聞都是候選者,因此我們先忽視掉其他的,這實現(xiàn)起來很簡單。
·
每次新的新聞貼上來后,我們將
ID
添加到列表中,使用
LPUSH + LTRIM
,確保只取出最新的
1000
條項目。
·
有一項后臺任務(wù)獲取這個列表,并且持續(xù)的計算這
1000
條新聞中每條新聞的最終得分。計算結(jié)果由
ZADD
命令按照新的順序填充生成列表,老新聞則被清除。這里的關(guān)鍵思路是排序工作是由后臺任務(wù)來完成的。
5. 過期項目處理
另一種常用的項目排序是按照時間排序。我們使用unix
時間作為得分即可。
模式如下:
·
每次有新項目添加到我們的非
Redis
數(shù)據(jù)庫時,我們把它加入到排序集合中。這時我們用的是時間屬性,
current_time
和
time_to_live
。
·
另一項后臺任務(wù)使用
ZRANGE…SCORES
查詢排序集合,取出最新的
10
個項目。如果發(fā)現(xiàn)
unix
時間已經(jīng)過期,則在數(shù)據(jù)庫中刪除條目。
6. 計數(shù)
Redis
是一個很好的計數(shù)器,這要感謝
INCRBY
和其他相似命令。
我相信你曾許多次想要給數(shù)據(jù)庫加上新的計數(shù)器,用來獲取統(tǒng)計或顯示新信息,但是最后卻由于寫入敏感而不得不放棄它們。
好了,現(xiàn)在使用Redis
就不需要再擔(dān)心了。有了原子遞增(
atomic increment
),你可以放心的加上各種計數(shù),用
GETSET
重置,或者是讓它們過期。
例如這樣操作:
INCR
user: EXPIRE
user: 60
你可以計算出最近用戶在頁面間停頓不超過60
秒的頁面瀏覽量,當(dāng)計數(shù)達到比如
20
時,就可以顯示出某些條幅提示,或是其它你想顯示的東西。
7. 特定時間內(nèi)的特定項目
另一項對于其他數(shù)據(jù)庫很難,但Redis
做起來卻輕而易舉的事就是統(tǒng)計在某段特點時間里有多少特定用戶訪問了某個特定資源。比如我想要知道某些特定的注冊用戶或
IP
地址,他們到底有多少訪問了某篇文章。
每次我獲得一次新的頁面瀏覽時我只需要這樣做:
SADD page:day1:<
page_id> <
user_id>
當(dāng)然你可能想用unix
時間替換
day1
,比如
time()-(time()%3600*24)
等等。
想知道特定用戶的數(shù)量嗎?只需要使用
SCARD page:day1:
需要測試某個特定用戶是否訪問了這個頁面?
8. 實時分析正在發(fā)生的情況,用于數(shù)據(jù)統(tǒng)計與防止垃圾郵件等
我們只做了幾個例子,但如果你研究Redis
的命令集,并且組合一下,就能獲得大量的實時分析方法,有效而且非常省力。使用
Redis
原語命令,更容易實施垃圾郵件過濾系統(tǒng)或其他實時跟蹤系統(tǒng)。
9. Pub/Sub
Redis
的
Pub/Sub
非常非常簡單,運行穩(wěn)定并且快速。支持模式匹配,能夠?qū)崟r訂閱與取消頻道。
10. 隊列
你應(yīng)該已經(jīng)注意到像list push
和
list pop
這樣的
Redis
命令能夠很方便的執(zhí)行隊列操作了,但能做的可不止這些:比如
Redis
還有
list pop
的變體命令,能夠在列表為空時阻塞隊列。
11. 緩存
Redis
的緩存部分值得寫一篇新文章,我這里只是簡單的說一下。
Redis
能夠替代
memcached
,讓你的緩存從只能存儲數(shù)據(jù)變得能夠更新數(shù)據(jù),因此你不再需要每次都重新生成數(shù)據(jù)了。
來源:簡書