1. 程式人生 > >redis開發與運維筆記(1)

redis開發與運維筆記(1)

1、Redis特性與優點

  • 速度快。redis所有資料都存放於記憶體;是用C語言實現,更加貼近硬體;使用了單執行緒架構,避免了多執行緒競爭問題。Redis使用了單執行緒架構和IO多路複用模型(epoll作為多路複用技術的實現,非阻塞IO)來實現。每次客戶端的請求都會經過傳送命令、執行命令、返回結果三個階段。所有客戶端命令都會放入到同一個佇列中,然後逐個被執行。單執行緒避免了執行緒切換和競態產生的消耗
  • 基於鍵值對的資料結構,支援的資料結構豐富。它主要提供了5種資料結構: 字串、 雜湊、 列表、 集合、 有序集合, 同時在字串的基礎之上演變出了點陣圖(Bitmaps) 和HyperLogLog兩種神奇的“資料結構”, 並且隨著LBS(Location Based Service, 基於位置服務) 的不斷髮展, Redis3.2版本中加入有關GEO(地理資訊定位)
    的功能。每種資料結構都有底層的內部編碼實現,而且是多種實現,redis會在合適的場景下選擇合適的內部編碼。
  • 功能豐富。鍵過期功能,用來實現快取;提供了釋出訂閱功能,實現訊息系統支援Lua指令碼提供簡單的事務功能;提供了Pipeline,一次性將一批命令傳給redis伺服器,減小了網路開銷
  • 簡單,穩定。原始碼少,3.0版本原始碼只有5w行左右
  • 客戶端語言多。
  • 持久化。兩種持久化方式: RDB和AOF
  • 主從複製。複製功能是分散式Redis的基礎
  • 高可用和分散式。2.8版本提供了高可用實現Redis Sentinel, 它能夠保證Redis節點的故障發現和故障自動轉移。 Redis從3.0版本正式提供了分散式實現Redis Cluster

    , 它是Redis真正的分散式實現, 提供了高用、 讀寫和容量的擴充套件性。

2、Redis啟動與關閉

  • 服務端啟動。配置檔案啟動,redis-server  /opt/redis/redis.conf
  • 客戶端啟動。redis-cli -h 127.0.0.1  -p 6379
  • 停止redis服務。redis-cli shutdown nosave|save  關閉過程:斷開與客戶端的連線;持久化檔案生成。不建議kill -9 暴力殺程序,極端下會造成丟失資料的情況

3、Redis的常用API

  • 檢視所有鍵。【keys *】會遍歷所有鍵,禁用
  • 鍵總數。【dbsize】不會遍歷所有鍵,直接獲取redis內建的鍵總數
  • 檢查鍵是否存在。【exists key】存在返回1,不存在返回0
  • 刪除鍵。【del key】返回結果為成功刪除的鍵的個數
  • 設定鍵過期。【expire key seconds】秒級別;【expireat key timestamp 】秒級時間戳;【pexpire key milliseconds】毫秒級過期 ;【pexpireat key milliseconds-timestamp 】毫秒級時間戳
  • 檢查鍵過期。【ttl key】返回鍵的剩餘過期時間,秒級;【pttl key】毫秒級;-1,鍵沒設定過期時間;-2 鍵不存在
  • 清除過期時間。【persist】;對於字串型別鍵,執行set命令也會去掉過期時間;setex命令作為set+expire的組合, 不但是原子執行, 同時減少了一次網路通訊的時間
  • 檢視鍵的型別。【type key】鍵不存在,返回none
  • 鍵重新命名。rename key newkey。如果在rename newkey之前,newkey已經存在,newkey的值會被覆蓋。防止被覆蓋,提供了renamenx命令。重新命名期間會刪除原來的key,如果key對應的值過大,存在阻塞redis的可能
  • 隨機返回一個鍵。randomkey。

4、Redis的字串

內部編碼,有三種

  • int。8個位元組的長整型
  • embstr。小於等於39個位元組的字串
  • raw。大於39個位元組的字串

應用場景

  • 快取
  • 計數
  • 共享session
  • 限速。每個使用者的請求頻率,每個ip的請求頻率

