Redis

NOsql

泛指非關(guān)系型數(shù)據(jù)庫,為了克服超大規(guī)模的高并發(fā)的問題,NoSQL在當今大數(shù)據(jù)環(huán)境下發(fā)展的十分迅速,Redis是發(fā)展最快的。

方便擴展(數(shù)據(jù)之間沒有關(guān)系)

大數(shù)據(jù)量高性能(Redis一秒寫8萬次,讀取11萬次,NoSQL的緩存記錄級,是一種細粒度的緩存,性能會比較高)

數(shù)據(jù)類型是多樣的(不需要事先設計數(shù)據(jù)庫)

發(fā)展歷程

單機MySQL->緩存+Mysql+垂直拆分(讀寫分離)->分庫分表+水平拆分+服務器集群

四大分類

K-V鍵值對 -Redis

文檔型數(shù)據(jù)庫

MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫,C++編寫,主要用來處理大量的文檔!

MongoDB是一個介于關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫中間的產(chǎn)品

MongoDB是非關(guān)系型數(shù)據(jù)庫中功能最豐富的

列存儲數(shù)據(jù)庫 -HBase? ? ? ? ? ? ? ? ? ? ? ? ? ? ? -分布式文件系統(tǒng)

圖關(guān)系數(shù)據(jù)庫 -Neo4J? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? -InfoGird

Redis入門

簡介:一個開源的使用ANSI C語言編寫,支持網(wǎng)絡,可基于內(nèi)存衣可持久化的日志型,K-V數(shù)據(jù)庫,并提供多種語言的API。免費和開源!

windows安裝

下載安裝包

通過CMD啟動,cd到redis的安裝目錄下

運行命令 redis-server redis.windows.conf

Linux安裝

下載安裝包,放到/opt目錄下 ,解壓

進入解壓后的文件,找到redis.conf

yum install gcc-c++ ? ?

make ? //下載環(huán)境

make install

redis的默認安裝路徑? /usr/local/bin

復制配置文件到指定目錄

redis配置文件復制

redis默認不是后臺啟動的,修改配置文件,使redis后臺啟動

后臺啟動

啟動redis服務

啟動及測試

查看redis進程是否開啟

Redis性能測試

redis -benchmark

redis性能測試參數(shù)

Redis基礎(chǔ)

redis有16個數(shù)據(jù)庫,默認使用第0個。

Redis是單線程的,基于內(nèi)存操作,CPU不是Redis的性能瓶頸,Redis的瓶頸是根據(jù)機器的內(nèi)存和網(wǎng)絡帶寬,既然可以使用單線程來實現(xiàn),就使用單線程來實現(xiàn)

Redis是C語言寫的,每秒100000+的QPS,完全不比同樣是使用key-value的Memecache(一套分布式的快取系統(tǒng))差.

Redis為什么單線程還這么快?

誤區(qū)1:高性能的服務器一定是多線程的?

誤區(qū)2:多線程(CPU上下文會切換)一定比單線程效率高!

核心:redis將所有的數(shù)據(jù)全部放在內(nèi)存中,所以使用單線程去操作效率最高,多線程(CPU上下文會切換:耗時的操作),對于內(nèi)存系統(tǒng)來說,如果沒有上下文切換效率就是最高的!多次讀寫都是在一個CPU上的,這就是最佳方案。

五大數(shù)據(jù)類型

Redis-Key

setkey value#set key

keys *#查看所有key

exists key#判斷當前key是否存在

move key database#移除當前key

expire key seconds#設置key的過期時間,單位秒

tll key#查看當前key的剩余時間

type key#查看當前key的類型

append key “”#追加/如key不存在就相當于set

strlen key#獲取字符創(chuàng)的長度

################################################

#步長 i+=

#i++

setviews0#初始瀏覽量為0

incr views#自增1

decr views#自減1

incrby views10#可以設置步長,指定增量

###################################################

#字符串范圍? range

GETRANGE key03#截取字符串[0,3]

GETRANGE key0-1#獲取全部的字符串

#替換

SETRANGE key1xx#替換指定位置開始的字符串

#######################################################

#setex (set with expire) #設置過期時間

#setnx (set if not exist) #不存在 再設置 (在分布式鎖種會常常使用!)

############################################################

mset#同時設置多個值

mget#同時獲取多個值

#對象

setuser:1 {name:wir,age:3}#設置一個user:1對象值為json字符來保存一個對象

#######################################################################

getset#先get再set

#如果不存在值,怎創(chuàng)建返回nil;如果存在值,獲取原來的值并設置新值

String

String類似的使用場景:value除了是字符串還可以是數(shù)字

計數(shù)器

