Redis五大數(shù)據(jù)類型及其常用操作
字符串
set key value ——設(shè)置屬性值
get key ——獲取值
getset key value ——先獲取值再重新設(shè)置值
del key ——?jiǎng)h除
incr key ——自增,如果key不存在,則會創(chuàng)建一個(gè)值為0的變量
decr key ——自減
incrby key number ——變量+number
decrby key number ——變量-number
append key string ——追加字符串
getrange key start end ——獲取[start,end]之間的字符串
setrange key offset value ——將從offset開始的子串設(shè)置為給定值
bitcount key [ start end ] ——統(tǒng)計(jì)二進(jìn)制位串指定范圍內(nèi)的1的二進(jìn)制位的數(shù)量
Hash
hset key k v ——設(shè)置某個(gè)key下的鍵值對
hmset key k v k v... ——設(shè)置某個(gè)key下的幾個(gè)鍵值對
hget key k ——獲取某個(gè)key下的鍵值
hmget key k k... ——獲取某個(gè)key下的幾個(gè)鍵值
hgetall key ——獲取某個(gè)key下的所有鍵值對
hdel key k k ... ——?jiǎng)h除某個(gè)key下的多個(gè)鍵值
hincrby key k number ——給某個(gè)key下的某個(gè)鍵值+number
hexists key k ——判斷某個(gè)鍵是否存在 (1——存在集币,0——不存在)
hlen key ——獲取key的屬性個(gè)數(shù)
hkeys key ——獲取key的所有鍵名稱
hvals key ——獲取key的所有值
list
lpush key v v v ——從左側(cè)插入鏈表
rpush key v v v ——從右側(cè)插入鏈表
lrange key start end —— 返回[start,end]之間的元素
lpop key ——左端彈出
rpop key ——右端彈出
llen key ——獲取鏈表元素個(gè)數(shù)
lpushx key v ——如果key存在則插入到頭部
rpushx key v ——如果key存在則插入到尾部
lrem key number v —— 刪除key中number個(gè)v(number為負(fù)表示從后往前手幢,0表示所有)
lset key index v ——在key的index的位置處設(shè)置v值
linsert key before v1 v2 ——在第一個(gè)v1之前插入v2
linsert key after v1 v2 ——在第一個(gè)v1之后插入v2
rpoplpush key1 key2——將key1的值彈出壓入key
lindex key index ——獲取列表中給定位置上的單個(gè)元素(從0開始)
ltrim key start end ——只保留[start,end]之間的元素
blpop key timeout ——彈出最左端的元素谷市,如果元素不存在將阻塞timeout秒并等待可彈出的元素出現(xiàn)
brpop key timeout ——彈出最右端的元素,如果元素不存在將阻塞timeout秒并等待可彈出的元素出現(xiàn)
rpoplpush source-key dest-key ——將source-key中最右端的元素彈出,壓入到dest-key的最左端
brpoplpush source-key dest-key timeout ——將source-key中最右端的元素彈出,壓入到dest-key的最左端癌幕,如果source-key中元素不存在,將阻塞timeout秒并等待可彈出的元素出現(xiàn)
set
sadd key v v v... ——往集合里面添加元素
srem key v v v ...——?jiǎng)h除
smembers key ——查看
sisimember key v ——判斷是否存在
sdiff key1 key2 ——找出key1中在key2不存在的元素
sinter key1 key2 ——交集
sunion key1 key2 —— 并集
scard key ——數(shù)目
srandmember key——隨機(jī)返回
sdiffstore key1 key2 key3 ——把key2和key3的差集保存到key1
sinterstore key1 key2 key3 ——把key2和key3的交集保存到key1
sunionstore key1 key2 key3 ——把key2和key3的并集保存到key1
spop key ——隨機(jī)移除集合中的一個(gè)元素
smove source-key dest-key item ——如果集合source-key包含元素item昧穿,那么從集合source-key里面移除元素item勺远,并將元素item添加到集合dest-key中
zset(sorted-set)
zadd key n v n v ——添加元素和相應(yīng)的分?jǐn)?shù)
zscore key v ——查看分?jǐn)?shù)
zcard key ——獲取長度
zrem key v v ——?jiǎng)h除
zrange key start end —— 獲取指定位置范圍內(nèi)的值
zrange key start end withscores ——獲取指定范圍內(nèi)的值和分?jǐn)?shù)
zrevrange key start end withscores
zremrangebyrank key start end ——下標(biāo)范圍刪除
zremrangebyscore key starts ends ——分?jǐn)?shù)范圍刪除
zincrby key number v ——v+number
zcount key starts ends ——分?jǐn)?shù)范圍內(nèi)的個(gè)數(shù)
zrank key v —— 返回成員v在有序集合中的排名
常用操作:
keys * ——獲取所有key
del key1 key2 ——?jiǎng)h除
exists key ——是否存在
rename key1 key2 ——重命名
expire key time ——設(shè)置過期時(shí)間
ttl key ——查看剩余時(shí)間
type key——查看類型
select number ——選擇數(shù)據(jù)庫(0-15)
move key number ——將變量移到number數(shù)據(jù)庫
hypeloglog
- pfadd key v v v :影響基數(shù)估值則返回1否則返回0.若key不存在則創(chuàng)建
- pfcount key :得到去重后的值
- pfmerge destkey key key2:合并多個(gè)key
bitmap
- setbit key index v : 設(shè)置值
- getbit key index :獲取值
- bitcount key [start,end] :獲取某個(gè)范圍的1的個(gè)數(shù)
- bitop op destkey key (op = or,and,not,xor) bitmap 之間的運(yùn)算
發(fā)布與訂閱
subscribe channel [channer...] ——訂閱給定的一個(gè)或多個(gè)頻道
unsubscribe [channer...] ——退訂給定的一個(gè)或多個(gè)頻道,如果沒有指定时鸵,那么退訂所有頻道
publish channel message ——向給定頻道發(fā)送消息
psubscribe pattern [pattern...] ——訂閱與給定模式相匹配的所有頻道
punsubscribe [pattern...] —— 退訂給定的模式胶逢,如果未指定,則退訂所有的模式
Redis注意點(diǎn)
- 如果用戶對一個(gè)不存在的鍵或者一個(gè)保存了空串的鍵執(zhí)行自增或者自減操作,那么Redis在執(zhí)行操作時(shí)會將這個(gè)鍵的值當(dāng)作是0來處理初坠。如果用戶嘗試對一個(gè)值無法被解釋為整數(shù)或者浮點(diǎn)數(shù)的字符串鍵執(zhí)行自增或者自減操作和簸,那么Redis將向用戶返回一個(gè)錯(cuò)誤。
Redis使用案例
從海量數(shù)據(jù)中查詢某一前綴的key
方法一:利用key查找(不推薦)
keys pattern:查找所有符合給定模式pattern的key
通過這種方式查詢可能會導(dǎo)致查詢時(shí)間過長某筐,導(dǎo)致redis其他服務(wù)卡頓比搭。
方法二:利用scan查找(推薦)
scan cursor [MATCH pattern] [COUNT count]
- 基于游標(biāo)的迭代器,需要基于上一次的游標(biāo)延續(xù)之前的迭代過程南誊;
- 以0作為游標(biāo)開始一次新的迭代,直到命令返回游標(biāo)0完成一次遍歷蜜托;
- 不保證每次執(zhí)行都返回某個(gè)給定數(shù)量的元素抄囚,支持模糊查詢;
- 一次返回的數(shù)量不可控橄务,只能是大概率符合count參數(shù)幔托。
如何通過Redis實(shí)現(xiàn)分布式鎖
方法一
setnx key value :如果key不存在,則創(chuàng)建并賦值
- 時(shí)間復(fù)雜度:O(1)
- 返回值:設(shè)置成功蜂挪,返回1重挑;設(shè)置失敗,返回0棠涮。
expire key seconds
- 設(shè)置key的生存時(shí)間谬哀,當(dāng)key過期時(shí)(生存時(shí)間為0),會被自動刪除严肪。
方法二
set key value [EX seconds] [PX milliseconds] [NX|XX]
- EX second :設(shè)置鍵的過期時(shí)間為second秒
- PX millisecond:設(shè)置鍵的過期時(shí)間為millisecond毫秒
- NX:只有鍵不存在時(shí)史煎,才對鍵進(jìn)行設(shè)置操作
- XX:只在鍵已經(jīng)存在時(shí),才對鍵進(jìn)行設(shè)置操作
- SET操作成功完成時(shí)驳糯,返回OK篇梭,否則返回nil
RDB和AOF
由于Redis是內(nèi)存數(shù)據(jù)庫,它將自己的數(shù)據(jù)庫狀態(tài)存儲在內(nèi)存中酝枢,如果不想辦法將存儲在內(nèi)存中的數(shù)據(jù)庫狀態(tài)保存到磁盤里面恬偷,那么一旦服務(wù)器進(jìn)程退出,服務(wù)器中的數(shù)據(jù)庫狀態(tài)也會消失不見帘睦。
RDB
- SAVE:會阻塞Redis服務(wù)器進(jìn)程袍患,直到RDB文件創(chuàng)建完成為止,在服務(wù)器進(jìn)程阻塞期間官脓,服務(wù)器不能處理任何命令請求协怒。
- BGSAVE:會派生出一個(gè)子進(jìn)程,然后由子進(jìn)程負(fù)責(zé)創(chuàng)建RDB文件卑笨,父進(jìn)程進(jìn)行處理命令請求孕暇。
一旦BGSAVE開始執(zhí)行了,SAVE命令和BGSAVE命令都會被服務(wù)器拒絕,避免產(chǎn)生競爭條件妖滔。如果BGSAVE命令正在執(zhí)行隧哮,那么客戶端發(fā)送的BGREWRITEAOF命令會被延遲到BGSAVE命令執(zhí)行完畢之后執(zhí)行;如果BGREWRITEAOF命令正在執(zhí)行座舍,那么客戶端發(fā)送的BGSAVE命令會被服務(wù)器拒絕沮翔。避免產(chǎn)生大量的磁盤寫入操作。
將某段時(shí)間內(nèi)的所有數(shù)據(jù)持久化到磁盤中曲秉,類似快照的行為采蚀。當(dāng)在進(jìn)行持久化的過程時(shí)有數(shù)據(jù)的更新,會把這些記錄保存到備份文件中承二,最后會把備份文件拿來替換原文件榆鼠。
缺點(diǎn):如果機(jī)器發(fā)生故障,容易丟失某個(gè)時(shí)間段內(nèi)的數(shù)據(jù)亥鸠。
AOF
**將所有寫命令保存到AOF緩沖區(qū)中妆够,根據(jù)appendfsync的值(默認(rèn)為everysec)來對AOF文件同步,由于大量的寫入命令會導(dǎo)致AOF文件過大负蚊,后臺就會開啟一個(gè)子進(jìn)程對原AOF文件進(jìn)行重寫(合并命令)神妹,對文件進(jìn)行壓縮。如果在重寫期間執(zhí)行了寫入命令家妆,會將寫入命令保存到AOF重寫緩沖區(qū)中鸵荠,等到AOF重寫結(jié)束,再將AOF重寫緩沖區(qū)中的內(nèi)容追加到新AOF文件中揩徊,此時(shí)會對父進(jìn)程阻塞腰鬼,最后用新AOF文件替換原AOF文件。
缺點(diǎn):由于恢復(fù)要進(jìn)行的操作較多塑荒,可能會導(dǎo)致主線程阻塞熄赡。
主從配置(docker無redis.conf)
- docker啟動主redis: docker run -d --name redis-master -p 6379:6379 redis --requirepass "mypassword"
- docker啟動從redis: docker run -d --name redis-slave -p 6380:6379 redis --requirepass "mypassword"
-
連接從redis并進(jìn)行配置:
1. auth <slave-password>
2. slaveof <master-ip> <master-port>。<master-ip>為主庫服務(wù)ip齿税,<master-port>表示主庫所在端口彼硫,默認(rèn)6379
3. config set masterauth <master-password>。<master-password>即為主庫訪問密碼
redis.conf相關(guān)配置
##設(shè)置當(dāng)本機(jī)為slav服務(wù)時(shí)凌箕,設(shè)置master服務(wù)的IP地址及端口拧篮,在Redis啟動時(shí),它會自動從master進(jìn)行數(shù)據(jù)同步
slaveof <masterip> <masterport>
###當(dāng)master服務(wù)設(shè)置了密碼保護(hù)時(shí)牵舱,slave服務(wù)連接master的密碼
masterauth <master-password>
##你可以配置salve實(shí)例是否接受寫操作串绩。可寫的slave實(shí)例可能對存儲臨時(shí)數(shù)據(jù)比較有用(因?yàn)閷懭雜alve
##的數(shù)據(jù)在同master同步之后將很容易被刪除
slave-read-only yes
# 是否在slave套接字發(fā)送SYNC之后禁用 TCP_NODELAY芜壁?
# 如果你選擇“yes”Redis將使用更少的TCP包和帶寬來向slaves發(fā)送數(shù)據(jù)礁凡。但是這將使數(shù)據(jù)傳輸?shù)絪lave
# 上有延遲高氮,Linux內(nèi)核的默認(rèn)配置會達(dá)到40毫秒
# 如果你選擇了 "no" 數(shù)據(jù)傳輸?shù)絪alve的延遲將會減少但要使用更多的帶寬
repl-disable-tcp-nodelay no
# slave的優(yōu)先級是一個(gè)整數(shù)展示在Redis的Info輸出中。如果master不再正常工作了顷牌,哨兵將用它來
# 選擇一個(gè)slave提升=升為master剪芍。
# 優(yōu)先級數(shù)字小的salve會優(yōu)先考慮提升為master,所以例如有三個(gè)slave優(yōu)先級分別為10窟蓝,100罪裹,25,
# 哨兵將挑選優(yōu)先級最小數(shù)字為10的slave运挫。
# 0作為一個(gè)特殊的優(yōu)先級状共,標(biāo)識這個(gè)slave不能作為master,所以一個(gè)優(yōu)先級為0的slave永遠(yuǎn)不會被
# 哨兵挑選提升為master
slave-priority 100
緩存穿透和緩存雪崩
- 緩存穿透:指大量查詢不再緩存中存在的數(shù)據(jù)谁帕,此時(shí)會直接查詢數(shù)據(jù)庫口芍。
解決方法:
1.采用布隆過濾器
2.為不存在的數(shù)據(jù)設(shè)置空值
- 緩存雪崩:大量緩存數(shù)據(jù)過期。
解決方法:
1.加鎖排隊(duì)
2.
布隆過濾器
首先構(gòu)建長度足夠的位陣列雇卷,所有位置的值都為0,然后創(chuàng)建m個(gè)hash函數(shù)颠猴,將所有元素根據(jù)m個(gè)hash函數(shù)得到的指定位位置的值都置為1关划。查詢的時(shí)候,同樣根據(jù)m個(gè)hash函數(shù)得到位位置的值翘瓮,只要其中有0贮折,說明一定不含有該元素,全為1則可能含有资盅。
Redis淘汰機(jī)制
當(dāng)客戶端發(fā)起了需要申請更多內(nèi)存的命令调榄;Redos檢查內(nèi)存使用情況,如果已使用的內(nèi)存大于maxmemory則開始根據(jù)用戶配置的不同淘汰策略來淘汰內(nèi)存呵扛,從而換取一定的內(nèi)存每庆;如果之前都沒問題,則這個(gè)命令執(zhí)行成功今穿。
- Volatile-lru:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰缤灵;
- Volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰;
- Volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰蓝晒;
- Allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰腮出;
- Allkeys-random:從數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰;
- no-enviction:禁止淘汰數(shù)據(jù)芝薇。
redis怎么自己實(shí)現(xiàn)線程安全的自增胚嘲?
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
通過watch命令來對一個(gè)變量進(jìn)行監(jiān)測。如果一個(gè)變量已經(jīng)被監(jiān)測洛二,當(dāng)變量被修改馋劈,之后的事務(wù)就不會執(zhí)行攻锰。
redis cluster
slot(槽)
redis cluster中有16384個(gè)slot。正常工作的時(shí)候侣滩,每個(gè)Master節(jié)點(diǎn)都負(fù)責(zé)一部分slot口注,當(dāng)有某個(gè)key被映射到某個(gè)Master負(fù)責(zé)的槽,那么這個(gè)Master負(fù)責(zé)為這個(gè)key提供服務(wù)君珠,至于哪個(gè)Master節(jié)點(diǎn)負(fù)責(zé)哪個(gè)槽寝志,這是可以由用戶指定的。只有Master才擁有槽的所有權(quán)策添,如果是某個(gè)Master的slave材部,這個(gè)slave只負(fù)責(zé)槽的使用,但是沒有所有權(quán)唯竹。
連接節(jié)點(diǎn)
CLUSTER MEET命令:用來連接不同的開啟集群支持的Redis節(jié)點(diǎn)乐导。
過程:
- 如果A節(jié)點(diǎn)接收到meet命令,首先對ip和port進(jìn)行合理性檢查浸颓,然后遍歷nodes物臂,通過判斷對應(yīng)的node是不是處于CLUSTER_NODE_HANDSHAKE狀態(tài),是的話产上,說明是重復(fù)meet棵磷。否則,創(chuàng)建一個(gè)帶HANDSHAKE和MEET標(biāo)記的clusterNode節(jié)點(diǎn)晋涣,添加到nodes中仪媒。
- A節(jié)點(diǎn)通過定時(shí)任務(wù)遍歷nodes,通過判斷node的link是否為null谢鹊,尋找到之前meet命令添加的節(jié)點(diǎn)算吩,向B節(jié)點(diǎn)發(fā)送一個(gè)meet消息。
- 節(jié)點(diǎn)B在接收到節(jié)點(diǎn)A發(fā)送的meet消息佃扼,會將節(jié)點(diǎn)A的信息創(chuàng)建一個(gè)node偎巢,添加到節(jié)點(diǎn)B的nodes中,并向節(jié)點(diǎn)A回復(fù)一個(gè)PONG消息松嘶。
- 節(jié)點(diǎn)A收到節(jié)點(diǎn)B的PONG消息后艘狭,會更新nodes中節(jié)點(diǎn)B的信息,消除HANDSHAKE標(biāo)記翠订。
- 同樣巢音,節(jié)點(diǎn)B在做定時(shí)任務(wù)的時(shí)候,發(fā)現(xiàn)節(jié)點(diǎn)A的link為null尽超,由于沒有meet flag官撼,會向A發(fā)送PING命令。