命令

  • 設定值。set key value [ex seconds] [px milliseconds] [nx|xx]。其中setnx可以作為分散式鎖的實現
  • 獲取值。 get key。不存在返回 nil(空)
  • 批量設定值,mset key value [key value ...] ;批量獲取值,mget key [key ...] 。一次請求的網路時間大於命令處理時間。學會使用批量操作,能減少大量的網路消耗。提高業務處理效率。但是一次批量操作過多,有可能導致Redis阻塞或者網路擁堵
  • 計數。incr、decr、incrby、decrby、incrbyfloat。很多其他的語言和儲存系統通過cas實現計數,會有一定的cpu開銷。redis單執行緒模型,完全不存在這個問題。
  • 追加值。append key value
  • 字串長度。strlen key。每個中文佔用三個位元組,也就是三個長度
  • 設定並返回原值。getset key value
  • 設定指定位置的字元。setrange key offset value
  • 獲取部分字串。getrange key start end。時間複雜度O(n)

5、Redis的HASH結構

內部編碼

  • ziplist(壓縮列表)。當雜湊型別元素個數小於hash-max-ziplist-entries
    配置(預設512個) 、 同時所有值都小於hash-max-ziplist-value配置(預設64
    位元組) 時, Redis會使用ziplist作為雜湊的內部實現, ziplist使用更加緊湊的
    結構實現多個元素的連續儲存, 所以在節省記憶體方面比hashtable更加優秀 
  • hashtable(雜湊表)。當雜湊型別無法滿足ziplist的條件時,Redis會使用hashtable作為雜湊的內部實現

命令

  • 設定field值。hset key field value。hsetnx,和setnx作用相同,只不過作用域由鍵變為field
  • 獲取field值。hget key field。如果field不存在,返回nil
  • 刪除field。hdel key field [field ...] 
  • 計算field個數。hlen key
  • 批量設定和獲取field-value。hmget key field [field ...] ;hmset key field value [field value ...] 。
  • 判斷field是否存在。hexists key field。存在返回1,不存在返回0
  • 獲取所有field。hkeys key
  • 獲取所有value。hvals key
  • 獲取所有field-value。hgetall key。如果獲取的元素比較多,可能會阻塞Redis。
  • hincrby key field;hincrbyfloat key field 
  • 計算value的字串長度。hstrlen key field

7、Redis的列表結構

列表中的每個字串稱為元素(element),一個列表最多儲存2^32-1個元素。可以充當棧和佇列,比較靈活。列表中的元素是有序的且可重複的,可以通過下標獲取某個元素

內部編碼

  • ziplist(壓縮列表)。當列表的元素個數小於list-max-ziplist-entries配置(預設512個),同時列表中每個元素的值都小於list-max-ziplist-value配置時(預設64位元組),Redis會選用ziplist來作為列表的內部實現來減少記憶體的使用
  • linkedlist(連結串列):當列表型別無法滿足ziplist的條件時, Redis會使用linkedlist作為列表的內部實現。
  • Redis3.2版本提供了quicklist內部編碼,簡單地說它是以一個ziplist為節點的linkedlist,它結合了ziplist和linkedlist兩者的優勢,為列表型別提供了一種更為優秀的內部編碼實現

應用場景

  • 訊息佇列。Redis的lpush+brpop命令組合即可實現阻塞佇列, 生產者客戶端使用lrpush從列表左側插入元素, 多個消費者客戶端使用brpop命令阻塞式的“搶”列表尾部的元素, 多個客戶端保證了消費的負載均衡和高可用性。
  • 文章列表。雜湊儲存每篇文章的詳細資訊。列表儲存每個人的文章列表。支援分頁獲取,如果列表較大,獲取列表中間元素的效能會變差,可以使用redis3.2版本的quicklist內部編碼實現。
  • lpush+lpop=Stack(棧) ;lpush+rpop=Queue(佇列) ;lpush+brpop=Message Queue(訊息佇列,阻塞佇列); lpush+ltrim=Capped Collection(有限集合) 

命令

  • 新增操作。從右邊插入資料 rpush key value [value ...];從左邊插入資料  lpush key value [value ...];向某個元素前或後插入資料 linsert key before|after pivot value
  • 查詢。獲取指定範圍的元素列表 lrange key start end(包含end);獲取指定下標的元素 lindex key index(-1為最後一個元素);獲取列表長度 llen key
  • 刪除。從左側彈出元素 lpop key;從右側彈出元素 rpop key;刪除指定元素 lrem key count value(count>0 從左到右,刪除最多count個元素;count<0 從右到左;count=0,刪除所有);按照索引範圍修剪列表 ltrim key start end
  • 修改。修改執行索引下標的元素 lset key index newValue;
  • 阻塞操作。blpop key [key ...] timeout ;brpop key [key ...] timeout 。需要注意兩點:第一點,如果blpop多個key,一旦有一個鍵能彈出元素,立刻給客戶端返回;第二點,如果多個客戶端對同一個key執行blpop,那麼最先執行blpop的客戶端可以獲取到彈出的值。