統(tǒng)計多單位的數(shù)量

List(命令l開頭)

基本的數(shù)據(jù)類型,列表;可以用list實現(xiàn)棧,隊列,阻塞隊列。

LPUSH list one#將一個值(多個),插入到列表的頭部(左)

RPUSH list right#將一個值(多個),插入到列表的頭部(右)

LRANGE list0-1#查詢list

#####################################################

LPOP

RPOP

LPOP list#移除list的第一個元素

RPOP list#移除list的最后一個元素

#########################################################

Llen? list#返回list的長度

###############################

lrem list1one#移除 list集合中指定個數(shù)的value

ltrim list12#通過下標截取指定的長度

##################################################

rpoplpush#移除列表的最后一個元素,將它移動到新的列表中!

rpoplpush list1 list2

###################################################

小結(jié)

list實際上類似鏈表,left,right,before Node after 都可以插入值

如果key不存在,創(chuàng)建新的鏈表

如果key存在,新增內(nèi)容

如果移除了所有值,鏈表空,表示不存在

在兩邊插入或者改動值效率最高!中間元素,相對來說效率會低一點~

消息排隊!消息隊列(Lpush Rpop),棧(Lpush Lpop)

Set(集合)

##########################################################

sadd myset"hello"#set集合紅添加元素

SMEMBERS myser#查看指定set的所有值

SISMEMBER myset hello#判斷某一個值在集合中是否存在

########################################

srem myset hello#移除set集合中的指定元素

########################################

SRANDMEMBER myset /2#隨機拿出一個元素 /指定個數(shù)的元素

#################################

spop myset#隨機刪除key中的元素

#########################

smove key1 key2"xxx"#將xxx移動到key2 中

##############################

SDIFF k1 k2#查看k1 k2兩個集合中不同的元素

SINTER k1 k2#查看k1 k2兩個集合中相同的元素

SUNION k1 k2#查看k1 k2兩個集合中所有元素

Hash(哈希)

key -<key,value>(map)!這個value是一個map集合 ;可以做變更數(shù)據(jù),例如用戶信息

##############################################

hset key field1 value#set一個具體的 key-value

hmset key field1 value11 field2 value22#同時set多個具體的k-v

hmget key field1 field2#獲取多個字段

hgetall key#獲取全部數(shù)據(jù)

######################################################

hdel key field1#刪除hash指定的key

#####################################################

hlen key#獲取hash表的字段數(shù)量

#####################################

HEXISTS key field1#判斷hash中指定字段是否存在

############################################

hkeys key#獲取所有的key

hvalues key#獲取所有的value

Zset(有序集合)

三種特殊數(shù)據(jù)類型

Geospatial-地理空間

#geoadd

#規(guī)則:兩極無法直接添加,一般通過程序一次性導入

#參數(shù) key 值(緯度,經(jīng)度,名稱)

geoadd china:city116.40.39.90 beijing#添加坐標

#geopos

geopos china:city beijing#獲取指定的城市的經(jīng)度和緯度

#geodist

geodist china:china beijin shanghai km# 兩地距離? 單位:m,km,mi(英里),ft(英尺)

#georadius

georadius china:city110301000km withdist withcoord count1#以經(jīng)緯度為中心1000km為半徑查找 顯示到中間距離的位置 顯示他人的定位信息 篩選出指定的結(jié)果

#georadiusbymember

georadiusbymember china:city beijing1000km#找出位于指定元素周圍的其他元素

Hyperloglog

占用的內(nèi)存是固定的,2^64不同的元素基數(shù),只要12KB內(nèi)存。0.18%錯誤率!

PFadd key

PFCOUNT key#統(tǒng)計

Bitmaps-位存儲

bitmaps位圖,數(shù)據(jù)結(jié)構(gòu)!都是操作二進制位來進行記錄,就只有0和1兩個狀態(tài)!

事務

Redis事務本質(zhì):一組命令的集合!一個事務中的所有命令都會被序列化,在事務執(zhí)行過程中,會按照順序執(zhí)行!

一次性,順序性,排他性!執(zhí)行一些列的命令!

Redis事務沒有隔離級別的概念!(不會出現(xiàn)臟讀,幻讀,不可重復讀)

所有的命令在事務中,并沒有直接被執(zhí)行!只有發(fā)起執(zhí)行命令的時候才會執(zhí)行!Exec

Redis單條命令是保證原子性的,但是事務不保證原子性

redis事務

開啟事務(multi)

命令入隊()

執(zhí)行事務(exec)

正常執(zhí)行事務

redis事務

放棄事務-discard#取消事務

編譯型異常(代碼有問題!命令有錯),事務中所有的命令都不會被執(zhí)行

