Redis初步學習筆記

Redis學習筆記

命名規範

  1. redis 的key 區分大小寫
  2. 建議使用:分割,用來命名字段,比如 user:101:zhangsan

redis的常用命令

DEL

用法 :DEL ke [key …]

刪除給定的一個或多個 key 。不存在的 key 會被忽略。

EXISTS

用法 :EXISTS key

檢查給定 key 是否存在

EXPIRE

用法:EXPIRE key seconds

爲給定 key 設置生存時間,當 key 過期時(生存時間爲 0 ),它會被自動刪除

KEYS

用法:KEYS pattern

查找所有符合給定模式 patternkey

KEYS * 匹配數據庫中所有 key

KEYS h?llo 匹配 hellohallohxllo 等。

KEYS h*llo 匹配 hlloheeeeello 等。

KEYS h[ae]llo 匹配 hellohallo ,但不匹配 hillo

特殊符號用 \ 隔開

TTL

用法:TTL key

以秒爲單位,返回給定 key 的剩餘生存時間(TTL, time to live)。

TYPE

用法:TYPE key

返回 key 所儲存的值的類型。

返回值:

none (key不存在)

string (字符串)

list (列表)

set (集合)

zset (有序集)

hash (哈希表)

String類型

賦值語法

SET KEY_NAME VALUE
Redis SET 命令用於設置給定 key 的值。如果 key 已經存儲值, SET 就覆寫舊值,且無視類型

SETNX key value

解決分佈式鎖 方案之一
只有在 key 不存在時設置 key 的值。Setnx(SET if Not eXists) 命令在指定的 key 不存在時,爲 key 設置指定的值

MSET key value [key value …]
同時設置一個或多個 key-value 對

SETEX key seconds value

將值 value 關聯到 key ,並將 key 的生存時間設爲 seconds (以秒爲單位)。

如果 key 已經存在, SETEX 命令將覆寫舊值。

SEXEX是一個原子操作

取值語法

GET KEY_NAME
Redis GET命令用於獲取指定 key 的值。如果 key 不存在,返回 nil 。如果key 儲存的值不是字符串類型,返回一個錯誤。

GETRANGE key start end
用於獲取存儲在指定 key 中字符串的子字符串。字符串的截取範圍由 start 和 end 兩個偏移量決定(包括 start 和 end 在內)

MGET key1 [key2…]
獲取所有(一個或多個)給定 key 的值

STRLEN key
返回 key 所儲存的字符串值的長度

GETSET KEY_NAME VALUE
Getset 命令用於設置指定 key 的值,並返回 key 的舊值,當 key 不存在時,返回 nil

自增/自減

INCR KEY_Name
Incr 命令將 key 中儲存的數字值增1。如果 key 不存在,那麼 key 的值會先被初始化爲 0 ,然後再執行 INCR 操作
INCRBY KEY_Name 增量值
Incrby 命令將 key 中儲存的數字加上指定的增量值
DECR KEY_NAMEDECYBY KEY_NAME 減值
decR 命令將 key 中儲存的數字減1

Hash類型

Redis hash 是一個string類型的fieldvalue的映射表,hash特別適合用於存儲對象。

hash類型類似於Java中對象的概念,允許有多個字段

賦值語法

HSET KEY FIELD VALUE

爲指定的KEY,設定FILD/VALUE
HMSET KEY FIELD VALUE [FIELD1,VALUE1]……

同時將多個 field-value (域-值)對設置到哈希表 key 中

取值語法

HGET KEY FIELD

獲取存儲在HASH中的值,根據FIELD得到VALUE
HMGET key field[field1]

獲取key所有給定字段的值
HGETALL key

返回HASH表中所有的字段和值

刪除語法

HDEL KEY field1[field2]

刪除一個或多個HASH表字段

其它語法

HSETNX key field value
只有在字段 field 不存在時,設置哈希表字段的值

HINCRBY key field increment
爲哈希表 key 中的指定字段的整數值加上增量 increment 。

HINCRBYFLOAT key field increment
爲哈希表 key 中的指定字段的浮點數值加上增量 increment 。

HEXISTS key field

查看哈希表 key 中,指定的字段是否存在

List類型

賦值語法

LPUSH key value1 [value2]

將一個或多個值插入到列表頭部(從左側添加)
RPUSH key value1 [value2]

在列表中添加一個或多個值(從右側添加)
LPUSHX key value

