1.啟動
1.1windows版本啟動命令
????redis-server.exe ./redis.windows.conf
????redis-cli??
2.數(shù)據(jù)類型
?2.1.string? ??
????????格式? set key value [EX seconds][PX milliseconds] [NX|XX]
????????EX seconds : 將鍵的過期時間設(shè)置為 seconds 秒。
????????PX milliseconds : 將鍵的過期時間設(shè)置為 milliseconds 毫秒。
????????NX : 只在鍵不存在時, 才對鍵進(jìn)行設(shè)置操作。 執(zhí)行 SET key value NX 的效果等同于執(zhí)行 SETNX key value
????????XX : 只在鍵已經(jīng)存在時, 才對鍵進(jìn)行設(shè)置操作。?
在 Redis 2.6.12 版本以前, SET 命令總是返回 OK 。?
? ? ? ? set name dubian? ? //添加
????????get name? ? //獲取
? ? ? ? exists name? ? //判斷key是否存在 0 存在 1 不存在
? ??????del name //刪除數(shù)據(jù)結(jié)構(gòu),所有數(shù)據(jù)結(jié)構(gòu)都用該命令刪除
? ? ? ? mset k1 v1 k2 v2 k3 v3 //批量讀寫可節(jié)省網(wǎng)絡(luò)消耗開銷
? ? ? ? mget k1 k2 k3
? ? ? ?過期策略
? ? ? ? expire name 5 //5s后過期
? ? ? ? setex name 5 dubian //等價于set+expire
? ? 計數(shù)
? ? ? ? 如果value是整數(shù),可對value進(jìn)行自增操作,范圍是singed long最大最小值,超過報錯
? ? ? ? set age 30? //OK
? ? ? ? incr age //31
? ? ? ? incrby age 4 //35
? ? ? ? incrby age -5 //30
2.2.list(列表)
? ? 特點:相當(dāng)于java的LinkedList,增刪快定位慢。列表元素為空數(shù)據(jù)結(jié)構(gòu)自動刪除,內(nèi)存回收(redis所有數(shù)據(jù)結(jié)構(gòu)都有此特性)。list底層是一個快速鏈表quicklist,在元素較少時會使用一塊連續(xù)的內(nèi)存存儲,稱為壓縮列表ziplist,當(dāng)數(shù)據(jù)較多才會變?yōu)閝uicklist。
? ? 隊列FIFO:右邊進(jìn)左邊出?
????棧:右邊進(jìn)右邊出
? ? rpush key1 v1 v2 v3 //添加元素
? ? llen key1? ?//獲取長度
? ? rpop key1? ? ? ?lpop key1 //彈出元素
? ? rpush key1 v1? ? ? ? rpush key1 v1? //添加元素
? ? lindex key1 1? ? //返回v2,相當(dāng)于java鏈表的get(index)
? ? ltrim key1 1 2? //對列表進(jìn)行截斷操作,返回OK 。 Index可為負(fù)數(shù),-1表示倒數(shù)第一個元素,可用于實現(xiàn)一個定長列表
? ? lrang key1 0 -1 //獲取所有元素,O(n)謹(jǐn)慎使用
2.3.hash(字典)
? ? 特點:相當(dāng)于java的HashMap,同樣是數(shù)組+鏈表的二維結(jié)構(gòu),不同的是,redis的字典采用的是漸進(jìn)式rehash。漸進(jìn)式rehash查詢時會同時查詢兩個hash結(jié)構(gòu),然后在后續(xù)的定時任務(wù)和hash子指令中,循序漸進(jìn)的將舊hash內(nèi)容遷移到新hash中。
????hset key1 field1 v1? //如果字符串包含空格需要藥引號括起來
????hgetall key1 //獲取entry field與value間隔出現(xiàn)
????hget key1 field1 //獲取指定field值
????hmset key1 field1 v1 field2 v2 field3 v3 //批量set
? ? hincrby dubian age 1 //單個field可進(jìn)行計數(shù)
2.4.set(集合)
? ? ? ? 特點:相當(dāng)于java里的HashSet,其內(nèi)部的鍵值是唯一無序的,內(nèi)部實現(xiàn)相當(dāng)于一個特殊字典,字典中所有的value都是NULL。set結(jié)構(gòu)可以用來存儲中獎用戶id,因為有去重功能,保證同一個用戶不會中獎兩次。
? ? sadd key1 m1 m2 m3 //key1中若存在該member則返回0,否則返回1成功
? ? smembers key1 //獲取所有member
? ? sismember key1 m1 //查詢某個member是否存在,存在返回1,不存在返回0
? ? scard key1 //計數(shù)
2.5.zset有序列表
? ? 特點:類似于SortSet和HashMap的結(jié)合體,一方面它是set,保證了內(nèi)部member的唯一性,另一方面它可以給每個member一個score,代表這個member的排序權(quán)重。它內(nèi)部實現(xiàn)用一種叫跳躍鏈表的數(shù)據(jù)結(jié)構(gòu)。
? ? 格式:zadd key [NX|XX] [CH] [INCR] score member [score member ...]
? ? zadd key1 9.0 member1 8.0 member2 10.0 member3//return 1
? ? zrevange key1 0 -1 //按score降序排列,參數(shù)區(qū)間為排名范圍 ,相反指令zrange則為升序排列
? ? zcard key1 //計數(shù)
? ? zrank key1 member1 //查看member1的排名,socre越高返回值越高
????格式:zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
????zrangebyscore key1 0 9 //根據(jù)分值區(qū)間遍歷zset,WITHSCORES同時返回對于score值,LIMIT設(shè)置偏移量及返回個數(shù)?
3.過期時間
? ? Redis的所有數(shù)據(jù)結(jié)構(gòu)都可以設(shè)置過期時間,需要注意過期時間是以對象為單位,比如一個hash結(jié)構(gòu)的過期時間是整個hash對象的過期,另外如果設(shè)置了過期時間后你調(diào)用set方法修改了它,它的過期時間會消失。
? ? 格式:expire key seconds
? ? expire key1 10? //設(shè)置10秒后過期
? ? ttl key1 //查看對象的過期時間
4.分布式鎖
? ? redis實現(xiàn)分布式鎖的原理是在redis里面占一個“坑”,當(dāng)別的進(jìn)程也要進(jìn)來占時,發(fā)現(xiàn)已經(jīng)有人蹲在那里了,就只能放棄或稍后再試。占坑一般使用setnx指令與expire設(shè)置過期時間,用完調(diào)用del釋放這個坑。但是這里有個問題,當(dāng)邏輯執(zhí)行到中間出現(xiàn)異常時,可能會導(dǎo)致del指令沒有被調(diào)用,這樣就會陷入死鎖,而且還有一個問題,如果在setnx和expire直接服務(wù)器進(jìn)程突然掛掉,也可能會造成死鎖。所幸redis在2.8版本作者加入了set的擴(kuò)展參數(shù),使得setnx與expire可以一起執(zhí)行。
? ? 另外,也可以使用lua腳本解決一致性問題。
? ? redis中的lua腳本使用格式如下:
? ? eval script numkeys key [key ...] arg [arg ...]? //其中script是lua命令,numkeys聲明key數(shù)量,key列表,參數(shù)列表
? ? EVAL "redis.call('setnx',KEYS[1],ARGV[1]);redis.call('expire',KEYS[1],ARGV[2]);" 1 key1 value1 60? ?//該語句設(shè)置key為key1的過期時間為60秒。
? ? 分布式鎖的可重入性:可重入性是指在持有鎖的情況下再次請求加鎖,如果一個鎖支持在同一個線程多次加鎖,那么這個鎖就是可重入的。比如java語言里的ReentrantLock,redis分布式鎖如果需要支持可重入,需要對客戶端的set方法進(jìn)行包裝,使用線程ThreadLocal變量存儲當(dāng)前持有鎖的value。
redis的分布式鎖實現(xiàn)可參考:https://github.com/HZ00M/springboot-demo的RedisWithReentrantLock對象。
5.延時隊列
? ? 延時隊列一般使用Rabbitmq和kafka中間件實現(xiàn),相比于專業(yè)的消息隊列,并沒有非常多的高級特性,也沒有ack保證,該內(nèi)容僅作為一項知識點,作為參考。
? ? redis使用rpush/lpush操作入隊,lpop/rpop操作來出隊,但是會出現(xiàn)一個問題,如果隊列為空,那pop操作將會陷入死循環(huán),拉高客戶端CPU和redis的QPS。
? ? 因此,redis提供了blpop/brpop來阻塞讀,b就是blocking。另外如果出現(xiàn)空閑連接,一般服務(wù)器會主動斷開連接,bpop操作會拋出異常來,所有編寫客戶端時需要注意捕獲異常,進(jìn)行重試。
? ? 延時隊列也可以通過zset(有序列表)來實現(xiàn)??梢詫⑾⒒?qū)ο笮蛄谢梢粋€字符串作為zset的value(可使用fastjson進(jìn)行序列化),到期時間做為score,然后使用多個線程輪詢zset獲取到期的任務(wù)進(jìn)行處理,多線程可保證萬一一個線程掛了還有其他線程繼續(xù)處理,因為有多個線程,需要考慮并發(fā)爭搶任務(wù),保證任務(wù)不能被多次執(zhí)行。redis的zrem方法是多線程爭搶任務(wù)的關(guān)鍵,它的返回值決定了當(dāng)前實例有沒有搶到任務(wù)。(獲取到為1,獲取不到為0)
redis的延時隊列實現(xiàn)可參考:https://github.com/HZ00M/springboot-demo的RedisDelayQueue對象。
6.位圖
? ? 介紹:redis提供了位圖數(shù)據(jù)結(jié)構(gòu)(位圖不是特殊的數(shù)據(jù)結(jié)構(gòu),它的內(nèi)容其實就是普通的字符串,也就是byte[]數(shù)組) ,我們可以使用普通的get/set獲取或設(shè)置整個位圖的內(nèi)容? ?redis的位數(shù)組是自動擴(kuò)展,如果設(shè)置某個偏移值超出了現(xiàn)有的內(nèi)容范圍,就會自動進(jìn)行零擴(kuò)充。
????使用場景:如記錄簽到信息可大大節(jié)省存儲空間。
? ? 獲取某個字符的ASCII碼和二進(jìn)制數(shù)組可用Integer.valueOf(c)和Integer.toBinaryString(c)。
? ? 比如字符‘h’的ASCII碼為104,二進(jìn)制數(shù)組為01101000。
? ? 單個bit操作
????格式:setbit key offset value? //按位設(shè)值,offset 偏移量 value 0或1
? ? ? ? ? ? ? ?getbit key offset? //按位取
? ? 如設(shè)置'h',其二進(jìn)制數(shù)組2/3/5位為1
? ? setbit hello 1 1 ;setbit hello 2 1;setbit hello 4 1;? //相當(dāng)于set hello h
? ? get hello //返回h(此為整取,也可以使用bitget 命令進(jìn)行按位取)
? ? 統(tǒng)計與查找:redis提供了位圖統(tǒng)計指令bitcount和位圖查找指令bitpos,bitcount用于統(tǒng)計指定范圍內(nèi)1的個數(shù),bitpos查找用戶從哪一天開始簽到,如果指定了范圍參數(shù)[start,end],就可以統(tǒng)計某個時間范圍內(nèi)簽到多少天,但是start和end是字節(jié)索引,也就是說指定范圍必須是8的倍數(shù)。
? ? bitcount格式:bitcount key [start end]
? ? set sign hello?
? ? bitcount sign //返回21
? ? bitcount 0 1 //前兩個字符中1的位數(shù)
? ? bitpos格式:bitpos key bit [start] [end]
? ? bitpos sign 1 1 1 //從第二個字符算起,第一個1位
? ? bitpos sign 1 2 2 //從第三個字符算起,第一個1位
? ? 魔術(shù)指令bitfield:可以一次進(jìn)行多次設(shè)置(setbit)和獲?。╣etbit),bitfiled有三個子指令,分別是get/set/incrby,它們都可以對為片段進(jìn)行讀寫,但是最多只能處理64個連續(xù)的位。
? ? bitfield格式:bitfield key [get type offset] [set type offset value] [incrby type offset increment]
? ? 前面的設(shè)置‘h’可改為bitfield hello set u1 1 1 set u1 2 1 set u1 4 1,效果是一樣的。
? ? bitfield hello get u4 0 //從第一位開始取4位,結(jié)果是無符號數(shù)
? ? bitfield hello get i4 0? //從第一位開始取4位,結(jié)果是有符合數(shù)
? ? 所謂的有符號數(shù)是位數(shù)組中第一位是符號位,剩下的才是值,如第一位是1,那就是負(fù)數(shù),有符號位最多可以取64位,無符號數(shù)最多可取63位。
? ? incrby子指令用來對指定范圍的位進(jìn)行自增操作,既然是自增,就有可能溢出,如果增加的是正數(shù),就有可能上溢,增加的是負(fù)數(shù),就有可能下溢。如果溢出,就將溢出的符號位丟掉,如果是8位的無符號數(shù)255,加一就會溢出,全部變成零。如果有符號位數(shù)127加一就會溢出,變成-128。redis提供三個溢出策略,默認(rèn)是折返(wrap),還可以選擇失敗不執(zhí)行,還可以進(jìn)行飽和截斷(sat)
? ? 如:bitfield hellow overflow sat incrby u4 2 1 //從第三位起取4位加1,溢出則保留最大值
7.HyperLogLog
? ? 介紹:HyperLogLog提供不精確的去重技術(shù)方案(標(biāo)準(zhǔn)誤差0.81%),是redis的高級數(shù)據(jù)結(jié)構(gòu)。
? ? 使用場景:計算UV(PV是頁面訪問量,UV是用戶量),如使用set存儲UV,會很浪費存儲空間,因此可以使用內(nèi)存占用率低的HyperLogLog。
? ? HyperLogLog格式:pfadd key member (對應(yīng)sadd)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pfcount key (對應(yīng)scard)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pfmerge distkey sourcekey [sourcekey ...](用于多個pf計數(shù)值得累加)
8.布隆過濾器
? ? 介紹:布隆過濾器可以理解為一個不name精確的set,在redis4.0之后才提供。布隆過濾器有兩個基本指令,bf.add添加元素,bf.exists查詢元素是否存在,它的用法和set集合的sadd和sismember差不多,注意一次只能添加一個元素,如需添加多個要用到bf.madd,同樣查詢多個使用bf.mexists。
? ? bf.add key1 member1
? ? bf.exists key1 member1 //1存在0不存在
? ? bf.madd key1 member1 member2 ...
? ? bf.mexists key1 member1 member2 //返回多個值 1 1 ...
? ? 布隆過濾器有一定的誤判性,因此redis還提供了自定義參數(shù)的布隆過濾器,需要我們在add之前使用bf.reserve顯式創(chuàng)建,bf.reserve有三個參數(shù),分別是key,error_rate和initial_size。錯誤率越低需要的空間越大,initial_size表示預(yù)計的元素數(shù)量,當(dāng)實際數(shù)量超出這個數(shù)值時,誤判率會上升。如不使用bf.reserve,默認(rèn)的error_rate是0.01,initial_size是100。
? ? 擴(kuò)展:布隆過濾器在NoSQL領(lǐng)域使用非常廣泛,我們平時用到的HBase,Cassandra,LevelDB,RocksDB內(nèi)部都有布隆過濾器結(jié)構(gòu)。布隆過濾器可以顯著降低數(shù)據(jù)庫IO請求數(shù)量。
9.限流策略
? ? redis的限流可使用zset實現(xiàn),通過score圈出一個時間窗口,窗口外的數(shù)據(jù)都可以砍掉,而value只要保證唯一性即可,如使用時間戳。
? ? 具體方法:用一個zset結(jié)構(gòu)記錄用戶的行為歷史,每一個行為作為zset中的一個key,同一個用戶的同一個行為用一個key記錄。通過統(tǒng)計窗口內(nèi)行為數(shù)量與閾值進(jìn)行比較,就可以得出當(dāng)前行為是否允許。?
? ? redis4.0提供了一個限流redis模塊,它叫redis-cell,該模塊使用了漏斗算法。
? ??漏桶算法(Leaky Bucket):主要目的是控制數(shù)據(jù)注入的速率,平滑操作次數(shù)。漏桶算法提供了一種機制,通過它,突發(fā)流量可以被整形以便提供一個穩(wěn)定的流量。漏桶算法的示意圖如下:

? ? 該模塊只有一條指令 cl.throttle
? ? cl.throttle key1 15 30 60 1 // 15為容量,30/60為速率 ,60秒內(nèi)30次操作 ,1 quota 多長時間漏斗完全空出來。返回值為【0,15,14,-1,2 】返回值第一個參數(shù)0表示允許,1表示拒絕。15表示漏斗容量,14表示剩余容量,第四個參數(shù)表示多長時間后可以再試(有空間了),第五個參數(shù)表示多長時間后漏斗完全空出來
? ? 上面這條指令的意思是允許key1的操作次數(shù)每60秒最多30次,初始容量為15是說一開始連續(xù)操作15次后才開始受速率影響,在執(zhí)行限流指令時,如果被拒絕了,就需要丟棄或重試,可直接用第四個參數(shù)的值進(jìn)行sleep后重試。
10.GeoHash
? ? GeoHash算法:業(yè)界通用的地理位置距離排序算法,算法將二維的經(jīng)緯度映射到一維數(shù)組,這樣就將所有的元素都掛載到一條直線上。
? ? Geo的內(nèi)部結(jié)構(gòu)實際上就是一個zset結(jié)構(gòu),score是geohash的52位整數(shù)值,value是元素的key通過score排序就可以得到坐標(biāo)附近的其他元素,并通過score還原成坐標(biāo)值就可以得到元素的原始坐標(biāo)。
? ? Geo有6條指令,格式如下:
? ? 添加元素:geoadd key longtitude latitude member [ longtitue latituemember...]
? ? 計算距離:geodist key member1 member2 [unit]
? ? 獲取元素坐標(biāo):geopos key member1 [member2 ...]
? ? 獲取geohash值:geohash key member1 [member2 ...]
? ? 獲取指定元素附近的元素:georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [count value] asc|desc?
? ? 根據(jù)坐標(biāo)值查詢附近元素【附近的車】【附近的餐館】:
? ? georadius key longtitue latitue radius m|km|ft|mi?[withdist] [withhash] [count value]?asc|desc
? ? geo數(shù)據(jù)如果過大,建議進(jìn)行拆分,且數(shù)據(jù)使用單獨的redis部署,不使用集群環(huán)境。
11.檢索
????keys格式:keys pattern? ? ?(采用遍歷算法,時間復(fù)雜度為O(n))
? ? scan格式:scan cursor [match pattern] [count count] (count不是限定數(shù)量,而是限定服務(wù)器單次遍歷字典槽位的數(shù)量,如果游標(biāo)的返回值不為零,說明遍歷還沒結(jié)束)
? ? scan采用的是高位進(jìn)位加法來遍歷,高位進(jìn)位可避免擴(kuò)容和縮容時槽位的遍歷和遺漏。? ??
? ? 大key掃描:大key掃描是檢索redis中的大對象,可在客戶端啟動時加上--bigkeys,如果擔(dān)心這個指令會抬升redis的ops,還可增加一個參數(shù) -i 0.1,上面指令的意思是每隔100條scan指令就會休眠0.1s,ops就不會劇烈抬升,但掃描的時間會變長。
12.持久化
? ? redis的持久化機制有兩種,第一種是快照,第二種是aof日志??煺帐且淮稳總浞荩琣of日志是連續(xù)的增量備份。
? ?快照原理: redis使用操作系統(tǒng)的多進(jìn)程COW(copy on write)機制來實現(xiàn)快照持久化。redis在持久化時會調(diào)用glibc的函數(shù)fork產(chǎn)生一個子進(jìn)程,快照持久化操作完全交給子進(jìn)程來處理,子進(jìn)程剛剛產(chǎn)生時,它與父進(jìn)程共享內(nèi)存里的代碼段和數(shù)據(jù)段,子進(jìn)程在做數(shù)據(jù)持久化時不會修改現(xiàn)有的內(nèi)存數(shù)據(jù)結(jié)構(gòu),它只是對數(shù)據(jù)結(jié)構(gòu)進(jìn)行遍歷讀取,然后序列化到磁盤中。當(dāng)父進(jìn)程對數(shù)據(jù)進(jìn)行修改時,會將被修改的數(shù)據(jù)共享頁復(fù)制一份分離出來,然后對這個復(fù)制頁面進(jìn)行修改,隨 著越來越多的共享頁面的分離,內(nèi)存會持續(xù)增長,但最高不會原數(shù)據(jù)內(nèi)存的2倍??煺諘G失大量數(shù)據(jù)。? ??
aof原理:aof日志存儲的是redis的順序指令序列,只記錄對內(nèi)存數(shù)據(jù)進(jìn)行修改的指令。在redis長期運行過程中,aof會變得越來越長,如果實例宕機重啟,aof日志會非常耗時,此時需要對aof日志進(jìn)行瘦身,redis提供bgrewriteaof?指令對aof日志進(jìn)行瘦身 。
? ? Linux的glibc提供了fsync(int fd)函數(shù)可以將指定內(nèi)容強制從內(nèi)核緩存刷到磁盤,只要redis實時調(diào)用fsync函數(shù)就可以保證aof日志不丟失。但fsync是一個磁盤io操作,它很慢,如果redis每執(zhí)行一條指令就要fsync一次,那redis的高性能地位就不保了。redis默認(rèn)每隔一秒fsync一次,該周期是可配置的,redis另外還提供了兩個策略:一個是永不,讓操作系統(tǒng)決定合適同步磁盤,很不安全;另外一個是一個指令就fsync一次,但生產(chǎn)環(huán)境最好不要使用??稍谂渲梦募锌吹竭@幾個配置:
#appendfsync always? ??
appendfsync everysec
# appendfsync no????
redis4.0混合持久化。原理是redis重啟的時候先加載快照內(nèi)容(.rdb),然后再重放增量aof日志。
13.管道
????管道本質(zhì)是將多個操作指令由客戶端封裝成數(shù)據(jù)包一次性發(fā)送給服務(wù)端進(jìn)行批量操作,達(dá)到節(jié)省io的目的,管道中指令越多,效果越好。
redis自帶了壓力測試工具redis-benchmark?,使用這個工具可以進(jìn)行管道測試
? ? >redis-benchmark -t set -q //返回 set:51452 requests per second
? ? 我們加入管道選項-P參數(shù),它表示單個管道內(nèi)并行請求的數(shù)量,當(dāng)P=2,QPS可達(dá)到9w/s。
14.事務(wù)
? ? redis同樣提供了事務(wù)機制,有三個指令,分別是multi/exec/discard。multi表示事務(wù)開始,exec表示事務(wù)執(zhí)行,discard表示事務(wù)丟棄。
? ? redis的事務(wù)失敗后,后面的指令還會繼續(xù)執(zhí)行,使用redis的事務(wù)不具備原子性,只能滿足隔離性(當(dāng)前事務(wù)不被其他事務(wù)打斷的權(quán)利)
? ? redis中的樂觀鎖:redis提供了watch機制,watch會在事務(wù)開始前盯住一個或多個鍵,當(dāng)事務(wù)執(zhí)行時,redis會檢測關(guān)鍵字自watch之后,是否被修改了(包括當(dāng)前事務(wù)所在的客戶端),如果關(guān)鍵字被人動過了,exec就會返回Null,告知客戶端事務(wù)執(zhí)行失敗,這時客戶端可進(jìn)行重試。
15.主從同步
????分布式理論的基石 --------? CAP原理
? ? ? ? C - Consistent , 一致性
? ? ? ? A - Availability,可用性
? ? ? ? P - Partiton tolerance,分區(qū)容忍性
? ? 分布式系統(tǒng)的節(jié)點往往都是分布在不同的機器上進(jìn)行網(wǎng)絡(luò)隔開的,這意味著必然有網(wǎng)絡(luò)斷開的風(fēng)險,這個斷開的場景叫做網(wǎng)絡(luò)分區(qū)。
? ? 在發(fā)送網(wǎng)絡(luò)分區(qū)時,兩個分布式節(jié)點無法互相通信,我們對一個節(jié)點進(jìn)行修改操作將無法同步到另外一個節(jié)點,所以數(shù)據(jù)的一致性無法得到滿足,因為兩節(jié)點數(shù)據(jù)不再保持一致,除非我們犧牲可用性,也就是暫停分布式節(jié)點服務(wù),在發(fā)生網(wǎng)絡(luò)分區(qū)時,不再提供修改數(shù)據(jù)功能,直到網(wǎng)絡(luò)恢復(fù)。
? ? 最終一致:redis的主從數(shù)據(jù)是異步同步的,所以分布式的redis不滿足一致性要求。當(dāng)客戶端從redis主節(jié)點修改了數(shù)據(jù)后,立即返回,即使在主從網(wǎng)絡(luò)斷開的情況下,主節(jié)點依舊可以正常對外提供服務(wù),所以redis滿足可用性。從節(jié)點在網(wǎng)絡(luò)恢復(fù)后會采用多種策略努力追趕落后的數(shù)據(jù)。
? ? 主從同步:redis支持主從同步和從從同步。
? ? 增量同步:redis同步的是指令流,主節(jié)點會將修改性的指令記錄在本地內(nèi)存buffer中,如何異步的將buffer中的指令記錄同步到從節(jié)點,從節(jié)點一步步執(zhí)行同步指令達(dá)到和主節(jié)點一樣的狀態(tài),同時反饋自己同步到哪里了(偏移量)。redis復(fù)制內(nèi)存buffer是一個定長的環(huán)形數(shù)組,如果因為網(wǎng)絡(luò)不好,redis主節(jié)點上那先沒有同步的指令可能會被后續(xù)的指令覆蓋,這時候就需要更復(fù)雜的同步機制,快照同步。
? ? 快照同步:快照同步是非常消耗資源的操作,它首先會進(jìn)行一次bgsave(產(chǎn)生.rdb),然后將快照傳送到從節(jié)點。快照接受完畢后,先清空當(dāng)前內(nèi)存,然后執(zhí)行一次全量加載,加載完成后通知主節(jié)點繼續(xù)進(jìn)行增量同步。但如果快照時間過長或者復(fù)制buffer太小,一樣會產(chǎn)生覆蓋問題,因此務(wù)必配置一個合適的復(fù)制buffer大小。
? ? 增加從節(jié)點:當(dāng)從節(jié)點剛加入集群時,它必須先進(jìn)行一次快照同步,完成后才進(jìn)行增量同步,redis2.8.18版本后快照文件將直接通過套接字傳輸減少主節(jié)點的io操作。
? ? wait指令:wait指令可以讓異步復(fù)制變成同步復(fù)制,確保強一致性。
? ? wait格式:wait numslaves timeout //numslave確保多少個從節(jié)點同步?jīng)]有滯后,timeout設(shè)置為0表示一直等待。
? ? 配置主從方式::
? ? ? ? 1:slaveof指令:從服務(wù)器啟動后,執(zhí)行slaveof host port?
? ? ? ? 2:配置方式:將
# slaveof <masterip> <masterport>
? ? ? ? ? ? ? ? ? ? ? ? ? ? 改成
slaveof 127.0.0.1 6379
? ?? ????????????????????????????????masterauth redis
????主從復(fù)制是系統(tǒng)數(shù)據(jù)安全的保障,必須認(rèn)真對待。
16.Sentinel(哨兵模式)
? ? 哨兵模式可以在故障發(fā)生時自動進(jìn)行主從切換,redis提供的redis sentinel可以看成一個zookeeper集群,一般由3~5個節(jié)點組成。當(dāng)客戶端連接集群時,首先連接sentinel,通過sentinel來查詢主節(jié)點地址,然后才進(jìn)行交互。
? ? 由于redis采用異步復(fù)制,無法保證消息完全不丟失,但可以保證消息少丟失。它有兩個選項可以限制主從延遲過大。
? ? min-slaves-to-write 1
? ? min-slaves-max-lag 10
? ? 第一個參數(shù)表示主節(jié)點至少有一個從節(jié)點在進(jìn)行正常復(fù)制,否則就停止對外寫服務(wù)。
? ? 何為正常復(fù)制,這個參數(shù)就是又第二個參數(shù)控制的,它的單位是秒,表示如果10秒內(nèi)沒有收到從節(jié)點的反饋,意味著同步不正常。
17.一主二從三哨兵模式搭建
? ? 假設(shè)有三臺服務(wù)器,ip分別為????127.1.1.1????,????127.1.1.2????,????127.1.1.3:
? ? 主庫配置:
? ? ? ? # 1. 修改綁定ip為服務(wù)器內(nèi)網(wǎng)ip地址,做綁定,三臺各自填寫各自的ip地址
????????bind 172.1.1.1
????????# 2. 保護(hù)模式修改為否,允許遠(yuǎn)程連接
????????protected-mode no
????????# 3. 設(shè)定密碼
????????requirepass"123"
????????# 4. 設(shè)定主庫密碼與當(dāng)前庫密碼同步,保證從庫能夠提升為主庫
? ? ? ? masterauth"123"
????????# 5. 打開AOF持久化支持
????????appendonly yes
兩個從庫配置:
? ??????# 1. 綁定的地址
????????bind172.1.1.2
????????# 2. 保護(hù)模式修改為否,允許遠(yuǎn)程連接
????????protected-mode no
????????# 3. 設(shè)定sentinel myid 每個都不一樣?
????????sentinel myid 04d9d3fef5508f60498ac014388571e719188527
????????# 4. 設(shè)定監(jiān)控地址,為對應(yīng)的主redis庫的內(nèi)網(wǎng)地址
????????sentinel monitor mymaster 172.1.1.1 6379 2
????????# 5. 設(shè)定5秒內(nèi)沒有響應(yīng),說明服務(wù)器掛了,需要將配置放在sentinel monitor master 127.0.0.1 6379 1下面
????????sentinel down-after-milliseconds mymaster 5000
????????# 6. 主數(shù)據(jù)庫密碼,需要將配置放在sentinel monitor master 配置下面
????????sentinel auth-pass mymaster 123
????????# 7. 設(shè)定15秒內(nèi)master沒有活起來,就重新選舉主
????????sentinel failover-timeout mymaster 15000
????????# 8. 表示如果master重新選出來后,其它slave節(jié)點能同時并行從新master同步緩存的臺數(shù)有多少個,顯然該值越大,所有slave節(jié)點完成同步切換的整體速度越快,但如果此時正好有人在訪問這些slave,可能造成讀取失敗,影響面會更廣。最保定的設(shè)置為1,只同一時間,只能有一臺干這件事,這樣其它slave還能繼續(xù)服務(wù),但是所有slave全部完成緩存更新同步的進(jìn)程將變慢。
????????sentinel parallel-syncs mymaster 2
18.消息隊列Stream
? ? 介紹:redis5.0提供的一個新的數(shù)據(jù)結(jié)構(gòu)stream,是一個強大的支持多播的可持久化消息隊列,它將所有加入的消息都串起來,每個消息都有一個唯一的ID和對應(yīng)的內(nèi)容。消息是持久化的,redis重啟之后,內(nèi)容還在。每個stream都有一個唯一的名稱,它就是redis的key,在我們首次使用xadd時自動創(chuàng)建。
? ? 每個stream可以掛多個消費組,每個消費組都有個游標(biāo)last_delivered_id在stream數(shù)組上往前移動,表示當(dāng)前消費組已經(jīng)消費到哪條消息了。每個消費組都有一個stream內(nèi)唯一的名稱,消費組不會自動創(chuàng)建,它需要單獨的指令xgroup create進(jìn)行創(chuàng)建需要指定從stream的哪條消息開始消費。這個id用來初始化last_delivered_id變量。
? ? 每個消費組的狀態(tài)都是相互獨立的,也就是說stream內(nèi)部的消息會被每個消費組消費到。
? ? 同一個消費組可以掛接多個消費者,這些消費者之間是競爭關(guān)系,消費者內(nèi)部有一個pending_ids(Pending Entries List),它記錄了當(dāng)前已經(jīng)被客戶端讀取的消息,但是還沒有ack,這是一個很核心的數(shù)據(jù)結(jié)構(gòu),它用來確??蛻舳酥辽傧M了一次消息。
? ? 增刪查改:
? ? 1.xadd [maxlen len]? key? #|*? ?key1 value1 [key2 value2 ...]? //追加消息, *和#表示服務(wù)器自動生成ID,maxlen提供一個定長,可以將老的消息干掉,確保不會超出指定長度
? ? 2.xdel key? ID //刪除消息
? ? 3.xrange? - +? //獲取消息列表,會自動過濾已經(jīng)刪除的消息,+ -表示最大值和最小值,也可以指定ID如xrange? -? 1482837165811-0
? ? 4.xlen? key? //消息長度,刪除操作對長度沒有影響
? ? 5.del key? ?//刪除stream
? ? 6.xread count limit streams key ID //從stream頭部讀取limit?條信息,當(dāng)使用xread時,可以忽略消費組
? ? ? ? xread block 0 count 1 streams key1 $ //從尾部阻塞等待新消息到來,block 0 表示永遠(yuǎn)阻塞,block 1000表示阻塞1S,一秒內(nèi)沒有任何消息到來就返回nil;
? ? 創(chuàng)建消費組:
? ? stream通過xgroup create指令創(chuàng)建消費組,需要傳遞起始ID。
? ? xgroup create key1 group1 0-0 //表示從頭開始消費
? ? xgroup create key1 group2 $? //$表示從尾部開始消費,只接受新消息
? ? xinfo stream key1//獲取stream信息
? ? xinfo groups group1 //獲取stream消費組信息
? ? xreadgroup GROUP group1 comsumer1 count 1 streams key1 > // >表示從當(dāng)前消費組的last_delivered_id后開始讀,每當(dāng)消費者讀取一條消息,last_delivered_id就會前進(jìn)
? ? xinfo comsumers key1 group1 # //查看group1每個消費者的狀態(tài)
? ? xack key1 group1 ID //確認(rèn)一條消息 ,待處理消息(peding)變成了4條?
19.查詢指令(info)
? ? info指令顯示的信息非常多,分為9大塊:
? ? 1.server服務(wù)器運行環(huán)境參數(shù)
? ? 2.clients客戶端相關(guān)信息
? ? 3.memory服務(wù)器運行內(nèi)存統(tǒng)計信息
? ? 4.persistence持久化信息
? ? 5.stats通用統(tǒng)計數(shù)據(jù)
? ? 6.replication主從復(fù)制相關(guān)信息
? ? 7.cpu cpu相關(guān)信息
? ? 8.cluster集群信息
? ? 9.keyspace鍵值對統(tǒng)計數(shù)量信息
? ? info的參數(shù)非常多,以下挑選關(guān)鍵性的、且非常實用的參數(shù)詳解:
?info stats//redis每秒執(zhí)行多少次指令?
? ? instantaneous_ops_per_sec:789 //表示所有客戶端每秒會發(fā)送789條指令到服務(wù)器
? ? info clients //redis連接了多少客戶端
? ? connected_clients:125 //這個就是正在連接的客戶端數(shù)量
? ? client list? ? ?//可以使用這個指令列出所有客戶端的源頭
? ? rejected_connetctions參數(shù)表示因為超出連接數(shù)限制而被拒絕連接的次數(shù),如果這個數(shù)字很大,說明需要調(diào)整maxclients參數(shù)
?info memory//查看內(nèi)存信息
? ? use_memory_human:828.22k? //內(nèi)存分配器(jemalloc)從操作系統(tǒng)分配的內(nèi)存總量
? ? use_memory_rss_human:3.11M? //操作系統(tǒng)看到的內(nèi)存占用,top命令看到的內(nèi)存
? ? use_memory_peak_human:842.11k? //redis內(nèi)存消耗的峰值
? ? use_memory_lua_human:21.00k? //lua腳本占用的內(nèi)存大小
? ? 如果單個redis內(nèi)存占用過大,需要考慮集群
info replication//查看復(fù)制模塊信息
? ? repl_backlog_active:0
? ? repl_blocklog_size:1048489? ? //這個就是擠壓緩沖區(qū)大小
? ? 復(fù)制積壓緩沖區(qū)大小非常重要,它直接影響到主從復(fù)制的效率。積壓緩沖區(qū)是環(huán)形的。
? ? 可查看sync_partial_err變量的次數(shù)確定是否要擴(kuò)大積壓緩沖區(qū),它表示主從半同步復(fù)制失敗的次數(shù)。
集群方案1(codis)
集群方案2(redisCluster)