運行時異常,如果事務隊列中存在語法錯誤,那么執(zhí)行命令的時候,其他命令是可以正常執(zhí)行的,錯誤命令會拋出異常

監(jiān)控! Watch

悲觀鎖:

悲觀,無論做什么都加鎖!效率低下

樂觀鎖:

樂觀,認為不會出問題,所以不加鎖!更新數(shù)據(jù)時去判斷在此期間是否有人修改數(shù)據(jù)。

獲取version

更新時比較version

Redis監(jiān)控測試

正常執(zhí)行成功!

127.0.0.1:6379> set money 100

OK

127.0.0.1:6379> set out 0

OK

127.0.0.1:6379> watch money #監(jiān)視money對象

OK

127.0.0.1:6379> multi #事務正常結(jié)束,數(shù)據(jù)期間沒有發(fā)生變動,這個時候就正常執(zhí)行成功

OK

127.0.0.1:6379(TX)> DECRBY money 20

QUEUED

127.0.0.1:6379(TX)> INCRBY out 20

QUEUED

127.0.0.1:6379(TX)> exec

1) (integer) 80

2) (integer) 20

如果事務執(zhí)行失??!就先unwatch(解除監(jiān)視)然后再watch(再次監(jiān)視),最后對比監(jiān)視的值是否發(fā)生變化,如果沒有變化,那么可以成功,如果有變化就執(zhí)行失敗!繼續(xù)重復。

Jedis

Jedis是Redis官方推薦的Java連接開發(fā)工具!使用Java操作Redis中間件

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>3.5.1</version>

</dependency>

具體方法同redis命令

Spring Boot整合

SpringBoot2.x之后,原來使用的jedis被替換為lettuce

jedis:才用的直連,多個線程操作的話,是不安全的,如果想要避免不安全,需要使用jedis pool 連接池!

lettuce :采用netty,實例可以在多個線程中進行共享,可以減少線程數(shù)量

源碼分析:

@Bean

@ConditionalOnMissingBean(name="redisTemplate")//如果沒有配置Bean會生效,所以可以自己定義一個redisTemplate來替換

@ConditionalOnSingleCandidate(RedisConnectionFactory.class)

publicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory) {

//默認的RedisTemplate沒有過多的設置,redis對象都是需要序列化的

//泛型都是object,類型,使用后需要強制類型轉(zhuǎn)換

RedisTemplate<Object,Object>template=newRedisTemplate<>();

template.setConnectionFactory(redisConnectionFactory);

returntemplate;

}

@Bean

@ConditionalOnMissingBean

@ConditionalOnSingleCandidate(RedisConnectionFactory.class)//String是redis中最常使用的類型,所以單獨提出來一個bean

publicStringRedisTemplatestringRedisTemplate(RedisConnectionFactoryredisConnectionFactory) {

StringRedisTemplatetemplate=newStringRedisTemplate();

template.setConnectionFactory(redisConnectionFactory);

returntemplate;

}

Redis持久化

Redis是基于內(nèi)存的數(shù)據(jù)庫,如果不將內(nèi)存中的數(shù)據(jù)保存到磁盤,那么一旦服務器進程退出,服務器中的數(shù)據(jù)庫狀態(tài)也會消失,所以Redis提供了持久化功能!

RDB(默認RDB,一般情況下不需要修改配置)

在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤,也就是快照。它恢復時是將快照文件直接讀到內(nèi)存里。

redis會單獨創(chuàng)建一個子進程來進行持久化,先將數(shù)據(jù)寫入一個臨時文件中,待持久化過程結(jié)束,在用臨時文件替換上次持久化好的文件。整個過程中,主進程是不進行任何IO操作的。這就確保了極高的性能。

如果需要進行大規(guī)模數(shù)據(jù)的恢復,且對于數(shù)據(jù)恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加搞笑。

RDB的缺點是最后一個持久化后的數(shù)據(jù)可能丟失。

rdb保存的文件是dump.rdb,在配置文件中的快照進行配置

觸發(fā)機制

save的規(guī)則滿足的情況下,會自動觸發(fā)rdb規(guī)則

執(zhí)行flushall命令,也會觸發(fā)rdb規(guī)則!

退出redis,也會產(chǎn)生rdb文件

備份會自動生成一個dump.rdb

如何恢復rdb文件!

只需要將rdb文件放在我們的redis啟動目錄就可以,redis啟動時會自動檢查dump.rdb并恢復其中的數(shù)據(jù)

優(yōu)點

適合大規(guī)模的數(shù)據(jù)恢復!

對數(shù)據(jù)的完整性要求不高!

缺點

需要一定的時間間隔進行操作!如果redis宕機了,這個最后一次修改的數(shù)據(jù)就沒有了