將一個值插入到已存在的列表頭部。如果列表不在,操作無效
RPUSHX key value

一個值插入已存在的列表尾部(最右邊)。如果列表不在,操作無效。

取值語法

LLEN key

獲取列表長度
LINDEX key index

通過索引獲取列表中的元素
LRANGE key start stop

獲取列表指定範圍內的元素

描述: 返回列表中指定區間內的元素,區間以偏移量 STARTEND 指定。 其中 0 表示列表的第一個元素, 1 表示列表的第二個元素,以此類推。也可以使用負數下標,以 -1 表示列表的最後一個元素, -2 表示列表的倒數第二個元素,以此類推。
start: 頁大小*(頁數-1)
stop : (頁大小*頁數)-1

刪除語法

LPOP key

移出並獲取列表的第一個元素(從左側刪除)
RPOP key

移除列表的最後一個元素,返回值爲移除的元素(從右側刪除)

BLPOP key1 [key2 ] timeout
移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。
實例
redis 127.0.0.1:6379> BLPOP list1 100
在以上實例中,操作會被阻塞,如果指定的列表 key list1 存在數據則會返回第一個元素,否則在等待100秒後會返回 nil 。

BRPOP key1 [key2 ] timeout
移出並獲取列表的最後一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

LTRIM key start stop

對一個列表進行修剪(trim),就是說,讓列表只保留指定區間內的元素,不在指定區間之內的元素都將被刪除。

修改語法

LSET key index value

通過索引設置列表元素的值
LINSERT key BEFORE|AFTER world value

在列表的元素前或者後插入元素
描述:將值 value 插入到列表 key 當中,位於值 world 之前或之後。

如果有多個相同的值,取第一個

高級語法

RPOPLPUSH source destination
移除列表的最後一個元素,並將該元素添加到另一個列表並返回
示例描述:
RPOPLPUSH a1 a2 //a1的最後元素移到a2的左側
RPOPLPUSH a1 a1 //循環列表,將最後元素移到最左側

BRPOPLPUSH source destination timeout
從列表中彈出一個值,將彈出的元素插入到另外一個列表中並返回它; 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。

Set類型

賦值語法

SADD key member1 [member2] 向集合添加一個或多個成員

取值語法

SCARD key

獲取集合的成員數
SMEMBERS key

返回集合中的所有成員
SISMEMBER key member

判斷 member 元素是否是集合 key 的成員(開發中:驗證是否存在判斷)
SRANDMEMBER key [count]

返回集合中一個或多個隨機數

刪除語法

SREM key member1 [member2]

移除集合中一個或多個成員
SPOP key [count]

移除並返回集合中的一個隨機元素
SMOVE source destination member
member 元素從 source 集合移動到 destination 集合

差集語法

SDIFF key1 [key2]

返回給定所有集合的差集(左側)
SDIFFSTORE destination key1 [key2]

返回給定所有集合的差集並存儲在 destination

交集語法

SINTER key1 [key2]

返回給定所有集合的交集(共有數據)
SINTERSTORE destination key1 [key2]

返回給定所有集合的交集並存儲在 destination

並集語法

SUNION key1 [key2]

返回所有給定集合的並集
SUNIONSTORE destination key1 [key2]

所有給定集合的並集存儲在 destination 集合中

ZSET類型

賦值語法
ZADD key score1 member1 [score2 member2]
向有序集合添加一個或多個成員,或者更新已存在成員的分數

取值語法
ZCARD key

獲取有序集合的成員數
ZCOUNT key min max

計算在有序集合中指定區間分數的成員數
ZRANK key member

返回有序集合中指定成員的索引
ZRANGE key start stop [WITHSCORES]
通過索引區間返回有序集合成指定區間內的成員(低到高)
ZREVRANGE key start stop [WITHSCORES]
返回有序集中指定區間內的成員,通過索引,分數從高到底

刪除語法
del key

移除集合
ZREM key member [member ...]

移除有序集合中的一個或多個成員
ZREMRANGEBYRANK key start stop

移除有序集合中給定的排名區間的所有成員(第一名是0)(低到高排序)
ZREMRANGEBYSCORE key min max

移除有序集合中給定的分數區間的所有成員

HyperLogLog

HyperLogLog是Redis的高級數據結構,是統計基數的利器。

PFADD key element [element …]

將任意數量的元素添加到指定的 HyperLogLog 裏面。

PFCOUNT key [key …]

