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