fork進程的時候,會占用一定的內(nèi)存空間

AOF(Append Only File)

將所有命令都記錄下來,恢復的時候會把這個文件全部執(zhí)行一遍

以日志的形式來記錄每個寫操縱,將Redis執(zhí)行過的所有指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啟動之初會讀取該文件重新構(gòu)建數(shù)據(jù),換言之,Redis重啟的話就根據(jù)日志文件的內(nèi)容將寫指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復工作

Aof保存的文件是appendonly.aof文件

redis默認不開啟aof,需要手動修改配置文件!將appendonly改為yes才能開啟aof

如果aof文件有問題,無法重新啟動redis服務,需要用redis-check-aof --fix appendonly-aof

如果aof文件大于64m!fork一個新的進程來將文件進行重寫

優(yōu)點和缺點

優(yōu)點:

每一次修改都同步,文件的完整性更好

默認每秒同步一次,可能會丟失一秒的數(shù)據(jù)

若從不同步,效率最高!

缺點:

相對于數(shù)據(jù)文件來說,aof遠遠大于rdb,修復的速度也比rdb慢!

Aof運行的效率也要比rdb慢,所以redis默認的持久化方式是rdb!

擴展:

RDB持久化方式能夠在指定的時間間隔內(nèi)對數(shù)據(jù)進行快照存儲

AOF持久化方式記錄每次對服務器的寫操作,當服務器重啟的時候回重新執(zhí)行這些命令來恢復原始數(shù)據(jù),AOF命令以Redis協(xié)議追加保存每次寫的操作到文件末尾,Redis還能對aof文件進行后臺重寫,防止aof文件體積不至于過大。

只做緩存,不需要使用任何持久化

同時開啟兩種持久化方式

在這種情況下當redis重啟的時候會優(yōu)先載入aof文件來恢復原始數(shù)據(jù),因為在通常情況下aof文件保存的數(shù)據(jù)集要比RDB文件保存的數(shù)據(jù)集完整

RDB的數(shù)據(jù)不實時,同時使用兩者時服務器重啟也只會找AOF文件,不建議只使用AOF,因為RDB更適合用于數(shù)據(jù)備份(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的Bug,留著作為一個萬一的手段。

性能建議

因為RDB文件只用作備份用途,建議只在Slave(從盤)上持久化RDB文件,而且只要15分鐘備份一次即可,只保留 save 900 1(15分鐘至少修改一條就開啟備份)這個規(guī)則。

如果Enable AOF,好處是在最惡劣情況下也只會丟失不超過兩秒數(shù)據(jù),啟動腳本較簡單只load自己的AOF文件就可以了,代價一是帶來了持續(xù)的IO,二是AOF rewirte的最后將重寫過程中產(chǎn)生的新數(shù)據(jù)寫到新文件造成的阻塞幾乎是不可避免的。只要硬盤許可,應該盡量減少AOF重寫的頻率,AOF重寫的基礎(chǔ)大小默認值64M太小了,可以設置到5G以上,默認超過原大小100%重寫可以改到適當?shù)臄?shù)值。

如果不開啟AOF,僅靠Master-Slave(主從復制) Repllcation實現(xiàn)高可用性也可以,能減少很多IO操作,也減少了重寫時帶來的系統(tǒng)波動,代價是Master/Slave同時宕機(斷電),會丟失十幾分鐘的數(shù)據(jù),啟動腳本也要比較兩個Master/Slave中的RDB文件,載入較新的那個,微博就是這種架構(gòu)。

Redis發(fā)布訂閱

Redis發(fā)布訂閱(pub/sub)是一種消息通信模式:發(fā)送者(pub)發(fā)送消息,訂閱者(sub)接收消息。微信,微博,關(guān)注系統(tǒng)!

Redis客戶端可以訂閱任意數(shù)量的頻道。

訂閱/發(fā)布消息圖:

發(fā)布訂閱原理

測試

訂閱端:

127.0.0.1:6379> SUBSCRIBE wirdeos#訂閱一個頻道

Reading messages... (press Ctrl-C to quit)

1)"subscribe"

2)"wirdeos"

3) (integer)1

#等待讀取推送的信息

1)"message"#消息

2)"wirdeos"#頻道

3)"1231341"#內(nèi)容

發(fā)送端:

127.0.0.1:6379> PUBLISH wirdeos 1231341 #發(fā)送者發(fā)送消息到頻道!

(integer) 1

原理

Redis是使用C實現(xiàn)的,通過分析Redis源碼里的pubsub.c文件,了解發(fā)布和訂閱機制的底層實現(xiàn),籍此加深對Redis的理解。