PFCOUNT]命令作用於單個鍵時, 返回儲存在給定鍵的 HyperLogLog 的近似基數, 如果鍵不存在, 那麼返回 0

PFMERGE destkey sourcekey [sourcekey …]

將多個 HyperLogLog 合併(merge)爲一個 HyperLogLog , 合併後的 HyperLogLog 的基數接近於所有輸入 HyperLogLog 的可見集合(observed set)的並集。

Redis 的訂閱

訂閱頻道
SUBSCRIBE channel [channel ...]

訂閱給定的一個或多個頻道的信息
PSUBSCRIBE pattern [pattern ...]

訂閱一個或多個符合給定模式的頻道。
發佈頻道
PUBLISH channel message

將信息發送到指定的頻道。
退訂頻道
UNSUBSCRIBE [channel [channel ...]]

指退訂給定的頻道。
PUNSUBSCRIBE [pattern [pattern ...]]

退訂所有給定模式的頻道。

Redis 的數據庫

FLUSHALL

清空整個 Redis 服務器的數據(刪除所有數據庫的所有 key )。

FLUSHDB

清空當前數據庫中的所有 key。

此命令從不失敗。

SELECT INDEX

用於切換到第index個數據庫。

Redis的事務

  1. Redis 事務可以一次執行多個命令(允許在一次單獨的步驟中執行一組命令),並且帶有以下兩個重要的保證:
  • 批量操作在發送 EXEC 命令前被放入隊列緩存。
  • 收到 EXEC 命令後進入事務執行,事務中任意命令執行失敗,其餘的命令依然被執行。
  • 在事務執行過程,其他客戶端提交的命令請求不會插入到事務執行命令序列中。

Redis 不支持回滾(roll back)

DISCARD
取消事務,放棄執行事務塊內的所有命令。
EXEC
執行所有事務塊內的命令。
MULTI
標記一個事務塊的開始。
UNWATCH
Redis Unwatch 命令用於取消 WATCH 命令對所有 key 的監視。
如果在執行WATCH命令之後,EXEC命令或DISCARD命令先被執行的話,那就不需要再執行UNWATCH

WATCH key [key ...]
監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。

Redis數據淘汰策略

redis 提供6種數據淘汰策略:

  • volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
  • volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
  • volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
  • allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
  • allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
  • no-enviction(驅逐):禁止驅逐數據

Redis 的持久化

Redis有兩種持久化的方式:快照(RDB文件)和追加式文件(AOF文件)

RDB

RDB持久化方式會在一個特定的間隔保存那個時間點的一個數據快照。

工作原理

  • Redis調用fork(),產生一個子進程。
  • 子進程把數據寫到一個臨時的RDB文件。
  • 當子進程寫完新的RDB文件後,把舊的RDB文件替換掉。

優點

  • RDB文件是一個很簡潔的單文件,它保存了某個時間點的Redis數據,很適合用於做備份。你可以設定一個時間點對RDB文件進行歸檔,這樣就能在需要的時候很輕易的把數據恢復到不同的版本。
  • 基於上面所描述的特性,RDB很適合用於災備。單文件很方便就能傳輸到遠程的服務器上。
  • RDB的性能很好,需要進行持久化時,主進程會fork一個子進程出來,然後把持久化的工作交給子進程,自己不會有相關的I/O操作。

缺點

  • RDB容易造成數據的丟失。假設每5分鐘保存一次快照,如果Redis因爲某些原因不能正常工作,那麼從上次產生快照到Redis出現問題這段時間的數據就會丟失了。
  • RDB使用fork()產生子進程進行數據的持久化,如果數據比較大的話可能就會花費點時間,造成Redis停止服務幾毫秒。如果數據量很大且CPU性能不是很好的時候,停止服務的時間甚至會到1秒。

AOF

每當Redis接受到會修改數據集的命令時,就會把命令追加到AOF文件裏,當你重啓Redis時,AOF裏的命令會被重新執行一次,重建數據。