8、Redis的Set

不允許有重複元素,無序,不能通過索引下標獲取元素。一個集合最多可以儲存2^32-1個元素。支援集合內的增刪改查,集合的交集、並集、差集。

內部編碼

  • intset(整數集合) : 當集合中的元素都是整數且元素個數小於set-maxintset-entries配置(預設512個)時, Redis會選用intset來作為集合的內部實現,從而減少記憶體的使用。
  • hashtable(雜湊表) : 當集合型別無法滿足intset的條件時, Redis會使用hashtable作為集合的內部實現。

使用場景

  • 標籤(tag)。使用sinter命令計算使用者的共同興趣。
  • 生成隨機數,抽獎

命令。集合內操作。

  • 新增元素。sadd key element [element ...]
  • 刪除元素。srem key element [element ...] 
  • 計算元素個數。scard key 。時間複雜度O(1),不會遍歷集合。
  • 判斷元素是否在集合中。sismember key element 。在集合內返回1,不在返回0
  • 隨機從集合中返回指定個數元素。srandmember key [count] 
  • 從集合隨機彈出指定個數的元素。spop key  [count] 
  • 獲取所有元素。smembers key 。如果元素過多,存在阻塞redis的可能。可以用sscan來完成

(2)命令,集合間操作。

  • 求多個集合的交集。sinter key [key ...] 
  • 求多個集合的並集。suinon key [key ...] 
  • 求多個集合的差集。sdiff key [key ...] 
  • 將集合操作的結果儲存。sinterstore/suionstore/sdiffstore  destination key [key ...] 

9、Redis的有序set

內部編碼

  • ziplist(壓縮列表) : 當有序集合的元素個數小於zset-max-ziplistentries配置(預設128個) , 同時每個元素的值都小於zset-max-ziplist-value配置(預設64位元組) 時, Redis會用ziplist來作為有序集合的內部實現, ziplist
    可以有效減少記憶體的使用 
  • skiplist(跳躍表) : 當ziplist條件不滿足時, 有序集合會使用skiplist作為內部實現, 因為此時ziplist的讀寫效率會下降。

使用場景

  • 排行榜

命令。集合內的命令。

  • 新增成員。zadd key score member [score member ...] 

    ·Redis3.2為zadd命令添加了nx、 xx、 ch、 incr四個選項:
    ·nx: member必須不存在, 才可以設定成功, 用於新增。
    ·xx: member必須存在, 才可以設定成功, 用於更新。
    ·ch: 返回此次操作後, 有序集合元素和分數發生變化的個數
    ·incr: 對score做增加, 相當於後面介紹的zincrby。

  • 計算成員個數。zcard key 
  • 計算某個成員的分數。zscore key member 
  • 計算成員排名。zrank key member (分數由低到高);zrevrank key member (分數由高到低)
  • 刪除成員。zrem key member [member ...] 
  • 增加成員分數。zincrby key increment member 
  • 返回指定排名範圍的成員。zrange key start end [withscores] (排名由低到高);zrevrange key start end [withscores] (排名由高到低)
  • 返回指定分數範圍的成員。zrangebyscore key min max [withscores] [limit offset count] 。其中zrangebyscore按照分數從低到高返回, zrevrangebyscore反之。 例如
    下面操作從低到高返回200到221分的成員, withscores選項會同時返回每個
    成員的分數。 [limit offset count]選項可以限制輸出的起始位置和個數 。同時min和max還支援開區間(小括號) 和閉區間(中括號) , -inf和
    +inf分別代表無限小和無限大。
  • 返回指定分數範圍成員個數。zcount key min max 
  • 刪除指定排名內的升序元素。zremrangebyrank key start end 
  • 刪除指定分數範圍的成員。zremrangebyscore key min max 