Redis通過PUBLISH,SUBSCRIBE和PSUBSCRIBE等命令實現(xiàn)發(fā)布和訂閱功能。

通過SUBSCRIBE命令訂閱某頻道后,redis-server里維護了一個字典,字典的鍵就是一個個channel,而字典的值則是一個鏈表,鏈表中保存了所有訂閱這個channel客戶端。SUBSCRIBE命令的關(guān)鍵,就是將客戶端添加到給定channel的訂閱鏈表中。

通過PUBLISH命令向訂閱者發(fā)送消息,redis-server會使用給定的頻道作為鍵,在它所維護的channel字典中查找記錄了訂閱這個頻道的所有客戶端鏈表,遍歷這個鏈表,將消息發(fā)布給所有訂閱者

Pub/Sub從字面理解就是發(fā)布(Publish)與訂閱(Subscribe),在Redis中可以設定對某一個key值進行消息發(fā)布及消息訂閱,當一個key值上進行了消息發(fā)布后,所有訂閱他的客戶端都會收到相應的消息。這一功能最明顯的用法就是用作實時消息系統(tǒng),比如普通的即使聊天,群聊等。

使用場景:

實時消息系統(tǒng)!

實時聊天!

訂閱關(guān)注系統(tǒng)!

Redis主從復制

主從復制,是指將一臺Redis服務器的數(shù)據(jù),復制到其他的Redis服務器。前者成為主節(jié)點(Master/leader),后者稱為從節(jié)點(slave/follower);數(shù)據(jù)的復制是單向的,只能由主節(jié)點到從節(jié)點。Master以寫為主,Slave以讀為主。

默認情況下,每臺Redis服務器都是主節(jié)點;且一個主節(jié)點可以有多個從節(jié)點(或沒有),但一個從節(jié)點只可以有一個主節(jié)點。

主從復制的作用主要包括:

數(shù)據(jù)冗余(重復數(shù)據(jù)):主從復制實現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式。

故障恢復:當主節(jié)點出現(xiàn)問題時,可以由從節(jié)點提供服務,實現(xiàn)快速的故障恢復;實際上是一種服務的冗余

負載均衡:在主從復制的基礎(chǔ)上,配合讀寫分離,可以由主節(jié)點提供寫服務,由從節(jié)點提供讀服務(即寫數(shù)據(jù)時應用連接主節(jié)點,讀Redis數(shù)據(jù)應用連接從節(jié)點),分擔服務器負載;尤其是在寫少讀多的場景下,通過多個從節(jié)點分擔讀負載,可以大大提高Redis服務器的并發(fā)量。

高可用(集群)基石:除了上述作用以外,主從復制還是哨兵和集群能夠?qū)嵤┑幕A(chǔ),因此說主從復制時Redis高可用的基礎(chǔ)。

最少,一主二從

一般來說,要將redis運用于工程項目中,只用一臺redis是不夠的,原因如下:

從結(jié)構(gòu)上,單個Redis服務器會發(fā)色單點故障,并且一臺服務器需要處理所有的請求負載,壓力較大;

從容量上,單個Redis服務器內(nèi)部容量有限,無法將所有內(nèi)存用作Redis存儲內(nèi)存。一般來說,單臺Redis的最大使用內(nèi)存不應該超過20G

環(huán)境配置

只配置從庫,不用配置主庫!

[root@localhost bin]# redis-server wconfig/redis.conf

[root@localhost bin]# redis-cli -p 6379

127.0.0.1:6379> info replication#查看當前庫的信息

# Replication

role:master

connected_slaves:0#從機個數(shù)

master_failover_state:no-failover

master_replid:578832bddda2f86b82bf1cf619620397a44c0d98

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:0

second_repl_offset:-1

repl_backlog_active:0

repl_backlog_size:1048576

repl_backlog_first_byte_offset:0

repl_backlog_histlen:0

賦值配置文件,修改對應的信息

端口

pid名字

log文件名字

dump.rdb名字

redis集群環(huán)境

一主二從

默認情況下,每臺Redis服務器都是主節(jié)點;一般情況下只需要配置從機就好了!

SLAVEOF 主機ip 端口號#在從機中配置

真實的主從配置應該在配置文件中配置,這樣才是永久的,使用命令配置是暫時的.

主從復制配置文件

細節(jié)

主機可以寫,從機只能讀!主機中的所有信息和數(shù)據(jù),都會自動的被從機保存

測試:主機斷開連接,從機依舊連接到主機,但是沒有寫操作;主機如果重連,從機依舊可以獲取主機寫入的信息

如果是使用命令行配置主從,如果重啟從機,從機就會變回主機。如果重新設置成從機,那么還可以獲取主機數(shù)據(jù)