優點

  • 比RDB可靠。你可以制定不同的fsync策略:不進行fsync、每秒fsync一次和每次查詢進行fsync。默認是每秒fsync一次。這意味着你最多丟失一秒鐘的數據。
  • AOF日誌文件是一個純追加的文件。就算是遇到突然停電的情況,也不會出現日誌的定位或者損壞問題。甚至如果因爲某些原因(例如磁盤滿了)命令只寫了一半到日誌文件裏,我們也可以用redis-check-aof這個工具很簡單的進行修復。
  • 當AOF文件太大時,Redis會自動在後臺進行重寫。重寫很安全,因爲重寫是在一個新的文件上進行,同時Redis會繼續往舊的文件追加數據。新文件上會寫入能重建當前數據集的最小操作命令的集合。當新文件重寫完,Redis會把新舊文件進行切換,然後開始把數據寫到新文件上。
  • AOF把操作命令以簡單易懂的格式一條接一條的保存在文件裏,很容易導出來用於恢復數據。例如我們不小心用FLUSHALL命令把所有數據刷掉了,只要文件沒有被重寫,我們可以把服務停掉,把最後那條命令刪掉,然後重啓服務,這樣就能把被刷掉的數據恢復回來。

缺點

  • 在相同的數據集下,AOF文件的大小一般會比RDB文件大。
  • 在某些fsync策略下,AOF的速度會比RDB慢。通常fsync設置爲每秒一次就能獲得比較高的性能,而在禁止fsync的情況下速度可以達到RDB的水平。
  • 在過去曾經發現一些很罕見的BUG導致使用AOF重建的數據跟原數據不一致的問題。

Redis 和mysql同步方案

緩存問題

緩存穿透

請求去查詢一條壓根兒數據庫中根本就不存在的數據,也就是緩存和數據庫都查詢不到這條數據,但是請求每次都會打到數據庫上面去。這種查詢不存在數據的現象我們稱爲緩存穿透

穿透帶來的問題

如果有黑客會對你的系統進行攻擊,拿一個不存在的id 去查詢數據,會產生大量的請求到數據庫去查詢。可能會導致你的數據庫由於壓力過大而宕掉。

解決方案

  1. 緩存空值

    之所以會發生穿透,就是因爲緩存中沒有存儲這些空數據的key。從而導致每次查詢都到數據庫去了。那麼我們就可以爲這些key對應的值設置爲null 丟到緩存裏面去。後面再出現查詢這個key 的請求的時候,直接返回null 。

  2. 布隆過濾器

    這種方案可以加在第一種方案中,在緩存之前在加一層 BloomFilter ,在查詢的時候先去 BloomFilter 去查詢 key 是否存在,如果不存在就直接返回,存在再走查緩存 -> 查 DB。

緩存擊穿

在平常高併發的系統中,大量的請求同時查詢一個 key 時,此時這個key正好失效了,就會導致大量的請求都打到數據庫上面去。這種現象我們稱爲緩存擊穿

擊穿帶來的問題

會造成某一時刻數據庫請求量過大,壓力劇增。

解決方案

上面的現象是多個線程同時去查詢數據庫的這條數據,那麼我們可以在第一個查詢數據的請求上使用一個 互斥鎖來鎖住它。其他的線程走到這一步拿不到鎖就等着,等第一個線程查詢到了數據,然後做緩存。後面的線程進來發現已經有緩存了,就直接走緩存。

緩存雪崩

緩存雪崩的情況是說,當某一時刻發生大規模的緩存失效的情況,比如你的緩存服務宕機了,會有大量的請求進來直接打到DB上面。

緩存雪崩帶來的問題

DB 稱不住,掛掉。

解決方案

  1. 使用集羣緩存,保證緩存服務的高可用

  2. ehcache本地緩存 + Hystrix限流&降級,避免MySQL被打死

  3. 開啓Redis持久化機制,儘快恢復緩存集羣

解決熱點數據集中失效問題

我們在設置緩存的時候,一般會給緩存設置一個失效時間,過了這個時間,緩存就失效了。

對於一些熱點的數據來說,當緩存失效以後會存在大量的請求過來,然後打到數據庫去,從而可能導致數據庫崩潰的情況。

解決辦法

  1. 設置不同的失效時間

爲了避免這些熱點的數據集中失效,那麼我們在設置緩存過期時間的時候,我們讓他們失效的時間錯開。

比如在一個基礎的時間上加上或者減去一個範圍內的隨機值。

  1. 互斥鎖

結合上面的擊穿的情況,在第一個請求去查詢數據庫的時候對他加一個互斥鎖,其餘的查詢請求都會被阻塞住,直到鎖被釋放,從而保護數據庫。

但是也是由於它會阻塞其他的線程,此時系統吞吐量會下降。需要結合實際的業務去考慮是否要這麼做。

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