數據類型
String:Map<String,String>
命令格式
set key value(相同的key會覆蓋)
get key
incr key
decr key
setex key seconds value seconds秒后失效
ttl key
del key
setnx ke value(if not exist)
應用場景
計數器
比如:訪問次數,減少mysql訪問
共享session
用戶登錄后將信息存儲在共享redis緩存層中
Hash:Map<String,HashMap<String,String>>使用ziplist和hash表來實現
命令格式
hset key filed value
hget key filed
hexist key field
hvals key
hkeys key
hgetall key
hincrby key field increment
hdel key filed
應用場景
存儲對象,代替String,String是使用的json來存儲對象,而hash使用一個hashmap來存儲對象,filed-value這樣,將對象存儲在hash比存儲在String空間小。
session也可以用hash存儲。
當使用string存儲對象,需要將對象轉換為json(所以查更容易,而修改某一字段需要轉為對象然后再轉為json),而用hash,查詢需要自己做序列化(但是修改某一字段容易)
List:Map<String,List >使用ziplist和雙向鏈表來實現
命令格式
rpush key value
lpush key value
rpop key
lpop key
llen key
lrange key start stop//如果是[0,-1]則是所有數據
List相當于一個雙端隊列來使用的,也可以從中間插入和刪除數據但是不常用
應用場景
常用于單key,多value
用戶收藏列表
Set:Map<String,Set>用intset和哈希表實現
無序,不重復,單key,多value
命令格式
sadd key [members]
smembers key 遍歷所有
srem key [members]
spop key count 隨機彈出key
特點
差集,并集,交集
sdiff key1 key2
sunion key1 key2
sinter key1 key2
應用場景
去重
抽獎:pop
Zset: Map<String,Set>跳表和哈希表
每個元素都有一個double的分數(在add時必須添加),然后用分數做key排序
zset的插入流程
會先在hash表中查找該元素是否存儲,如果存在則更新分數,然后在跳表中重新插入。
如果不存在,則插入跳表和hash表。
操作指令
zadd key scrose value
zincrby key increment member
zrange key start stop [withscores]
zrevrange key start stop
zcard key 數量
zrank key member member的排名
zrevrank key member member的逆序排名
范圍刪除,返回范圍等操作
應用場景
排行榜
延遲隊列,定時任務
優先級隊列
各種數據類型的效率
String插入O1,查詢O1
Hash插入O1,查詢O1
List插入O1,查詢On
Set插入O1,查詢O1
ZSet插入Ologn,查詢Ologn/nlogn
當使用成員查看排名時rank,先用hash定位在跳表中的位置,然后遍歷跳表,查看其排名,所以是logn
當查看zrange一定排名的成員時,過程和rank相似
設計redis
如果需要一個map形式的緩存,并且本地Map不太合適:
redis集群,分片,保證了數據的高可用和高可靠
redis有持久化機制
高效了數據結構
Lua腳本
分布式鎖
過期鍵
設計v
是否需要排序:zset
單value還是多value?
多value:List,hash,set
單value:string
不允許重復:set
設計key
唯一性
可讀性
模塊名:數據名:主鍵id
表名:主鍵名:主鍵值:列名
全局命令
key pattern
exists key
type key
expire key seconds
perist key
select 0-15 選數據庫
randomkey 一個隨機key
rename key newname
dbsize
redis事務
單個redis命令是原子性的,因為redis單線程,執行完一個命令才會執行下一個。
redis存在事務的概念,但是只是一個執行腳本包,不支持事務的回滾等。
加入隊列,順序執行任務。如果在此期間有其他命令插入,需要等待事務執行完畢。
multi
command:queued
command:queued
command:queued
exec
持久化
RDB
使用save(阻塞)或者bgsave(子進程)來創建一個新的rdb文件。
間隔RDB自動保存
redis每個數據庫都會保存上次save時間以及期間做的dirty次數。
save 100 2 如果100有兩個修改,則會調用save
RDB二進制文件內容
下面是RDB文件的內容:
redis:db_version:selectdb:0:paris:selectdb:3:pairs:EOF:check_sum
selectdb:0代表0號數據庫,pairs中存儲鍵值對和過期時間(如果有)
AOF
將用戶的命令記錄到文件中。
當啟用AOF時,載入數據庫時就會優先載入AOF而不是RDB
格式
set msg “hello”
/r/nset/r/n$3/r/nmsg/r/n$5/r/nhello/r/n
AOF的實現流程:命令追加,文件寫入,文件同步
命令追加:每次執行完一個命令后,就會將其加入aof_buf緩沖區尾部。
AOF文件寫入和同步:時間事件的AOF寫入觸發時,會將aof_buf的數據寫入aof,并且文件同步。
aof文件寫入策略:
(1)always : 每次寫入aof_buf都會寫入并且同步aof落到磁盤。
(2)everysec:每秒寫入aof文件,但是每秒才會將最新的aof文件修改落到磁盤。
(3)no:有操作系統完成aof落磁盤
AOF文件載入
依次執行AOF文件中的內容
AOF文件重寫:不會阻塞
會讀數據庫,然后創建aof語句。
Redis中的過期刪除策略
redis可以減少mysql的讀操作,減少磁盤io。
但是內存如果只放不刪,遲早會滿。
所以Redis設置了一個屬于每個數據庫的過期字典。
設置過期時間來判定鍵是否過期
設置過期時間:expire key second
查看過期時間:ttl key
移除過期時間:persist key
過期字典:key是鍵對象指針,value是long類型的UNIX時間戳
檢查鍵是否過期
檢查該鍵是否存在于過期字典,如果存在獲得該鍵的過期時間。檢查當前UNIX時間戳是否大于鍵的ttl,如果大于則過期
過期鍵刪除策略:如果一個鍵過期了,那么它什么時候被刪除
redsi使用:惰性刪除+定期刪除(每隔一段時間就掃描一些過期鍵空間)
采用隨機掃描,而不是順序記錄掃描
設置的參數:
hz 20 (config set hz 20):每秒掃描20次
active-expire-effort 1 : 每次掃描的努力情況,越大掃描越徹底
RDB對過期鍵的處理
在生成RDB文件時,會檢查鍵是否過期,如果過期,則不會放入RDB文件中。
載入RDB文件中對過期鍵的處理
如果過期,不會載入
AOF對過期鍵的處理
當一個鍵被過期刪除時,會向AOF文件中寫入一條del命令
AOF重寫對過期鍵的處理
重寫時,過期則不會寫入AOF文件
集群模式下的鍵過期
集群下,從服務器不會主動刪除過期鍵(惰性和定期都不會),主服務器檢測到過期鍵會向從服務器發生del命令。
通過主服務器控制所有過期鍵,可以保證主從一致性,當一個過期鍵在主服務器中沒有被刪除,那么從服務器中也一定沒有被刪除(此時客戶端仍然可以讀到)。
Redis的內存淘汰策略(主動刪除,即使是一些鍵沒有到達ttl也會被刪除)
當reids使用的內存空間超過設置的最大內存空間,就會使用內存淘汰策略:
配置:
maxmemory 256mb (config set maxmemory 256mb)
maxmemory-policy allkeys-lru
觸發內存淘汰策略是漸進式的,分階段回收內存的,避免長時間阻塞
處理設置了過期時間的數據
volatile-lru(最近最少使用,維持一個LRU的隊列)
volatile-ttl(設置了過期時間的,剩余存活時間最短的鍵)(鍵有一個訪問頻率的計數器,并且使用了時間衰減機制)
volatile-lfu(最不常使用)
volatile-random
LFU:A最近調用了3次(時間無關,次數有關)
LRU:A在3秒前調用了一次(時間相關)
處理全部數據
allkeys-lru
allkeys-lfu
allkeys-random
不處理,直接報錯異常
no-enviction