復制原理

從機啟動成功連接到主機后會發(fā)送一個同步命令

主機接到命令,啟動后臺的存盤進程,同時收集所有接受到的用于修改數(shù)據(jù)集命令,在后臺進程執(zhí)行完畢之后主機將整個數(shù)據(jù)文件傳到從機,并完成一次完全同步。

全量賦值:從機服務在接收到數(shù)據(jù)庫文件數(shù)據(jù)后,將其存盤并加載到內(nèi)存中

增量賦值:主機繼續(xù)將新的所有收集到的修改命令一次傳給從機完成同步

但是只要重新連接主機,一次完全同步(全量復制)將被自動執(zhí)行!數(shù)據(jù)一定可以在從機中看到

模式1
模式2

這個時候也可以完成主從復制

如果主節(jié)點斷開,這個時候只能手動完成(沒有哨兵模式)

SLAVEOF on one;若主機斷開,將從節(jié)點設置成主節(jié)點!其他的結(jié)點就可以手動操作到主節(jié)點

哨兵模式(redis2.8開始提供)

概述

能夠后臺監(jiān)控主機是否故障,如果故障了根據(jù)投票數(shù)自動將從庫轉(zhuǎn)為主庫

哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個獨立的進程,作為進程,它會獨立運行。其原理是哨兵通過發(fā)送命令,等待Redis服務器響應,從而監(jiān)控運行多個Redis實例。

哨兵模式原理圖

這里的哨兵有兩個作用

通過發(fā)送命令,讓Redis服務器返回監(jiān)控其運行狀態(tài),包括主服務器和從服務器

當哨兵監(jiān)測到master宕機,會自動將slave切換成master,然后通過發(fā)布訂閱模式通知其他的從服務器,修改配置文件,讓它們切換主機

然而一個哨兵進程對Redis服務器進行監(jiān)控,可能會出現(xiàn)問題,因此可以采用多哨兵進行監(jiān)控。各個哨兵之間還會進行監(jiān)控,這樣就形成了多哨兵模式。

多哨兵模式

假設主服務器宕機,哨兵1先檢測到這個結(jié)果,系統(tǒng)不會馬上進行重新選舉的過程,僅僅是哨兵1主觀的認為主服務器不可用,這個現(xiàn)象稱為主觀下線。當后面的哨兵也檢測到主服務器不可用,并且數(shù)量達到一定值時,那么哨兵之間就會進行一次投票,投票的結(jié)果由一個哨兵發(fā)起,進行故障轉(zhuǎn)移操作。切換成功后,就會通過發(fā)布訂閱模式,讓各個哨兵把自己監(jiān)控的從服務器實現(xiàn)切換主機,這個過程成為客觀下線

哨兵配置

[root@localhost wconfig]# vim sentinel.conf #在配置文件目錄下新建哨兵配置文件

#sentinel monitor 被監(jiān)控的名稱? host port 1 #開啟投票

sentinel monitor myredis127.0.0.163791

啟動哨兵

[root@localhost bin]# redis-sentinel wconfig/sentinel.conf

[root@localhost bin]# redis-sentinel wconfig/sentinel.conf

3450:X23Mar202114:01:35.952# oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo

3450:X23Mar202114:01:35.952# Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=3450, just started

3450:X23Mar202114:01:35.952# Configuration loaded

3450:X23Mar202114:01:35.953 * Increased maximum number of open files to10032(it was originallysetto1024).

3450:X23Mar202114:01:35.953 * monotonic clock: POSIX clock_gettime

? ? ? ? ? ? ?? _._ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

_.-``__''-._

_.-```.? `_.''-._ ? ? ? ? ? Redis6.2.1 (00000000/0)64bit

.-``.-```.? ```\/ ?? _.,_''-._

