Redis探路

整理自Redis 中文官網http://www.redis.cn/

1. 定義:

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.-From Redis official website 。

譯:Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 複製(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁盤持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)。

2. 數據結構

雖說是key-value存儲結構,但是絕不是簡單的key-value形式,它實際上是一個數據結構服務器。它的value還支持下列數據類型。

2.0 Redis 的key:

2.0.1 概述

Redis的key是二進制安全的,所以任何二進制序列都可以作爲key值,比如說普通字符串“redis”,jpeg圖片內容,空字符串等。

2.0.2 規則

  1. 鍵值不宜太長,這樣不僅消耗內存,在檢索鍵值的成本也會很高。
  2. 不要爲了節省空間而過分縮減鍵值長度,以至於詞不達意。
  3. 在多個單詞中間可以用點或下劃線隔開

2.0.3 操作鍵

exists:判斷鍵值是否存在
del:刪除鍵值
type:獲取鍵存儲的類型

> exists count
(integer) 1
> del count
(integer) 1
> exists count
(integer) 0
> type count
"string"

2.0.4 設置鍵的存活時間

顧名思義就是給鍵值設置一個時間,達到時間後就刪除該鍵值對
set count 10 ex 10:設置鍵值對同時設置時間
expire:給鍵設置存活時間
ttl:查看鍵剩餘存活時間,若已過期返回-2

> expire count 10
(integer) 1
> ttl count
(integer) 5
> get count
(nil)

2.1 字符串(Strings)

Redis最簡單的類型,使用這種類型Redis就類似於一個可以持久化的memcached服務器。

memcached 只將數據存放在內存中,服務器重啓後數據會丟失。

2.1.1 設置/獲取

  • set key hehe/get key :支持存不超過512M的任意字符串(包括二進制)
  • mset a 10 b 20 c 30/mget a b c:批量插入/獲取,mget返回的是value組成的數組
  • Attention:在Try Redis 中測試時set 重複key不會報錯,而是覆蓋原來key的value值

2.1.2 原子操作

  • INCR 命令將字符串值解析成整型,將其加一,最後將結果保存爲新的字符串值,類似的還有incrby,decr,decrby
  • 案例:這裏引用一個應用場景來解釋,一個網站需要記錄瀏覽的客戶端數量
> set count 0
OK
> get count
"0"
> incr count
(integer) 1
> get count
"1"
> incrby count 50
(integer) 51
> decr count
(integer) 50
> decrby count 50
(integer) 0
  • INCR原子操作的意義:當客戶端併發訪問該數據的時候不會出現線程安全的問題,即客戶端A和客戶端B同時訪問“1”時,不會出現兩者都將其加到2,然後將value賦值爲2,其值肯定是3

2.2 散列(Hashs)

hmset:批量插入hset:插入一條
hmget:批量獲得hget:獲得一條
hgetall:獲取所有鍵/值

2.3 列表(Lists)

2.3.1 原理

Redis的List是基於Linked List實現的,使用Linked的原因是對於數據庫系統來說,能非常快的在很大的數據列表中快速添加數據,另外一點是Redis能在常數複雜度獲取常數的長度

2.3.2操作

lpush:從列左插入,可批量rpush:從列右插入,可批量
lrange:從列左開始遍歷,需要兩個數值參數,其中第一個是開始遍歷位置,第二個表示遍歷結束位置。數值可以爲負數,爲-1時代表列尾元素,-2代表列尾前一元素,以此類推
lpop/rpop:從列左、列右彈出元素,並刪除
ltirm:從左邊截取指定長度用法與lrange一樣

> lpush tt hehe
(integer) 1
> lpush tt xixi
(integer) 2
> rpush tt haha
(integer) 3
> lrange tt 0 -1
1) "xixi"
2) "hehe"
3) "haha"
> rpop tt
"g"
> lpop tt
"xixi"
> ltrim tt 0 3
OK
> lrange tt 0 -1
1) "hehe"
2) "haha"
3) "a"
4) "b"

2.3.3 常用案例

list可被用來實現聊天系統。還可以作爲不同進程間傳遞消息的隊列。關鍵是,你可以每次都以原先添加的順序訪問數據。這不需要任何SQL ORDER BY 操作,將會非常快,也會很容易擴展到百萬級別元素的規模。

例如在評級系統中,比如社會化新聞網站 reddit.com,你可以把每個新提交的鏈接添加到一個list,用LRANGE可簡單的對結果分頁。

在博客引擎實現中,你可爲每篇日誌設置一個list,在該list中推入博客評論

2.3.4 阻塞操作

用Redis來實現生產者和消費者模型,如使用LPUSH和RPOP來實現該功能。但會遇到這種情景:list是空,這時候消費者就需要輪詢來獲取數據,這樣就會增加redis的訪問壓力、增加消費端的cpu時間,而很多訪問都是無用的。

