一妖泄、 Redis簡(jiǎn)介
- redis的優(yōu)點(diǎn)
● 數(shù)據(jù)間沒(méi)有必然的關(guān)聯(lián)關(guān)系
● 內(nèi)部采用單線程機(jī)制
● 高性能
● 多數(shù)據(jù)類型支持(String蹬昌,Hash扇谣,List,Set牲平,ZSet)
● 持久化支持(數(shù)據(jù)恢復(fù)) - redis的應(yīng)用場(chǎng)景
● 為熱點(diǎn)數(shù)據(jù)加速查詢(熱點(diǎn)商品堤框、熱點(diǎn)資訊等)
● 任務(wù)隊(duì)列(秒殺、搶票等)
● 即時(shí)信息查詢(排行榜、在線人數(shù)胰锌、微博粉絲數(shù)等)
● 時(shí)效性信息控制(驗(yàn)證碼等)
● 分布式數(shù)據(jù)共享(分布式session)
● 分布式鎖
● 消息隊(duì)列
二骗绕、 數(shù)據(jù)類型的基本操作
- String類型
● 添加數(shù)據(jù)
set key value
● 獲取數(shù)據(jù)
get key
● 刪除數(shù)據(jù)
del key
● 添加/修改多個(gè)數(shù)據(jù)
mset key1 value1 key2 value2 ...
● 獲取多個(gè)數(shù)據(jù)
mget key1 key2 ...
● 獲取數(shù)據(jù)字符長(zhǎng)度
strlen key
● 追加信息(原始信息存在就追加不存在就新建)
append key value
擴(kuò)展操作
● 設(shè)置數(shù)值增加指定范圍的值(分布式中id的自增)
incr key
incrby key increment
incrbyfloat key increment
● 設(shè)置數(shù)據(jù)減少指定范圍的值
decr key
decrby key increment
● 設(shè)置數(shù)據(jù)具有指定的時(shí)效
setex key seconds value
psetex key millseconds value - Hash類型
存儲(chǔ)對(duì)象類的數(shù)據(jù),底層使用hash表結(jié)構(gòu)實(shí)現(xiàn)(常應(yīng)用于商品購(gòu)物車的實(shí)現(xiàn))
● 添加/修改數(shù)據(jù)
hset key value
● 獲取數(shù)據(jù)
hget key field
hgetall key
● 刪除數(shù)據(jù)
hdel key field1 field2 ...
● 添加/修改多個(gè)數(shù)據(jù)
hmset key field1 value1 field2 value2 ...
● 獲取多個(gè)數(shù)據(jù)
hmget key filed1 field2 ...
● 獲取hash表中字段的數(shù)量
hlen key
● 獲取hash表中是否存在指定的字段
hexists key field
擴(kuò)展操作
● 獲取hash表中所有字段的名和值
hkeys key
hvals key
● 設(shè)置指定字段的數(shù)值數(shù)據(jù)增加指定范圍的值
hincrby key field increment
hincrbyfloat key field increment - List類型
● 添加/修改數(shù)據(jù)
lpush key value1 value2 ...
rpush key value1 value2 ...
● 獲取數(shù)據(jù)
lrang key start stop
lindex key index
llen key
● 刪除并移除數(shù)據(jù)
lpop key
rpop key
擴(kuò)展操作
● 規(guī)定時(shí)間內(nèi)獲取并移除數(shù)據(jù)
blpop key1 key2 ... timeout
brpop key1 key2 ... timeout
● 移除指定數(shù)據(jù)
lrem key count value - Set類型
● 添加數(shù)據(jù)
sadd key memer1 member2 ...
● 獲取全部數(shù)據(jù)
smembers key
● 刪除數(shù)據(jù)
srem key member1 member2
● 獲取集合數(shù)據(jù)總量
scard key
● 判斷集合中是否包含指定數(shù)據(jù)
sismember key member
擴(kuò)展操作
● 隨機(jī)獲取集合中指定數(shù)量的數(shù)據(jù)
srandmember key count - SortedSet類型
● 添加數(shù)據(jù)
zadd key score1 member1 score2 member2 ...
● 獲取全部數(shù)據(jù)
zrange key start stop withscores
zrevrange key start stop withscores
● 刪除數(shù)據(jù)
zrem key member1 member2 ...
● 按條件獲取數(shù)據(jù)
zrangebyscore key min max withscores limit
zrevrangebyscore key max min withscores
● 獲取集合數(shù)據(jù)總量
zcard key
zcount key min max
三资昧、 key的通用操作
● 刪除key
del key
● 獲取key是否存在
exists key
● 獲取key的類型
type key
● 為key設(shè)置有效期
expire key seconds
pexpire key milliseconds
expireat key timestamp
pexpireat key millinseconds-timestamp
● 獲取key的有效時(shí)間
ttl key
pttl key
● 將key從時(shí)效性轉(zhuǎn)換為永久性
persist key
● 通配符查詢key
key * 查詢所有
key name* 查詢所有以name開(kāi)頭的
key ?name 查詢以一個(gè)任意字符開(kāi)頭的name結(jié)尾的
key n[ab]e 查詢以n開(kāi)頭的e結(jié)尾的中間包含字母a或b的
四酬土、 Redis持久化
為了防止數(shù)據(jù)的意外丟失,確保數(shù)據(jù)的安全性格带,需要對(duì)數(shù)據(jù)進(jìn)行持久化撤缴。
Redis中的持久化分為兩種方式RDB(快照)和AOF(過(guò)程日志)
RDB
以數(shù)據(jù)快照的方式進(jìn)行存儲(chǔ)
手動(dòng)執(zhí)行:
save命令:手動(dòng)執(zhí)行一次保存操作(每保存一次會(huì)生成一個(gè).rdb文件)
會(huì)阻塞當(dāng)前的Redis服務(wù)器,直到RDB過(guò)程完成為止叽唱,可能會(huì)造成長(zhǎng)時(shí)間阻塞(不建議使用)
bgsave命令:手動(dòng)啟動(dòng)后臺(tái)保存操作屈呕,但不是立即執(zhí)行,對(duì)阻塞問(wèn)題進(jìn)行了優(yōu)化棺亭,Redis內(nèi)部所有涉及到的RDB的操作都采用bgsave的方式
執(zhí)行過(guò)程:
自動(dòng)執(zhí)行:
更改redis的conf目錄下的redis.conf文件
# 指定端口號(hào)為6379
port 6379
# 設(shè)置redis后臺(tái)運(yùn)行
daemonize yes
# 指定日志文件
logfile "6379.log"
# 文件存儲(chǔ)的位置
dir /redis/data
# 指定快照存儲(chǔ)的名稱
dbfilename dump-6379.rdb
# 設(shè)置壓縮rdb
rdbcompression yes
# 對(duì)rdb的數(shù)據(jù)進(jìn)行校驗(yàn)
rdbchecksum yes
# 每隔10秒有30次增刪改則生成rdb文件
save 10 30
優(yōu)點(diǎn):
RDB是一個(gè)緊湊壓縮的二進(jìn)制文件虎眨,存儲(chǔ)效率高,數(shù)據(jù)恢復(fù)速度比AOF更快
缺點(diǎn):
無(wú)法做到實(shí)時(shí)持久化镶摘,可能會(huì)丟失數(shù)據(jù)嗽桩,每次執(zhí)行需要?jiǎng)?chuàng)建fork子進(jìn)程,消耗性能
AOF
以獨(dú)立日志的方式記錄每次寫命令凄敢,重啟時(shí)再重新執(zhí)行AOF中的命令碌冶,以達(dá)到恢復(fù)數(shù)據(jù)的目的,解決了數(shù)據(jù)持久化的實(shí)時(shí)性問(wèn)題
AOF寫數(shù)據(jù)過(guò)程:
描述:在redis客戶端執(zhí)行寫操作涝缝,服務(wù)器接收到寫操作之后扑庞,將寫命令刷新到緩存區(qū)中,再通過(guò)某種策略拒逮,將命令同步到AOF文件中
AOF寫數(shù)據(jù)的三種策略
● always:每次寫入操作均同步到AOF文件中罐氨,數(shù)據(jù)零誤差,性能較低
● everysec:每秒將緩存中的指令同步到AOF中消恍,準(zhǔn)確性較高岂昭,性能較高,在系統(tǒng)突然宕機(jī)時(shí)會(huì)丟失1秒的數(shù)據(jù)
● no:系統(tǒng)控制每次同步到AOF文件的周期狠怨,過(guò)程不可控
配置:
在(上面RDB的)redis.cnf文件中追加內(nèi)容:
# 開(kāi)啟AOF支持
appendonly yes
# 指定寫策略
appendfsync always
# 指定aof持久化的文件名
appendfilename appendonly-6379.aof
AOF重寫
將對(duì)同一個(gè)數(shù)據(jù)的若干條命令執(zhí)行結(jié)果轉(zhuǎn)化為最終結(jié)果數(shù)據(jù)對(duì)應(yīng)的指令進(jìn)行記錄
好處:降低磁盤占用空間,提高IO性能邑遏,提高數(shù)據(jù)恢復(fù)效率
重寫規(guī)則:
● 手動(dòng)重寫:直接在客戶端使用命令 bgwriteaof
● 自動(dòng)重寫:
自動(dòng)重寫觸發(fā)條件設(shè)置
auto-aof-rewrite-min-size 70
auto-aof-rewrite-percentage 70
自動(dòng)重寫觸發(fā)比對(duì)參數(shù)
aof_current_size
aof_base_size
自動(dòng)重寫觸發(fā)條件
aof_current_size>auto-aof-rewrite-min-size
(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage
五佣赖、 Redis事務(wù)
事務(wù)執(zhí)行示例:
# 開(kāi)啟事務(wù),后續(xù)的命令將加入到事務(wù)隊(duì)列中
multi
set name tom
set age 10
set gender male
# 如果發(fā)現(xiàn)加入事務(wù)隊(duì)列的命令寫錯(cuò)了记盒,使用該命令來(lái)取消事務(wù)憎蛤,該命令發(fā)生在multi之后,exec之前
discard
# 執(zhí)行事務(wù),和multi成對(duì)出現(xiàn)
exec
加入到事務(wù)隊(duì)列中的命令并不會(huì)立即執(zhí)行俩檬,只有在執(zhí)行了exec命令后才開(kāi)始執(zhí)行
錯(cuò)誤處理:
● 語(yǔ)法錯(cuò)誤(命令格式有誤)
如果定義的事務(wù)中所包含的命令存在語(yǔ)法錯(cuò)誤萎胰,那么整個(gè)事務(wù)將不會(huì)執(zhí)行
● 運(yùn)行錯(cuò)誤(指令格式正確,但無(wú)法正確執(zhí)行)
能夠正確運(yùn)行的命令會(huì)執(zhí)行棚辽,運(yùn)行錯(cuò)誤的命令不會(huì)執(zhí)行技竟,已經(jīng)執(zhí)行完畢的命令對(duì)應(yīng)的數(shù)據(jù)不會(huì)自動(dòng)回滾,需要程序員在代碼中實(shí)現(xiàn)回滾
六屈藐、 Redis鎖
加鎖示例:
- 對(duì)key添加監(jiān)視鎖榔组,在事務(wù)執(zhí)行exec前如果數(shù)據(jù)發(fā)生了變化,會(huì)終止事務(wù)的執(zhí)行(wath命令需要放在multi命令之前)
watch [key1] [key2] - 取消對(duì)所有key的監(jiān)視
unwatch
分布式鎖: - 使用setnx命令設(shè)置一個(gè)公共的鎖联逻,返回0表示設(shè)置失敗搓扯,業(yè)務(wù)需排隊(duì)或等待,返回1表示設(shè)置成功包归,執(zhí)行業(yè)務(wù)操作
setnx lock-key value - 操作完成后锨推,需通過(guò)del命令釋放鎖,以免后面請(qǐng)求無(wú)法獲取鎖
del lock-key
改良方案(為鎖設(shè)置超時(shí)時(shí)間公壤,一段時(shí)間后自動(dòng)釋放鎖): - 設(shè)置鎖
setnx lock-key value - 設(shè)置超時(shí)時(shí)間换可,expire為秒級(jí),pexpire為毫秒級(jí)
expire lock-key [second]
pexpire lock-key [millsecond]
再次改良
使用lua腳本境钟,使設(shè)置鎖和設(shè)置超時(shí)時(shí)間成為一個(gè)原子操作
if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end
七锦担、 Redis刪除策略
● 定時(shí)刪除(過(guò)期時(shí)間到達(dá)時(shí),立即刪除:降低內(nèi)存慨削,占用cpu)
● 惰性刪除(過(guò)期時(shí)間到達(dá)時(shí)洞渔,不做處理,下次訪問(wèn)時(shí)進(jìn)行刪除:占用內(nèi)存缚态,節(jié)約cpu)
● 定期刪除(周期性輪詢r(jià)edis庫(kù)中的時(shí)效性數(shù)據(jù)磁椒,采用隨機(jī)抽取的策略,利用過(guò)期數(shù)據(jù)占比的方式控制刪除頻度:cpu性能占用設(shè)置有峰值玫芦,檢測(cè)頻度可以自定義)
逐出算法:
redis在執(zhí)行每一個(gè)命令之前會(huì)調(diào)用freeMemoryIfNeeded()檢測(cè)內(nèi)存是否充足浆熔,如果內(nèi)存不滿足新加入數(shù)據(jù)的最低存儲(chǔ)要求,redis會(huì)臨時(shí)刪除一些數(shù)據(jù)為新數(shù)據(jù)存儲(chǔ)騰出空間桥帆,這種策略稱為逐出算法医增。(不保證100%清理出足夠的空間,如不成功老虫,則反復(fù)執(zhí)行叶骨,仍不能達(dá)到則報(bào)錯(cuò))
數(shù)據(jù)逐出策略:
配置:
在redis.conf文件中配置
maxmemory-policy [策略] 如:maxmemory-policy volatile-lru
八、 高級(jí)數(shù)據(jù)類型
bitmaps:一般用于信息狀態(tài)統(tǒng)計(jì)
HyperLogLog:用于基數(shù)統(tǒng)計(jì)
GEO:用于地理坐標(biāo)運(yùn)算
九祈匙、 主從復(fù)制
主從復(fù)制避免了單點(diǎn)故障忽刽,提供了數(shù)據(jù)的冗余備份
一個(gè)master可以擁有多個(gè)slave天揖,一個(gè)slave只對(duì)應(yīng)一個(gè)master
讀寫分離職責(zé):
master:負(fù)責(zé)寫數(shù)據(jù),并將數(shù)據(jù)同步到slave
slave:負(fù)責(zé)讀數(shù)據(jù)
三個(gè)階段:
● 建立連接
1.設(shè)置master的地址和端口跪帝,保存master信息
2.建立socket連接今膊,發(fā)送ping命令
3.身份驗(yàn)證
4.發(fā)送slave端口信息
配置:
master配置
- master節(jié)點(diǎn)要求密碼
requirepass [password]
slalve配置
在slavle節(jié)點(diǎn)的redis.conf文件下配置
slave聯(lián)通master配置
slaveof [master的IP地址] [master的端口]
配置master的密碼
masterauth [password]
● 數(shù)據(jù)同步
1.slave請(qǐng)求同步
2.master創(chuàng)建rdb同步數(shù)據(jù)
3.slave接收rdb,進(jìn)行數(shù)據(jù)恢復(fù)
以上過(guò)程叫做全量復(fù)制
4.slave請(qǐng)求同步部分?jǐn)?shù)據(jù)
5.slave接收復(fù)制緩沖區(qū)的數(shù)據(jù)伞剑,執(zhí)行bgrewriteaof命令斑唬,恢復(fù)數(shù)據(jù)
以上過(guò)程叫做部分復(fù)制
image
數(shù)據(jù)同步階段master說(shuō)明
1.如果master數(shù)據(jù)量巨大,數(shù)據(jù)同步階段應(yīng)該避免流量高峰期纸泄,避免造成master阻塞赖钞,影響業(yè)務(wù)正常執(zhí)行
2.復(fù)制緩沖區(qū)大小設(shè)定不合理,會(huì)導(dǎo)致數(shù)據(jù)溢出聘裁。如進(jìn)行全量復(fù)制周期太長(zhǎng)雪营,進(jìn)行部分賦值時(shí)發(fā)現(xiàn)數(shù)據(jù)已經(jīng)存在丟失的情況,必須進(jìn)行第二次全量復(fù)制衡便,致使slave陷入死循環(huán)狀態(tài),修改緩沖區(qū)大小操作如下
repl-backlog-size 1mb
3.master單機(jī)內(nèi)存占用主機(jī)內(nèi)存的比例不應(yīng)過(guò)大献起,建議使用50-70%的內(nèi)存,留下30-50%的內(nèi)存用于執(zhí)行bgsave命令和創(chuàng)建復(fù)制緩沖區(qū)
數(shù)據(jù)同步階段slave說(shuō)明
1.為避免slave進(jìn)行全量復(fù)制镣陕、部分復(fù)制時(shí)服務(wù)器響應(yīng)阻塞或數(shù)據(jù)不同步谴餐,建議關(guān)閉此期間的對(duì)外服務(wù)
slave-server-stale-data yes|no
2.數(shù)據(jù)同步階段,master發(fā)送給slave信息可以理解master是slave的一個(gè)客戶端呆抑,主動(dòng)向slave發(fā)送命令
3.多個(gè)slave同時(shí)對(duì)master請(qǐng)求數(shù)據(jù)同步岂嗓,master發(fā)送的RDB文件增多,會(huì)對(duì)帶寬造成巨大沖擊鹊碍,如果master寬帶不足厌殉,因此數(shù)據(jù)同步需要根據(jù)業(yè)務(wù)需求,適量錯(cuò)峰侈咕。
4.slave過(guò)多時(shí)公罕,建議調(diào)整拓?fù)浣Y(jié)構(gòu),由一主多從結(jié)構(gòu)變?yōu)闃?shù)狀結(jié)構(gòu)耀销,中間接待你即是master,也是slave楼眷。注意使用樹(shù)狀結(jié)構(gòu)時(shí),由于層級(jí)深度熊尉,導(dǎo)致深度越高的slave與最頂層master間數(shù)據(jù)同步延遲較大罐柳,數(shù)據(jù)一致性變差,應(yīng)謹(jǐn)慎選擇
● 命令傳播
image
主從復(fù)制工作流程完整版
image
十狰住、 哨兵模式
哨兵:哨兵(sentinel) 是一個(gè)分布式系統(tǒng)硝清,用于對(duì)主從結(jié)構(gòu)中的每臺(tái)服務(wù)器進(jìn)行監(jiān)控,當(dāng)出現(xiàn)故障時(shí)通過(guò)投票機(jī)制選擇新的master并將所有slave連接到新的master
哨兵的作用
● 監(jiān)控
不斷地檢查master和slave是否正常運(yùn)行
master存活檢測(cè)转晰、master與slave運(yùn)行情況檢測(cè)
● 通知(提醒)
當(dāng)被監(jiān)控地服務(wù)器出現(xiàn)問(wèn)題時(shí),向其他(哨兵間,客戶端)發(fā)送通知
● 自動(dòng)故障轉(zhuǎn)移
斷開(kāi)master與slave連接查邢,選取一個(gè)slave作為master,將其他slave連接到新的master蔗崎,并告知客戶端新的服務(wù)器地址
注意:哨兵也是一臺(tái)redis服務(wù)器,只是不提供數(shù)據(jù)服務(wù)扰藕,通常哨兵配置數(shù)量為單數(shù)
十一缓苛、 集群
集群就是使用網(wǎng)絡(luò)將若干臺(tái)計(jì)算機(jī)聯(lián)通起來(lái),并提供統(tǒng)一的管理方式邓深,使其對(duì)外呈現(xiàn)單機(jī)的服務(wù)效果未桥。
十二、 故障及解決方案
緩存預(yù)熱:系統(tǒng)啟動(dòng)前提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)芥备,避免用戶在請(qǐng)求的時(shí)候先查詢數(shù)據(jù)庫(kù)冬耿,然后再將數(shù)據(jù)緩存的問(wèn)題。用戶可以直接查詢事先被預(yù)熱的緩存數(shù)據(jù)
緩存雪崩:短時(shí)間內(nèi)萌壳,大量的緩存集中失效亦镶,數(shù)據(jù)庫(kù)同時(shí)接收到大量的請(qǐng)求無(wú)法處理,redis大量請(qǐng)求被積壓袱瓮,數(shù)據(jù)庫(kù)崩潰缤骨。重啟后仍然面對(duì)緩存中無(wú)數(shù)據(jù)可用,redis服務(wù)器資源被嚴(yán)重占用尺借,最后redis服務(wù)器崩潰绊起,導(dǎo)致集群坍塌。
解決辦法:1.多級(jí)緩存 2.mysql是否存在嚴(yán)重耗時(shí)燎斩,對(duì)mysql進(jìn)行優(yōu)化 3.限流 4.過(guò)期時(shí)間設(shè)置為隨機(jī)時(shí)間
緩存擊穿:redis某個(gè)高熱key過(guò)期瞬間虱歪,大量請(qǐng)求過(guò)來(lái)在redis中均未命中,直接壓倒了數(shù)據(jù)庫(kù)上
解決辦法:1.預(yù)先設(shè)定熱點(diǎn)key 2.多級(jí)緩存瘫里,設(shè)置不同的失效時(shí)間 3.設(shè)置為永久key
緩存穿透:大量訪問(wèn)一個(gè)不存在的數(shù)據(jù)实蔽,在跳過(guò)了合法數(shù)據(jù)在redis中的緩存階段,每次都直接訪問(wèn)數(shù)據(jù)庫(kù)
解決辦法:1.對(duì)查詢結(jié)果為null的數(shù)據(jù)緩存null值谨读,并設(shè)定過(guò)期時(shí)間
2.黑白名單 3.布隆過(guò)濾器