(' ? ?? , ? ? ? .-`? | `, ?? ) ? ? Running in sentinel mode

|`-._`-...-` __...-.``-._|'`_.-'| ? ? Port: 26379

|`-._ ? `._ ?? / ? ? _.-' ?? | ? ? PID: 3450

`-._ ?? `-._`-./? _.-' ?? _.-' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

|`-._`-._`-.__.-' ?? _.-'_.-'| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

|`-._`-._ ? ? ?? _.-'_.-'| ? ? ? ? ? http://redis.io

`-._ ?? `-._`-.__.-'_.-' ?? _.-' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

|`-._`-._`-.__.-' ?? _.-'_.-'| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

|`-._`-._ ? ? ?? _.-'_.-'|

`-._ ?? `-._`-.__.-'_.-' ?? _.-' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

`-._ ?? `-.__.-' ?? _.-'

`-._ ? ? ?? _.-' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

`-.__.-' ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

3450:X23Mar202114:01:35.954# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

3450:X23Mar202114:01:35.955# Sentinel ID is 80bbca2a11769d234d3cfb2b826429af2ae27f80

3450:X23Mar202114:01:35.955# +monitor master myredis 127.0.0.1 6379 quorum 1

3450:X23Mar202114:01:35.956 *+slave slave127.0.0.1:6380127.0.0.16380@ myredis127.0.0.16379

3450:X23Mar202114:01:35.965 *+slave slave127.0.0.1:6381127.0.0.16381@ myredis127.0.0.16379

如果主機宕機,哨兵會自動選出新的主機并做好遷移處理,而原主機重連之后,只能歸并到新的主機下變?yōu)閺臋C

哨兵模式

優(yōu)點:

哨兵集群基于主從復制模式,所有的主從配置優(yōu)點全都有

主從可以切換,故障可以轉(zhuǎn)義,系統(tǒng)可用性會更好

哨兵模式類似于主從模式的升級,從手動到自動,健壯性更好

缺點:

Redis不好在線擴容,集群容量一旦到達上線,在線擴容十分麻煩!

實現(xiàn)哨兵模式的配置很麻煩,選擇比較多

哨兵模式的全部配置

# Example ? sentinel.conf

# 哨兵sentinel實例運行的端口 ? 默認是26379,如果有哨兵集群,還需要配置每個哨兵端口

port26379

#哨兵sentinel的工作目錄

dir /tmp

#哨兵 sentine1 監(jiān)控的redis主節(jié)點的 ip port ?

# master-name? ,可以自己命名的主節(jié)點名字 只能由字母A-Z、數(shù)字0-9、這三個字符"? . ? -? _ "組成。

# quorum配置多少個sentine1哨兵統(tǒng)- -認為master主節(jié)點失聯(lián)那么這時客觀上認為主節(jié)點失聯(lián)了

# sentine1 monitor <master-name> <ip> <redis-port> <quorum>

sentinel monitor mymaster127.0.0.163792

#當在Redis實例中開啟了requirepass foobared 授權(quán)密碼這樣所有連接kedis實例的客戶端都要提供密碼

#設置哨兵sentinel連接主從的密碼注意必須為主從設置- - 樣的驗證密碼

# sentine1 auth-pass <master-name> <password>

sentine1 auth-pass mymaster MySUPER--secret-0123passwOrd

#指定多少毫秒之后主節(jié)點沒有應答哨兵sentine1 此時哨兵主觀上認為主節(jié)點下線默認30秒

# sentinel down-after-mi 11i seconds <master-name> <mi 11iseconds>

sentine1 down-after-mi 11iseconds mymaster30000

#這個配置項指定了在發(fā)生failover主備切換時最多可以有多少個slave同時對新的master進行同步,

這個數(shù)字越小,完成fai lover所需的時間就越長,

但是如果這個數(shù)字越大,就意味著越多的slave因為replication而 不可用。

可以通過將這個值設為1來保證每次只有一個slave處于不能處理命令請求的狀態(tài)。

# sentine1 paralle1-syncs <master-name> <numslaves>

sentine1 paralle1-syncs mymaster1

#故障轉(zhuǎn)移的超時時間failover-timeout 可以用在以下這些方面:

#1.同一個sentine1對同一 個master兩次fai lover之間的間隔時間。

#2.當一個slave從一 個錯誤的master那里同步數(shù)據(jù)開始計算時間。直到s1ave被糾正為向正確的master那里同步數(shù)據(jù)時。

#3.當想要取消一個正在進行的failover所需要的時間。

#4.當進行failover時,配置所有s1aves指向新的master所需的最大時間。不過,即使過了這個超時,slaves 依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規(guī)則來了

#默認三分鐘

# sentine1 failover-timeout <master-name> <milliseconds>

sentine1 fai lover-ti meout mymaster180000

# SCRIPTS EXECUTION

#配置當某一事件發(fā)生時所需要執(zhí)行的腳本,可以通過腳本來通知管理員,例如當系統(tǒng)運行不正常時發(fā)郵件通知相關(guān)人員。

#對于腳本的運行結(jié)果有以下規(guī)則:

#若腳本執(zhí)行后返回1,那么該腳本稍后將會被再次執(zhí)行,重復次數(shù)目前默認為10

#若腳本執(zhí)行后返回2,或者比2更高的一個返回值,腳本將不會重復執(zhí)行。

#如果腳本在執(zhí)行過程中由于收到系統(tǒng)中斷信號被終止了,則同返回值為1時的行為相同。

#一個腳本的最大執(zhí)行時間為60s,如果超過這個時間,腳本將會被-一個SIGKILL信號終止,之后重新執(zhí)行。

#通知型腳本:當sentine1有任何警告級別的事件發(fā)生時(比如說redis實例的主觀失效和客觀失效等等),將會去調(diào)用這個腳本,這時這個腳本應該通過郵件,SMS等 方式去通知系統(tǒng)管理員關(guān)于系統(tǒng)不正常運行的信息。調(diào)用該腳本時,將傳給腳本兩個參數(shù),一 個是事件的類型,一個是事件的描述。如果sentine1. conf配置文件中配置了這個腳本路徑,那么必須保證這個腳本存在于這個路徑,并且是可執(zhí)行的,否則sentine1無法正常啟動成功。

#通知腳本

# she11編程

# sentine1 notification-script <master-name> <script-path>

sentine1 notificati on-script mymaster /var/redis/notify.sh

#客戶端重新配置主節(jié)點參數(shù)腳本

#當一個master由于failover而發(fā)生改變時,這個腳本將會被調(diào)用,通知相關(guān)的客戶端關(guān)于master地址已經(jīng)發(fā)生改變的信息。

#以下參數(shù)將會在調(diào)用腳本時傳給腳本:

# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>

#目前<state>總是“failover",

# <role>是“Teader"或者"observer"中的-一個。

#參數(shù)from-ip, from-port, to-ip,to-port是用來和舊的master和新的master(即舊的s lave)通信的

#這個腳本應該是通用的,能被多次調(diào)用,不是針對性的。

# sentine1 client-reconfig-script <master-name> <script-path>

sentine1 client-reconfig-script mymaster /var/redis/reconfig.sh#一般都是由運維來配置!

Redis緩存穿透和雪崩

緩存穿透(查不到)

概念

緩存穿透,就是查一個數(shù)據(jù)緩存中沒有,然后向數(shù)據(jù)庫中查詢。發(fā)現(xiàn)數(shù)據(jù)庫也沒有,因此查詢失敗。而當數(shù)據(jù)訪問量特別大的時候,會對數(shù)據(jù)庫造成很大壓力,出現(xiàn)了緩存穿透。

解決方案

布隆過濾器

布隆過濾器是一種數(shù)據(jù)結(jié)構(gòu),對所以可能查詢的參數(shù)以hash形式存儲,在控制層先進行校驗,不符合則丟棄,從而避免了對底層存儲系統(tǒng)的查詢壓力。

布隆過濾器

優(yōu)缺點

優(yōu)點:由于存放的不是完整數(shù)據(jù),所以占用內(nèi)存少,而且新增,查詢速度快

缺點:鎖著數(shù)據(jù)的增加,誤判率會隨之增加;無法做到刪除數(shù)據(jù);也就是說布隆過濾器說不存在就一定不存在,說存在那么是可能存在。

緩存空對象

當存儲曾不命中后,即使返回空對象也將其緩存起來,同時或設置一個過期時間,之后再訪問這個數(shù)據(jù)將會從緩存中獲取,不會再訪問數(shù)據(jù)庫。

緩存空對象存在問題

如果空值可以被緩存,這就意味著需要更多的空間存儲更多的鍵,因為空值的鍵可能會占用很大空間

即使對空值設置過期時間,還是會存在緩存和數(shù)據(jù)庫的數(shù)據(jù)會有一段時間窗口不一致,對數(shù)據(jù)的一致性會有影響

緩存擊穿(庫有緩存無,量大)

概述

緩存擊穿指一個key非常熱點,在高并發(fā)的環(huán)境下,緩存中查不到,但是數(shù)據(jù)庫中可以查到,導致所有訪問都進入到數(shù)據(jù)庫中,數(shù)據(jù)庫瞬間壓力過大。

解決方案

設置value永不過期

加互斥鎖(類似synchronized)

分布式鎖:使用分布式鎖,保證對于每個key同一時間只有一個線程去查詢后端服務,其他線程只能等待。將高并發(fā)的壓力轉(zhuǎn)移到分布式鎖,因此對于分布式鎖的考驗很大

緩存雪崩

概述

緩存雪崩,指同一時間緩存大量失效,到時大量訪問全部進入數(shù)據(jù)庫,可能會造成數(shù)據(jù)庫崩潰進而導致網(wǎng)站崩潰

解決方案

Redis高可用-搭建集群

限流降級

數(shù)據(jù)預熱

正式部署之前,先把可能的數(shù)據(jù)預先訪問一遍,這樣部分可能大量訪問的數(shù)據(jù)就會加載到緩存中。在即將發(fā)生高并發(fā)訪問錢手動觸發(fā)加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容