爲此,Redis提供了阻塞式訪問命令BRPOP,BLPOP,消費者可以在獲取數據時指定如果數據不存在阻塞的時間,如果在時限內獲得數據則立即返回,如果超時還沒有數據則返回null, 0表示一直阻塞。

2.3.5 key的自動刪除和創建

  • 當我們向一個聚合數據類型中添加元素時,如果目標鍵不存在,就在添加元素前創建空的聚合數據類型。

  • 當我們從聚合數據類型中移除元素時,如果值仍然是空的,鍵自動被銷燬。

  • 對一個空的 key 調用一個只讀的命令,比如 LLEN (返回 list 的長度),或者一個刪除元素的命令,將總是產生同樣的結果。該結果和對一個空的聚合類型做同個操作的結果是一樣的。

2.4 集合(Sets)

Redis Set 是 String 的無序排列
sadd:批量添加元素
smembers:獲取元素
sismember:檢測set中是否存在一個指定元素
scard:獲得集合的數量
srandmember:隨機獲得一個元素,不從set中刪除

> sadd tset 1 2 3
(integer) 3
> smembers tset
1) "1"
2) "2"
3) "3"
> sismember tset 1
(integer) 1
> sinter stt:1 stt:2 stt:3//取多個集合的交集
1) "1000"
> scard tset
3

2.5 有序集合(Sorted Sets)

2.5.1 原理

有序集合類似於Set和Hash的混和,它與Set一樣是由唯一的,不重複的String元素組成。同時,它的每一個元素都映射到了一個“score”(浮點值),排序方式就是根據“score”大小來排序的。但是“score”是可以重複的,如果score是重複的,那麼就會按照字符串的數據字典來排序。

2.5.2 操作

zadd:添加,可批量
zrange:按score升序獲取指定索引範圍元素
zrevrange:按score降序獲取指定範圍索引元素
zrangebyscore:按score範圍檢索
zremrangebyscore:移除指定score值區間
zrank:獲取指定元素的索引位置
zrangebylex:返回指定字符字典區間的元素

> zadd zuser 22 wx 23 ly 24 kk
(integer) 3
> zrange zuser 0 -1
1) "ll"
2) "wx"
3) "ly"
4) "kk"
> zrevrange zuser 0 -1
1) "kk"
2) "ly"
3) "am"
4) "wx"
5) "lly"
6) "ll"
> zrevrange zuser 0 -1 withscores
1) "kk"
2) 24.0
3) "ly"
4) 23.0
5) "am"
6) 23.0
7) "wx"
8) 22.0
9) "lly"
10) 7.0
11) "ll"
12) 1.0
> zrangebyscore zuser -inf 23
1) "ll"
2) "lly"
3) "wx"
4) "am"
5) "ly"
> zremrangebyscore zuser 23 24
3
> zrangebylex zuser [l [o
1) "ll"
2) "lly"

3. Redis持久化機制

3.1 RDB

RDB持久化方式能夠在指定的時間間隔能對你的數據進行快照存儲.

3.1.1 優勢

  • RDB是一個非常緊湊的文件,它保存了某個時間點得數據集,非常適用於數據集的備份,比如你可以在每個小時報保存一下過去24小時內的數據,同時每天保存過去30天的數據,這樣即使出了問題你也可以根據需求恢復到不同版本的數據集.
  • RDB是一個緊湊的單一文件,很方便傳送到另一個遠端數據中心或者亞馬遜的S3(可能加密),非常適用於災難恢復.
  • RDB在保存RDB文件時父進程唯一需要做的就是fork出一個子進程,接下來的工作全部由子進程來做,父進程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
  • 與AOF相比,在恢復大的數據集的時候,RDB方式會更快一些.

3.1.2 劣勢

  • 如果你希望在redis意外停止工作(例如電源中斷)的情況下丟失的數據最少的話,那麼RDB不適合你.雖然你可以配置不同的save時間點(例如每隔5分鐘並且對數據集有100個寫的操作),是Redis要完整的保存整個數據集是一個比較繁重的工作,你通常會每隔5分鐘或者更久做一次完整的保存,萬一在Redis意外宕機,你可能會丟失幾分鐘的數據.
  • RDB 需要經常fork子進程來保存數據集到硬盤上,當數據集比較大的時候,fork的過程是非常耗時的,可能會導致Redis在一些毫秒級內不能響應客戶端的請求.如果數據集巨大並且CPU性能不是很好的情況下,這種情況會持續1秒,AOF也需要fork,但是你可以調節重寫日誌文件的頻率來提高數據集的耐久度.

3.2 AOF

AOF持久化方式記錄每次對服務器寫的操作,當服務器重啓的時候會重新執行這些命令來恢復原始的數據,AOF命令以redis協議追加保存每次寫的操作到文件末尾.Redis還能對AOF文件進行後臺重寫,使得AOF文件的體積不至於過大.

3.2.2 優勢

3.2.3 劣勢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章