命令,集合間的操作

  • 交集。zinterstore destination numkeys key [key ...] [weights weight [weight ...]][aggregate sum|min|max]
  • destination: 交集計算結果儲存到這個鍵。
    ·numkeys: 需要做交集計算鍵的個數。
    ·key[key...]: 需要做交集計算的鍵。 
    weights weight[weight...]: 每個鍵的權重, 在做交集計算時, 每個鍵中
    的每個member會將自己分數乘以這個權重, 每個鍵的權重預設是1。
    ·aggregate sum|min|max: 計算成員交集後, 分值可以按照sum(和) 、
    min(最小值) 、 max(最大值) 做彙總, 預設值是sum 
  • 並集。zunionstore destination numkeys key [key ...] [weights weight [weight ...]][aggregate sum|min|max] 。

10、Redis 的Bitmaps

(1)概述。Bitmaps本身的資料結構就是字串,支援對字串的位進行操作。

(2)每個獨立使用者是否訪問過網站存放在Bitmaps中,將訪問的使用者記做1,沒有訪問的使用者記做0,用偏移量作為使用者的id

  • 設定值。setbit key offset value 。初始化的時候,如果偏移量非常大,整個初始化過程會非常慢,可能會造成redis阻塞
  • 獲取值。gitbit key offset 。返回0說明沒有訪問過
  • 獲取Bitmaps指定範圍值為1的個數 。bitcount [start][end] 。
  • Bitmaps間的運算 。bitop op destkey key[key....] 。做多個Bitmaps的and(交集) 、 or(並集) 、 not(非) 、 xor(異或) 操作並將結果儲存在destkey中
  • 計算Bitmaps中第一個值為targetBit的偏移量。bitpos key targetBit [start] [end]

(3)Bitmaps分析

   假設網站有1億使用者, 每天獨立訪問的使用者有5千萬, 如果每天用集合型別和Bitmaps分別儲存活躍使用者。
   集合型別記憶體量:64位*50000000=400M。
   Bitmaps記憶體量:1位*50000000=12.5M。

11、Redis 的HyperLogLog

  • Redis中hyperloglog是用來做基數統計的,其優點是:在輸入元素的數量或者體積非常非常大的時候,計算基數所需的空間總是固定的,並且是很小的。在Redis裡面,每個Hyperloglog鍵只需要12Kb的大小就能計算接近2^64個不同元素的基數,但是hyperloglog只會根據輸入元素來計算基數,而不會儲存元素本身,所以不能像集合那樣返回各個元素本身
  • pfadd key element [element …]。新增操作。如果新增成功返回1
  • pfcount key [key …]。求一個或多個key的基數,計算獨立使用者數
  • pfmerge destkey sourcekey [sourcekey ...]。合併。pfmerge可以求出多個HyperLogLog的並集並賦值給destkey
  • HyperLogLog記憶體佔用量小得驚人, 但是用如此小空間來估算如此巨大的資料, 必然不是100%的正確, 其中一定存在誤差率。 Redis官方給出的數字是0.81%的失誤率

12、GEO

  • 增加地理位置資訊。geoadd key longitude latitude member [longitude latitude member ...]。longitude、 latitude、 member分別是該地理位置的經度、 緯度、 成員。新增和更新都是用此命令,可以同時新增多個地理位置資訊。
  • 獲取地理位置資訊。geopos key member [member ...]
  • 獲取兩個地址位置的距離。geodist key member1 member2 [unit]。unit代表返回結果的單位,m(meters) 代表米、km(kilometers) 代表公里、mi(miles) 代表英里、ft(feet) 代表尺
  • 獲取指定位置範圍內的地理資訊位置集合。georadius key longitude latitude/georadiusbymember key member radiusm|km|ft|mi [withcoord] [withdist][withhash] [COUNT count] [asc|desc] [store key] [storedist key]
    都是以一個地理位置為中心算出指定半徑內的其他地理資訊位置

  • 獲取geohash。geohash key member [member ...]。Redis使用geohash將二維經緯度轉換為一維字串。
    GEO的資料型別為zset, Redis將所有地理位置資訊的geohash存放在zset中字串越長, 表示的位置更精確, 例如geohash長度為9時, 精度在2米左右兩個字串越相似, 它們之間的距離越近, Redis利用字串字首匹配演算法實現相關的命令
    geohash編碼和經緯度是可以相互轉換的

  • 刪除地理位置資訊。zrem key member。GEO沒有提供刪除成員的命令, 但是因為GEO的底層實現是zset, 所以可以借用zrem命令實現對地理位置資訊的刪除。