摘要:?jiǎn)尉€(xiàn)程執(zhí)行命令。文件描述符事件。內(nèi)部原因不合理使用或數(shù)據(jù)結(jié)構(gòu)可能由此導(dǎo)致慢查詢(xún)等飽和是單線(xiàn)程,只會(huì)使用單個(gè)持久化阻塞操作產(chǎn)生阻塞,對(duì)硬盤(pán)的操作產(chǎn)生阻塞或?qū)懖僮髯枞?。?nèi)存達(dá)到時(shí)執(zhí)行內(nèi)存溢出控制策略。
最近在看《Redis開(kāi)發(fā)與運(yùn)維》,把自己學(xué)會(huì)的知識(shí)點(diǎn)記錄下來(lái),畢竟好記性不如爛筆頭。
一.Redis是什么。
Redis是一個(gè)Key-Value的NoSQL數(shù)據(jù)庫(kù).
二.Redis的特點(diǎn)。
1.支持的數(shù)據(jù)類(lèi)型:hash,list,set,zset,string(memacached只支持string)。
2.單線(xiàn)程執(zhí)行命令。因?yàn)槭菃尉€(xiàn)程,所以減少了線(xiàn)程上下文切換的開(kāi)銷(xiāo),同時(shí)如果一個(gè)命令執(zhí)行時(shí)間過(guò)長(zhǎng)就會(huì)引起阻塞。
3.數(shù)據(jù)持久化到內(nèi)存中,一定時(shí)間后會(huì)存儲(chǔ)到硬盤(pán)中。
三.操作數(shù)據(jù)的命令
1.常用的命令
命令 | 含義 |
---|---|
keys * | 查看全部的鍵,會(huì)遍歷Redis所有的鍵,時(shí)間復(fù)雜度是O(n) |
scan cursor match pattern | 遍歷鍵,cursor是游標(biāo) |
type key | 查看鍵的類(lèi)型,key是鍵的名稱(chēng) |
dbsize | 查看鍵的數(shù)量:dbsize 是直接獲取Redis內(nèi)置的鍵總量,時(shí)間復(fù)雜度是O(1) |
exists key | 判斷某個(gè)鍵是否存在,存在返回1,不存在返回0. |
del key[ key...] | 返回成功刪除鍵的個(gè)數(shù) |
expire key time | 設(shè)置鍵的過(guò)期時(shí)間 |
ttl key | 查詢(xún)某個(gè)鍵的剩余過(guò)期時(shí)間 |
object encoding key | 查詢(xún)鍵的內(nèi)部編碼 |
rename key newkey | 鍵重命名 |
renamenx key newkey | 當(dāng)newkey不存在,鍵重命名成功 |
randomkey | 隨機(jī)選擇一個(gè)鍵 |
persist key | 清除鍵的過(guò)期時(shí)間 |
move key db | 在Redis內(nèi)部進(jìn)行數(shù)據(jù)庫(kù)遷移 |
dump + restore | 在不同Redis實(shí)例間遷移數(shù)據(jù) |
migrate | 在數(shù)據(jù)庫(kù)實(shí)例間遷移數(shù)據(jù) |
2.操作String數(shù)據(jù)類(lèi)型的命令
注意:操作String數(shù)據(jù)類(lèi)型的命令基本以s作為前綴開(kāi)頭
命令 | 含義 |
---|---|
set key value | 插入鍵值對(duì),key是鍵,value是值 |
get key | 查看鍵的值 |
del key | 刪除鍵 |
setnx key value | 當(dāng)key不存在時(shí),設(shè)置值 |
setex key seconds value | seconds是過(guò)期時(shí)間,設(shè)置鍵值對(duì) |
mset key value[key value..] | 批量獲取值 |
mget key [key ...] | 批量獲取值 |
incr key | 對(duì)值做自增1 |
decr key | 對(duì)值做自減1 |
incrby key incrment | 自增指定的數(shù)目 increment 數(shù)字 |
decrby key incrment | 自減指定的數(shù)目 increment 數(shù)字 |
incrbyfloat key incrment | 自增指定的浮點(diǎn)數(shù) increment 數(shù)字 |
內(nèi)部編碼有三種:int,embstr和raw
使用場(chǎng)景:
setnx和setex可用于分布式鎖
incr等可以用于計(jì)數(shù)
統(tǒng)一管理用戶(hù)的session
3.操作hash數(shù)據(jù)類(lèi)型的命令
注意:操作hash數(shù)據(jù)類(lèi)型的命令基本以h作為前綴開(kāi)頭
命令 | 含義 |
---|---|
hset key field value | 設(shè)置hash的內(nèi)容key=[{field:value}{field:value}] |
hget key field | 獲取字段值 |
hdel key field | 刪除字段值 |
hlen key | 獲取key的字段數(shù) |
hmset key field value [field value...] | 批量設(shè)置key的field-value |
hmget key field1[field2...] | 批量獲得key的field的字段值 |
hexists key field | 判斷key的field是否存在 |
hkeys key | 獲取key的全部字段 |
hvals key | 獲取key的全部value值 |
hgetall key | 獲取key的全部field,value |
hincrby key field incrment | key的字段field自增increment |
hincrbyfloat key field increment | key的字段field自增浮點(diǎn)數(shù)increment |
hstrlen key field | 計(jì)算field的value的長(zhǎng)度 |
內(nèi)部編碼:ziplist和hashtable
4.操作list數(shù)據(jù)類(lèi)型的命令
注意:操作list數(shù)據(jù)類(lèi)型的命令基本以l或r或b作為前綴開(kāi)頭
命令 | 含義 |
---|---|
rpush key value[value...] | 從列表右邊添加元素 |
lpush key value[value...] | 從列表左邊添加元素 |
lrange key start end | 獲取指定索引范圍的元素,0表示第一個(gè),-1表示最后一個(gè) |
linsert key before/after pivot value | 在pivot元素前/后插入value元素 |
lindex key index | 獲取列表指定下標(biāo)的元素 |
llen key | 獲取列表的長(zhǎng)度 |
lpop key | 從列表的左側(cè)彈出元素 |
rpop key | 從列表的右側(cè)彈出元素 |
lrem key count value | 從左到右刪除count個(gè)值為value的元素 |
lset key index value | 設(shè)置index位置的值 |
brpop/blpop key timeout | 阻塞彈出,timeout是超時(shí)時(shí)間,0表示一直等待下去 |
內(nèi)部編碼:ziplist(壓縮列表),linkedlist(鏈表)和quicklist
使用場(chǎng)景:
lpush+brpop=阻塞隊(duì)列(消息隊(duì)列)。
lpush+lpop=Stack(棧)
lpush+rpop=Queue(隊(duì)列)
lpush+ltrim=Capped Collection(有限集合)
5.操作set數(shù)據(jù)類(lèi)型的命令
注意:操作set數(shù)據(jù)類(lèi)型的命令基本以s作為前綴開(kāi)頭
命令 | 含義 |
---|---|
sadd key element[element...] | 添加元素 |
srem key element[element...] | 刪除元素 |
scard key | 計(jì)算元素個(gè)數(shù) |
sismember key element | 判斷element元素是否在集合中 |
srandmember key [count] | 隨機(jī)生成count個(gè)元素,默認(rèn)是1個(gè) |
spop key | 隨機(jī)彈出一個(gè)元素 |
smembers key | 查詢(xún)?nèi)康脑?/td> |
sinter key [key...] | 查詢(xún)多個(gè)集合的并集 |
sunion key [key...] | 查詢(xún)多個(gè)集合的交集 |
sdiff key [key...] | 查詢(xún)多個(gè)集合的差集 |
sinterstore destination key [key...] | 查詢(xún)多個(gè)集合的并集,存儲(chǔ)到destination中 |
sunionstore destination key [key...] | 查詢(xún)多個(gè)集合的交集,存儲(chǔ)到destination中 |
sdiffstore destination key [key...] | 查詢(xún)多個(gè)集合的差集,存儲(chǔ)到destination中 |
內(nèi)部編碼:intset,hashtable
使用場(chǎng)景:
sadd=Tagging(標(biāo)簽)
spop/srandmember=Random item(隨機(jī)數(shù)抽獎(jiǎng))
sadd+sinter=Social Graph(社交需求)
6.操作zset數(shù)據(jù)類(lèi)型的命令
注意:操作zset數(shù)據(jù)類(lèi)型的命令基本以z作為前綴開(kāi)頭
命令 | 含義 |
---|---|
zadd key score memeber[score memeber...] | 添加成員 |
zcard key | 計(jì)算成員個(gè)數(shù) |
zscore key member | 計(jì)算成員的分?jǐn)?shù) |
zrank/zrevrank key member | 計(jì)算成員的排名 |
zrem key member[member...] | 刪除成員 |
zincrby key increment member | 增加成員的分?jǐn)?shù) |
zrange/zrevrange key start end [withscores] | 從低到高,返回指定排名范圍的成員 |
zrangebyscore key min max [withscores] [limit offset count] | 從低到高,返回指定分?jǐn)?shù)范圍的成員 |
zrevrangebyscore key max min [withscores] [limit offset count] | 返回指定分?jǐn)?shù)范圍的成員 |
zcount key min max | 返回指定范圍的成員個(gè)數(shù) |
zremrangebyrank key start end | 刪除指定排名內(nèi)的升序元素 |
zremrangebyscore key min max | 刪除指定分?jǐn)?shù)范圍的成員 |
zinterstore destination numberkeys key [key...] [weights weight [weight...]] [aggregate sum/min/max] | 兩個(gè)有序集合的交集,numberkeys指有序集合進(jìn)行交集的個(gè)數(shù) |
zunionstore destination numberkeys key [key...] [weights weight [weight...]] [aggregate sum/min/max] | 兩個(gè)有序集合的并集,numberkeys指有序集合進(jìn)行并集的個(gè)數(shù) |
內(nèi)部編碼:ziplist(壓縮列表)和skiplist(跳躍表)
使用場(chǎng)景:
排行榜(點(diǎn)贊)
7.Jedis對(duì)五種數(shù)據(jù)類(lèi)型的操作
Jedis jedis = null; try { jedis = new Jedis("127.0.0.1", 6379, 10000); //1.string String result1 = jedis.set("string1", "value1"); String result2 = jedis.get("string1"); System.out.println(result1);//OK System.out.println(result2);//value1 //2.list long result3 = jedis.lpush("list1", "math","math","score","score","name","xiaoming"); Listresult4 = jedis.lrange("list1", 0, -1); System.out.println(result1);//OK System.out.println(result4);//xiaoming, name, score, score, math, math //3.hash jedis.hset("hash1", "subject","math"); jedis.hset("hash1", "score","99"); jedis.hset("hash1", "name","xiaoming"); List result5 = jedis.hmget("hash1", "subject","score","name"); System.out.println(result5);//[math, 99, xiaoming] //4.set jedis.sadd("set1", "math","math","english","chinese"); jedis.sadd("set2", "math","chinese","art"); jedis.sinterstore("set3", "set1","set2"); System.out.println(jedis.smembers("set3"));//[math, chinese] //5.zset jedis.zadd("zset1", 100, "math"); jedis.zadd("zset1", 200, "chinese"); jedis.zadd("zset1", 300, "english"); Set result6 = jedis.zrangeByScore("zset1", 100, 200); result6.forEach(string -> { System.out.print(string+" "); });//math chinese }catch(Exception e) { e.printStackTrace(); }finally { if(jedis != null) { jedis.close(); } }
四.客戶(hù)端操作
1.client list
列出與Redis服務(wù)器相連的所有客戶(hù)端信息。
屬性如下:
名稱(chēng) | 含義 |
---|---|
id | 客戶(hù)端的唯一標(biāo)識(shí)。自增,重啟后重置為0。 |
addr | 客戶(hù)端連接的地址和端口。 |
fd | socket的文件描述符。 |
name | 客戶(hù)端的名稱(chēng)。 |
age | 當(dāng)前客戶(hù)端的連接時(shí)間。 |
idle | 當(dāng)前客戶(hù)端的最近一次空閑時(shí)間。當(dāng)age等于idle表示連接一直處于空閑狀態(tài)。 |
flags | 標(biāo)識(shí)當(dāng)前客戶(hù)端的類(lèi)型。 |
db | 當(dāng)前客戶(hù)端正在使用的數(shù)據(jù)庫(kù)索引下標(biāo)。 |
sub | 當(dāng)前客戶(hù)端訂閱的頻道或者模式數(shù)。 |
psub | 當(dāng)前客戶(hù)端訂閱的頻道或者模式數(shù)。 |
multi | 當(dāng)前事務(wù)中已執(zhí)行命令個(gè)數(shù)。 |
qbuf | 輸入緩沖區(qū)總?cè)萘俊?/td> |
qbuf-free | 輸入緩沖區(qū)的剩余容量。 |
obl | 輸出緩沖區(qū)的固定緩沖區(qū)的大小。 |
oll | 輸出緩沖區(qū)的動(dòng)態(tài)緩沖區(qū)的大小。 |
omem | 輸出緩沖區(qū)使用的字節(jié)數(shù)。 |
events | 文件描述符事件。 |
cmd | 當(dāng)前客戶(hù)端最后一次執(zhí)行的命令。 |
2.輸入緩沖區(qū)
作用:客戶(hù)端發(fā)送的命令不是直接發(fā)送給Redis服務(wù)器,而是先存放在輸入緩沖區(qū),Redis服務(wù)器從輸入緩沖區(qū)中獲得命令并執(zhí)行。
當(dāng)輸入緩沖區(qū)的輸入速度大于Redis服務(wù)器的處理速度且存在大量的bigkey或是Redis服務(wù)器發(fā)生阻塞,短期不能執(zhí)行命令時(shí),都會(huì)造成輸入緩沖區(qū)過(guò)大,可以通過(guò)client list查看qbuf和qbuf-free的大小或是通過(guò)info clients命令找到最大的輸入緩沖區(qū)。
3.輸出緩沖區(qū)
作用:Redis服務(wù)器執(zhí)行命令后的結(jié)果不是直接返回給客戶(hù)端,而是先存放在輸出緩沖區(qū)。
輸出緩沖區(qū)分為固定緩沖區(qū)和動(dòng)態(tài)緩沖區(qū),固定緩沖區(qū)是字節(jié)數(shù)組,動(dòng)態(tài)緩沖區(qū)是列表,固定緩沖區(qū)使用完之后才會(huì)使用動(dòng)態(tài)緩沖區(qū)。
通過(guò)client list和info clients可以監(jiān)控輸出緩沖區(qū)的異常情況。
4.客戶(hù)端的分類(lèi)
(1)普通客戶(hù)端
(2)發(fā)布訂閱客戶(hù)端
(3)slave客戶(hù)端
5.客戶(hù)端操作
命令 | 含義 |
---|---|
config set maxclients value | 設(shè)置最大連接數(shù) |
config get maxclients | 設(shè)置最大連接數(shù) |
info clients | 查看當(dāng)前已經(jīng)連接的客戶(hù)端數(shù)量 |
config set timeout value | 設(shè)置超時(shí)時(shí)間,空閑時(shí)間一旦大于超時(shí)時(shí)間,客戶(hù)端連接就會(huì)自動(dòng)斷開(kāi)。 |
client setName value | 設(shè)置客戶(hù)端的名稱(chēng) |
client getName | 獲得客戶(hù)端的名稱(chēng) |
client kill ip:port | 關(guān)閉指定的ip:port的客戶(hù)端 |
client pause timeout | (時(shí)間單位毫秒) 阻塞客戶(hù)端timeout毫秒 |
五.持久化
1.RDB
(1)概念:將當(dāng)前線(xiàn)程數(shù)據(jù)生成快照保存在磁盤(pán)中。
(2)方式
a.手動(dòng)觸發(fā)
bgsave命令:Redis進(jìn)程執(zhí)行fork操作創(chuàng)建子進(jìn)程,RDB的序列化由子進(jìn)程完成,在fork階段會(huì)出現(xiàn)堵塞。
b.自動(dòng)觸發(fā)
在某些情況下自動(dòng)觸發(fā)bgsave命令或是save命令。
(3)RDB的優(yōu)缺點(diǎn)
a.優(yōu)點(diǎn)
緊湊壓縮的二進(jìn)制文件,能夠代表Redis在某個(gè)時(shí)間點(diǎn)的數(shù)據(jù)備份,可復(fù)制到不同的機(jī)器進(jìn)行災(zāi)難恢復(fù)。Redis加載RDB恢復(fù)數(shù)據(jù)的速度快于AOF。
b.缺點(diǎn)
無(wú)法實(shí)現(xiàn)實(shí)時(shí)持久化,執(zhí)行fork操作創(chuàng)建子進(jìn)程是重量級(jí)操作,頻繁執(zhí)行成本較高,且老版本的Redis服務(wù)無(wú)法兼容新版本的RDB格式文件。
2.AOF
(1)概念:記錄每次的寫(xiě)命令,重啟后執(zhí)行AOF文件中的命令以達(dá)到恢復(fù)數(shù)據(jù)的目的??梢杂胊of_enabled開(kāi)啟aof功能。
(2)特點(diǎn):
a.AOF命令以文本協(xié)議格式的形式寫(xiě)入內(nèi)容到aof_buf中,再由aof_buf同步到硬盤(pán)中。文本協(xié)議格式具有很好的兼容性以及避免了二次處理的開(kāi)銷(xiāo)。而寫(xiě)入到aof_buf中是為了避免直接寫(xiě)入硬盤(pán),以免硬盤(pán)的容量決定了追加寫(xiě)入的性能。
b.aof重寫(xiě)將無(wú)效的命令如del去掉,將多個(gè)命令合并成一個(gè)命令,以達(dá)到壓縮文件體積,加快Redis加載aof文件的速度。
六.復(fù)制
1.從節(jié)點(diǎn)和主節(jié)點(diǎn)之間建立關(guān)系有以下的方式:
(1)在配置文件(redis.conf)中加入slaveof {masterofhost} {masterofport}
(2)啟動(dòng)redis-server時(shí)執(zhí)行:redis-server -slaveof {masterofhost} {masterofport}
2.主節(jié)點(diǎn)和從節(jié)點(diǎn)斷開(kāi)和切換:
(1)斷開(kāi):slaveof no one
(2)切換:執(zhí)行命令slaveof {masterofhost} {masterofport}
3.復(fù)制的特點(diǎn)
(1)只能將主節(jié)點(diǎn)的數(shù)據(jù)復(fù)制到從節(jié)點(diǎn)。
(2)slaveof是異步命令,從節(jié)點(diǎn)保存了主節(jié)點(diǎn)的信息后返回,而不需要等到完全復(fù)制完畢才返回。
(3)可以通過(guò)命令info replication查看復(fù)制信息。
(4)從節(jié)點(diǎn)斷開(kāi)與主節(jié)點(diǎn)的復(fù)制關(guān)系后,會(huì)晉升為主節(jié)點(diǎn)。
(5)從節(jié)點(diǎn)切換主節(jié)點(diǎn)之后,會(huì)刪除從節(jié)點(diǎn)當(dāng)前的所有數(shù)據(jù),對(duì)新節(jié)點(diǎn)數(shù)據(jù)進(jìn)行復(fù)制。
4.Redis的復(fù)制關(guān)系
(1)一主一從:用于主節(jié)點(diǎn)宕機(jī)時(shí),從節(jié)點(diǎn)提供故障轉(zhuǎn)移支持。
(2)一主多從:用于讀寫(xiě)分離,主節(jié)點(diǎn)執(zhí)行寫(xiě)命令,從節(jié)點(diǎn)執(zhí)行讀命令,當(dāng)高并發(fā)寫(xiě)時(shí),將寫(xiě)命令的數(shù)據(jù)復(fù)制到從節(jié)點(diǎn)就需要消耗比較多的網(wǎng)絡(luò)帶寬。
(3)樹(shù)狀主從:從節(jié)點(diǎn)不僅可以復(fù)制主節(jié)點(diǎn)的數(shù)據(jù),還可以作為其他從節(jié)點(diǎn)的主節(jié)點(diǎn)進(jìn)行向下復(fù)制??梢杂行Ы档椭鞴?jié)點(diǎn)的負(fù)載和傳輸給從節(jié)點(diǎn)的數(shù)據(jù)量。
5.全量復(fù)制和部分復(fù)制
全量復(fù)制:將主節(jié)點(diǎn)的數(shù)據(jù)一次性發(fā)生給從節(jié)點(diǎn)。一般用于初次復(fù)制場(chǎng)景。
部分復(fù)制:僅復(fù)制主節(jié)點(diǎn)的部分?jǐn)?shù)據(jù)給從節(jié)點(diǎn)。一般用于處理主從復(fù)制中網(wǎng)絡(luò)閃斷等原因造成的數(shù)據(jù)丟失場(chǎng)景。
從節(jié)點(diǎn)執(zhí)行命令:psync {runId} {offse7dxzt}
runId是主節(jié)點(diǎn)的運(yùn)行id,offset是從節(jié)點(diǎn)已復(fù)制的偏移量。主節(jié)點(diǎn)響應(yīng)寫(xiě)命令時(shí),會(huì)把寫(xiě)命令發(fā)送給從節(jié)點(diǎn),還會(huì)將寫(xiě)命令寫(xiě)入復(fù)制積壓緩沖區(qū)。
七.Redis的阻塞
利用日志對(duì)Redis的異常進(jìn)行監(jiān)控。
內(nèi)部原因:不合理使用API或數(shù)據(jù)結(jié)構(gòu)(可能由此導(dǎo)致慢查詢(xún)等)、CPU飽和(Redis是單線(xiàn)程,只會(huì)使用單個(gè)CPU)、持久化阻塞(fork操作產(chǎn)生阻塞,AOF對(duì)硬盤(pán)的操作產(chǎn)生阻塞或HugePage寫(xiě)操作阻塞)等。
外在原因:CPU競(jìng)爭(zhēng)、內(nèi)存交換、網(wǎng)絡(luò)問(wèn)題等。
八.Redis的內(nèi)存
1.Redis進(jìn)程內(nèi)存消耗
可以通過(guò)config set maxmemory value設(shè)置最大內(nèi)存以達(dá)到伸縮內(nèi)存的目的
2.Redis內(nèi)存的回收
(1)刪除已過(guò)期的鍵對(duì)象。包括惰性刪除(查詢(xún)時(shí)判斷鍵對(duì)象是否過(guò)期,如果過(guò)期執(zhí)行刪除操作并返回空)和定時(shí)刪除。
(2)內(nèi)存達(dá)到maxmemory時(shí)執(zhí)行內(nèi)存溢出控制策略。內(nèi)存溢出策略包括noeviction,volatile-lru,allkeys-lru,allkeys-random,volatile-random和volatile-ttl,可以通過(guò)config set maxmemory-policy {policy}動(dòng)態(tài)設(shè)置。
3.內(nèi)存優(yōu)化
(1)縮短鍵和值得長(zhǎng)度,使用高效二進(jìn)制序列化工具。
(2)使用對(duì)象共享池優(yōu)化小整數(shù)對(duì)象。
(3)避免字符串的追加操作,因?yàn)樽址芳訒?huì)導(dǎo)致內(nèi)存的預(yù)分配,降低內(nèi)存的分配次數(shù)。
(4)ziplist壓縮編碼的原則是追求時(shí)間和空間的平衡,hash,zset,list的內(nèi)部編碼可以是ziplist,可以通過(guò){type}-max-ziplist-value和{type}-max-ziplist-entries進(jìn)行編碼的控制。
(5)intset是set的內(nèi)部編碼,整數(shù)集合盡量使用intset編碼,
(6)數(shù)據(jù)優(yōu)先使用整數(shù),比字符串類(lèi)型更節(jié)省內(nèi)存。
九.Redis Sentinel(哨兵)
1.Redis Sentinel是什么?
一個(gè)分布式架構(gòu),包括Sentinel節(jié)點(diǎn),Redis數(shù)據(jù)節(jié)點(diǎn)和分布在多個(gè)物理機(jī)的客戶(hù)端應(yīng)用。完成主節(jié)點(diǎn)不可用時(shí)的故障轉(zhuǎn)移處理工作,提供了高可用的解決方案。
2.Sentinel節(jié)點(diǎn)發(fā)現(xiàn)故障轉(zhuǎn)移前的內(nèi)容:
(1)每個(gè)Sentinel節(jié)點(diǎn)會(huì)對(duì)所有的數(shù)據(jù)節(jié)點(diǎn)(包括主節(jié)點(diǎn)和從節(jié)點(diǎn))和其他的Sentinel節(jié)點(diǎn)進(jìn)行監(jiān)控。
(2)當(dāng)半數(shù)以上的節(jié)點(diǎn)認(rèn)為主節(jié)點(diǎn)故障不可用,就會(huì)選擇其中一個(gè)Sentinel節(jié)點(diǎn)作為領(lǐng)導(dǎo)者進(jìn)行故障轉(zhuǎn)移處理。
3.故障轉(zhuǎn)移處理的步驟如下:
(1)對(duì)某一個(gè)從節(jié)點(diǎn)執(zhí)行slaveof no one,晉升為主節(jié)點(diǎn)。
(2)其他的從節(jié)點(diǎn)復(fù)制新的主節(jié)點(diǎn)命令(slaveof new master)。
(3)舊的主節(jié)點(diǎn)恢復(fù)后也要復(fù)制新的主節(jié)點(diǎn)命令(slaveof new master)。
(4)通知應(yīng)用方新的主節(jié)點(diǎn)。
4.為什么需要多個(gè)Rentinel節(jié)點(diǎn)?
由多個(gè)Rentinel節(jié)點(diǎn)對(duì)主節(jié)點(diǎn)不可達(dá)進(jìn)行判斷,可以防止誤判。如果有個(gè)別Rentinel節(jié)點(diǎn)失效,整個(gè)Rentinel集合依然可用。
5.Redis Sentinel的搭建
(1)建立配置文件,逐一開(kāi)啟。(配置文件的寫(xiě)法可以去看《Redis開(kāi)發(fā)與設(shè)計(jì)》第九章)
開(kāi)啟主節(jié)點(diǎn):redis-server redis-6379.conf
開(kāi)啟從節(jié)點(diǎn) redis-server redis-6380.conf
redis-server redis-6381.conf
開(kāi)啟sentinel節(jié)點(diǎn) redis-server redis-sentinel-26379.conf --sentinel
redis-server redis-sentinel-26380.conf --sentinel redis-server redis-sentinel-26381.conf --sentinel
查看主節(jié)點(diǎn)的從節(jié)點(diǎn):redis-cli -h 127.0.0.1 -p 6379 info replication
查看從節(jié)點(diǎn)的主節(jié)點(diǎn) redis-cli -h 127.0.0.1 -p 6380 info replication
查看sentinel節(jié)點(diǎn)監(jiān)控的主節(jié)點(diǎn) redis-cli -h 127.0.0.1 -p 26379 info sentinel
(2)sentinel配置文件的一些參數(shù)
參數(shù) | 含義 |
---|---|
sentinel monitor |
sentinel節(jié)點(diǎn)要監(jiān)控名字叫 |
sentinel down-after-milliseconds |
sentinel節(jié)點(diǎn)會(huì)向數(shù)據(jù)節(jié)點(diǎn)和其他sentinel節(jié)點(diǎn)發(fā)送ping命令,如果節(jié)點(diǎn)在 |
sentinel parallel-syncs |
一次故障轉(zhuǎn)移后,每次向新節(jié)點(diǎn)發(fā)起復(fù)制操作的從節(jié)點(diǎn)個(gè)數(shù)。 |
sentinel failover-timeout |
故障轉(zhuǎn)移的超時(shí)時(shí)間。 |
sentinel authpass |
添加主節(jié)點(diǎn)的密碼。 |
sentinel notification-script |
在故障轉(zhuǎn)移期間,如果發(fā)生了一些警告級(jí)別的事件(如客觀(guān)下線(xiàn),主觀(guān)下線(xiàn)等),就會(huì)觸發(fā)對(duì)應(yīng)路徑的腳本,并向腳本發(fā)送相應(yīng)的事件參數(shù)。 |
sentinel client-reconfig-script |
在故障轉(zhuǎn)移結(jié)束后,會(huì)觸發(fā)相應(yīng)路徑下的腳本,并把故障轉(zhuǎn)移后的結(jié)果參數(shù)發(fā)送給腳本。 |
6.Redis Sentinel部署的特點(diǎn)
(1)將Sentinel節(jié)點(diǎn)部署在不同的物理機(jī)上,因?yàn)槿绻坏┪锢頇C(jī)出現(xiàn)故障,那這臺(tái)物理機(jī)上的Sentinel節(jié)點(diǎn)都會(huì)受到影響。
(2) 部署三個(gè)以上且奇數(shù)個(gè)Sentinel節(jié)點(diǎn),因?yàn)轭I(lǐng)導(dǎo)者選舉需要半數(shù)加上1個(gè),部署奇數(shù)個(gè)節(jié)點(diǎn)可以節(jié)省一個(gè)節(jié)點(diǎn)。
(3)如果Sentinel節(jié)點(diǎn)需要監(jiān)控同一個(gè)業(yè)務(wù)的所有主節(jié)點(diǎn)集合,就使用同一套Sentinel節(jié)點(diǎn)監(jiān)控,如果不是,就用不同的Sentinel節(jié)點(diǎn)集合監(jiān)控不同的業(yè)務(wù)的主節(jié)點(diǎn)。使用同一套Sentinel節(jié)點(diǎn)監(jiān)控可以節(jié)約資源,但是一旦出現(xiàn)異常,就會(huì)對(duì)監(jiān)控的數(shù)據(jù)節(jié)點(diǎn)造成影響。
7.Sentinel節(jié)點(diǎn)的操作(進(jìn)入某個(gè)Sentinel節(jié)點(diǎn)客戶(hù)端輸入以下操作)
操作 | 含義 |
---|---|
sentinel master | 查看所有的監(jiān)控的主節(jié)點(diǎn)的信息。 |
sentinel master |
查看指定的監(jiān)控的主節(jié)點(diǎn)的信息。 |
sentinel get-master-addr-by-name |
根據(jù)主節(jié)點(diǎn)名稱(chēng)查看主節(jié)點(diǎn)的IP地址和端口 |
sentinel slaves |
查看主節(jié)點(diǎn)的從節(jié)點(diǎn)信息 |
sentinel sentinels |
查看主節(jié)點(diǎn)的Sentinel節(jié)點(diǎn)信息(不包括當(dāng)前節(jié)點(diǎn)) |
sentinel remove |
取消當(dāng)前節(jié)點(diǎn)對(duì)指定主節(jié)點(diǎn)的監(jiān)控。 |
8.根據(jù)Sentinel節(jié)點(diǎn)連接主節(jié)點(diǎn)
遍歷Sentinel節(jié)點(diǎn)集合獲得一個(gè)可用的Sentinel節(jié)點(diǎn),再利用sentinel get-master-addr-by-name獲得主節(jié)點(diǎn)的IP地址和端口號(hào)。
/** * 使用Sentinel節(jié)點(diǎn)連接主節(jié)點(diǎn) * @author liuffei * @date 2018年7月21日 * @description */ public class SentinelTest { public static void main(String[] args) { org.slf4j.Logger logger = LoggerFactory.getLogger(SentinelTest.class); Setsentinels = new HashSet (); sentinels.add("127.0.0.1:26379"); sentinels.add("127.0.0.1:26380"); sentinels.add("127.0.0.1:26381"); JedisSentinelPool pool = new JedisSentinelPool("mymaster",sentinels); Jedis jedis = null; try { jedis = pool.getResource(); String result = jedis.get("hello"); System.out.println(result); }catch(Exception e) { logger.error(e.getMessage()); }finally { if(null != jedis) { jedis.close(); } } } }
9.Sentinel的內(nèi)部原理
(1)Sentinel需要三個(gè)定時(shí)任務(wù)來(lái)保證對(duì)節(jié)點(diǎn)不可達(dá)的判斷:
每隔10秒,每個(gè)Sentinel節(jié)點(diǎn)向數(shù)據(jù)節(jié)點(diǎn)(主節(jié)點(diǎn)和從節(jié)點(diǎn))發(fā)送info replication命令獲取最新的主從關(guān)系。
每隔2秒,每個(gè)Sentinel節(jié)點(diǎn)需要向某個(gè)頻道發(fā)送自己對(duì)主節(jié)點(diǎn)是否可達(dá)的判斷和自身節(jié)點(diǎn)的信息,以發(fā)現(xiàn)新的Sentinel節(jié)點(diǎn)和Sentinel節(jié)點(diǎn)之間可以交換主節(jié)點(diǎn)的狀態(tài)。
每隔1秒,每個(gè)Sentinel節(jié)點(diǎn)需要向其它節(jié)點(diǎn)(包括主節(jié)點(diǎn),從節(jié)點(diǎn),Sentinel節(jié)點(diǎn))發(fā)送ping命令來(lái)確認(rèn)這些節(jié)點(diǎn)是否可達(dá)。
(2)主觀(guān)下線(xiàn)和客觀(guān)下線(xiàn)
主觀(guān)下線(xiàn):Sentinel節(jié)點(diǎn)向某個(gè)節(jié)點(diǎn)發(fā)出ping命令后,該節(jié)點(diǎn)在down-after-milliseconds之后沒(méi)有進(jìn)行回復(fù),Sentinel會(huì)對(duì)該節(jié)點(diǎn)做失敗判定,這個(gè)行為成為主觀(guān)下線(xiàn)。
客觀(guān)下線(xiàn):如果主觀(guān)下線(xiàn)的是主節(jié)點(diǎn),那Sentinel節(jié)點(diǎn)就會(huì)通過(guò)is-master-down-by-addr向其他Sentinel節(jié)點(diǎn)詢(xún)問(wèn)主節(jié)點(diǎn)的狀態(tài),當(dāng)Sentinel認(rèn)為主節(jié)點(diǎn)失敗的個(gè)數(shù)超過(guò)
(3)領(lǐng)導(dǎo)者的選舉
只需要一個(gè)Sentinel節(jié)點(diǎn)就能完成故障轉(zhuǎn)移。當(dāng)一個(gè)Sentinel節(jié)點(diǎn)完成客觀(guān)下線(xiàn)之后,會(huì)詢(xún)問(wèn)其他節(jié)點(diǎn)是否同意自己成為領(lǐng)導(dǎo)者,如果獲得票數(shù)大于等于max{quorum,num(sentinels/2+1)},就會(huì)成為領(lǐng)導(dǎo)者,
十.集群
集群和哨兵都可以保障高可用,不同的是哨兵是每臺(tái)Redis服務(wù)器存儲(chǔ)相同的數(shù)據(jù),而集群是將數(shù)據(jù)分區(qū)后,每個(gè)節(jié)點(diǎn)操作一個(gè)分區(qū)的數(shù)據(jù)。
1.數(shù)據(jù)分區(qū)
分布式數(shù)據(jù)庫(kù)需要把數(shù)據(jù)集劃分到多個(gè)節(jié)點(diǎn)上,常用的分區(qū)規(guī)則有:順序分區(qū)和哈希分區(qū)。Redis采用哈希分區(qū),哈希分區(qū)有節(jié)點(diǎn)取余分區(qū),一致性哈希分區(qū)和虛擬槽分區(qū)等等。Redis Cluster采用虛擬槽分區(qū)。
虛擬槽分區(qū):使用分散度良好的哈希函數(shù)把所有數(shù)據(jù)映射到一個(gè)固定范圍的整數(shù)集合中,整數(shù)定義為槽。槽是集群內(nèi)數(shù)據(jù)管理和遷移的基本單位。采用大范圍槽的主要目的是為了方便拆分和集群拓展。Redis Cluster采用虛擬槽分區(qū),所有的鍵根據(jù)哈希函數(shù)映射到0-16383整數(shù)槽內(nèi),計(jì)算公式:slot=CRC16(key)&16383。每個(gè)節(jié)點(diǎn)負(fù)責(zé)維護(hù)一部分槽以及槽所映射的鍵值數(shù)據(jù)。
2.集群的搭建
(1)準(zhǔn)備節(jié)點(diǎn)
需要準(zhǔn)備6臺(tái)及以上的Redis服務(wù)器才能保證完整的高可用。需要設(shè)置cluster-enabled yes。
(2)節(jié)點(diǎn)握手
概念:指一批運(yùn)行在集群模式下的節(jié)點(diǎn)通過(guò)Gossip協(xié)議通信,達(dá)到感知對(duì)方的過(guò)程。由客戶(hù)端發(fā)起命令:cluster meet {ip} {port}
(3)分配槽
只有當(dāng)節(jié)點(diǎn)分配了槽,才能響應(yīng)和這些槽關(guān)聯(lián)的鍵命令。
客戶(hù)端執(zhí)行cluster replicate {nodeId}可以讓一個(gè)節(jié)點(diǎn)變成子節(jié)點(diǎn)。
3.Gossip協(xié)議
工作原理:節(jié)點(diǎn)彼此不斷通信交換消息,一段時(shí)間后所有節(jié)點(diǎn)都會(huì)知道集群完整的信息,這種方式類(lèi)似留言傳播。
Gossip的消息包括以下:
(1)meet消息:向集群中加入新的節(jié)點(diǎn) cluster meet {ip} {port}
(2)ping消息:用于集群內(nèi)交換消息。
(3)pong消息: 響應(yīng)消息。
(4)fail消息:用于在集群內(nèi)廣播下線(xiàn)消息。
4.集群的伸縮和擴(kuò)容
(1)擴(kuò)容:準(zhǔn)備新節(jié)點(diǎn)->加入集群->分配槽和數(shù)據(jù)
(2)收縮:下線(xiàn)遷移槽->遺忘節(jié)點(diǎn)
十一.緩存
1.使用緩存的好處以及帶來(lái)的問(wèn)題
(1)好處:Redis將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,可以加快寫(xiě)入和讀取的速度,同時(shí)還能在緩存層做一些復(fù)雜的操作和計(jì)算。減少了向后端的訪(fǎng)問(wèn),降低了對(duì)后端(存儲(chǔ)層)的負(fù)載。
(2)問(wèn)題:緩存層和存儲(chǔ)層的數(shù)據(jù)存在一致性問(wèn)題。增加了代碼維護(hù)和運(yùn)維成本。
2.緩存的更新策略
(1)算法剔除:當(dāng)緩存的使用量超過(guò)最大值時(shí),利用一些算法策略,刪除一部分緩存鍵值對(duì)象。
(2)過(guò)期刪除:給緩存對(duì)象設(shè)置過(guò)期時(shí)間,這會(huì)導(dǎo)致存儲(chǔ)層和緩存層的數(shù)據(jù)存在不一致,可用于實(shí)時(shí)性不高的場(chǎng)景中。
(3)主動(dòng)更新:真實(shí)數(shù)據(jù)更新后就立馬更新存儲(chǔ)層的數(shù)據(jù)??捎糜趯?shí)時(shí)性要求高的場(chǎng)景。
3.緩存全部數(shù)據(jù)和部分?jǐn)?shù)據(jù)的對(duì)比:
(1)緩存全部數(shù)據(jù)可以使用在比較多的場(chǎng)景下,但是對(duì)內(nèi)存的壓力也比較大,代碼維護(hù)壓力小。
(2)緩存部分?jǐn)?shù)據(jù)的適用場(chǎng)景比較少,對(duì)內(nèi)存壓力小,但是一旦需要在緩存中新加字段,就需要修改代碼。
4.緩存穿透
指查詢(xún)了存儲(chǔ)層和緩存層都不存在的數(shù)據(jù),存儲(chǔ)層和緩存層都不會(huì)命中。
問(wèn)題:如果不把空值存儲(chǔ)在緩存層就會(huì)導(dǎo)致頻繁訪(fǎng)問(wèn)存儲(chǔ)層,增加了數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn)壓力。如果把空值存儲(chǔ)在內(nèi)存中,就會(huì)在緩存層維護(hù)一些值為空的鍵。增大了內(nèi)存的存儲(chǔ)壓力。
5.緩存“無(wú)底洞”
指添加新的節(jié)點(diǎn)機(jī)器沒(méi)有提高性能,反而導(dǎo)致性能下降。因?yàn)閷?shù)據(jù)分散存儲(chǔ)在更多的機(jī)器節(jié)點(diǎn)上了,批量操作需要從不同的節(jié)點(diǎn)上獲取。
6.緩存雪崩
指緩存層不能提供服務(wù)之后,會(huì)有大量的請(qǐng)求涌入存儲(chǔ)層,可能會(huì)導(dǎo)致存儲(chǔ)層宕機(jī)。
7.熱點(diǎn)Key失效
熱點(diǎn)Key會(huì)有大量的請(qǐng)求,短時(shí)間內(nèi)不能恢復(fù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71682.html
摘要:在這里使用學(xué)而思網(wǎng)校的錄像設(shè)備,記錄每天學(xué)習(xí)的內(nèi)容閆昌李樂(lè)階段李樂(lè)李樂(lè)李樂(lè)李樂(lè)李樂(lè)李樂(lè)馬運(yùn)運(yùn)李樂(lè)李樂(lè)李樂(lè)源碼集群閆昌源碼閆昌源碼主從復(fù)制李樂(lè)源碼施洪寶源碼施洪寶韓天 在這里使用學(xué)而思網(wǎng)校的錄像設(shè)備,記錄每天學(xué)習(xí)的內(nèi)容: 2019-06-24 ~ 2019-06-28 06-27 nginx by 閆昌 06-26 nginx module by 李樂(lè) 06-25 nginx http ...
摘要:在這里使用學(xué)而思網(wǎng)校的錄像設(shè)備,記錄每天學(xué)習(xí)的內(nèi)容執(zhí)行潘森執(zhí)行潘森執(zhí)行潘森趙俊峰紅黑樹(shù)景羅紅黑樹(shù)景羅配置三叉樹(shù)田志澤新建模塊馬運(yùn)運(yùn)配置田志澤田志澤田志澤李樂(lè)田志澤田志澤文件系統(tǒng) 在這里使用學(xué)而思網(wǎng)校的錄像設(shè)備,記錄每天學(xué)習(xí)的內(nèi)容: 2019-07-15 ~ 2019-07-19 07-18 nginx http 執(zhí)行 by 潘森 07-17 nginx http 執(zhí)行 by 潘森 07...
摘要:前段時(shí)間,有個(gè)人吐槽自己的同事是上古程序猿,一直堅(jiān)持反對(duì)使用。上古程序猿堅(jiān)決反對(duì)用,我該怎么說(shuō)服他分布式鎖如果你是一位后端工程師,面試時(shí)八成會(huì)被問(wèn)到,特別是大廠(chǎng),不僅要求能簡(jiǎn)單使用,還要深入理解底層原理,具備解決常見(jiàn)問(wèn)題的能力。 前段時(shí)間,有個(gè)人吐槽自己的同事是上古程序猿,一直堅(jiān)持反對(duì)使用Redis。那位上古程序猿設(shè)計(jì)公司...
閱讀 333·2025-02-07 13:40
閱讀 503·2025-02-07 13:37
閱讀 786·2024-11-06 13:38
閱讀 972·2024-09-10 13:19
閱讀 1166·2024-08-22 19:45
閱讀 1439·2021-11-19 09:40
閱讀 2719·2021-11-18 13:14
閱讀 4351·2021-10-09 10:02