Redis

因為沒有指定組態檔
需配置
redis-server redis.windows.conf
之后自動啟動
測驗性能
redis-benchmark -p 6379 -c 100 -n 10000


基礎概念:


清空當前資料庫:flushdb
清空全部資料庫:flushall
redis是單執行緒的
redis的瓶頸是機器的記憶體和網路的帶寬,用單執行緒既然可以實作,就用單執行緒了
為什么單執行緒還這么快呢
redis是將所有的資料全部放在記憶體中,所以說用單執行緒操作效率最高,多執行緒(cpu背景關系會切換:耗時的操作),對于記憶體系統來說,如果沒有背景關系切換效率就是最高的!多次讀寫都是在一個cpu上,在記憶體情況下,這個就是最佳的選擇,
底層資料結構(參考
簡單動態字串

一般來說,SDS 除了保存資料庫中的字串值以外,SDS 還可以作為緩沖區(buffer):包括 AOF 模塊中的AOF緩沖區以及客戶端狀態中的輸入緩沖區,
鏈表
Redis鏈表特性:
①、雙端:鏈表具有前置節點和后置節點的參考,獲取這兩個節點時間復雜度都為O(1),
②、無環:表頭節點的 prev 指標和表尾節點的 next 指標都指向 NULL,對鏈表的訪問都是以 NULL 結束,
③、帶鏈表長度計數器:通過 len 屬性獲取鏈表長度的時間復雜度為 O(1),
④、多型:鏈表節點使用 void* 指標來保存節點值,可以保存各種不同型別的值
字典
Redis 的字典使用哈希表作為底層實作、
key 用來保存鍵,val 屬性用來保存值,值可以是一個指標,也可以是uint64_t整數,也可以是int64_t整數,
注意這里還有一個指向下一個哈希表節點的指標,我們知道哈希表最大的問題是存在哈希沖突,如何解決哈希沖突,有開放地址法和鏈地址法,這里采用的便是鏈地址法,通過next這個指標可以將多個哈希值相同的鍵值對連接在一起,用來解決哈希沖突,
跳表
跳躍表(skiplist)是一種有序資料結構,它通過在每個節點中維持多個指向其它節點的指標,從而達到快速訪問節點的目的,具有如下性質:
1、由很多層結構組成;
2、每一層都是一個有序的鏈表,排列順序為由高層到底層,都至少包含兩個鏈表節點,分別是前面的head節點和后面的nil節點;
3、最底層的鏈表包含了所有的元素;
4、如果一個元素出現在某一層的鏈表中,那么在該層之下的鏈表也全都會出現(上一層的元素是當前層的元素的子集);
5、鏈表中的每個節點都包含兩個指標,一個指向同一層的下一個鏈表節點,另一個指向下一層的同一個鏈表節點;
? ①、搜索:從最高層的鏈表節點開始,如果比當前節點要大和比當前層的下一個節點要小,那么則往下找,也就是和當前層的下一層的節點的下一個節點進行比較,以此類推,一直找到最底層的最后一個節點,如果找到則回傳,反之則回傳空,
②、插入:首先確定插入的層數,有一種方法是假設拋一枚硬幣,如果是正面就累加,直到遇見反面為止,最后記錄正面的次數作為插入的層數,當確定插入的層數k后,則需要將新元素插入到從底層到k層,
③、洗掉:在各個層中找到包含指定值的節點,然后將節點從鏈表中洗掉即可,如果洗掉以后只剩下頭尾兩個節點,則洗掉這一層,
五大資料型別的應用場景
對于string 資料型別,因為string 型別是二進制安全的,可以用來存放圖片,視頻等內容,另外由于Redis的高性能讀寫功能,而string型別的value也可以是數字,可以用作計數器(INCR,DECR),比如分布式環境中統計系統的在線人數,秒殺等,
對于 hash 資料型別,value 存放的是鍵值對,比如可以做單點登錄存放用戶資訊,
對于 list 資料型別,可以實作簡單的訊息佇列,另外可以利用lrange命令,做基于redis的分頁功能
對于 set 資料型別,由于底層是字典實作的,查找元素特別快,另外set 資料型別不允許重復,利用這兩個特性我們可以進行全域去重,比如在用戶注冊模塊,判斷用戶名是否注冊;另外就是利用交集、并集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能,
對于 zset 資料型別,有序的集合,可以做范圍查找,排行榜應用,取 TOP N 操作等
五大資料型別
redis-key
#移除name key
move name 1

#設定過期時間
expire name 10

查看剩余過期時間:ttl name;
#查看鍵的型別
type name

String

如果append后的鍵不存在就創建一個,相當于set

獲取一部分值

獲取全部的值

替換值

setex 設定過期時間
setnx 如果沒有這個鍵就設定值成功,如果已存在這個鍵就設定不成功(在分布式鎖中常應用 )

批量設定鍵和值,批量獲取值

msetnx 具有原子性
設定物件,以json字串的形式

getset

List
在redis中,list可以被我們玩成堆疊,佇列,阻塞佇列
lpush 放進串列資料
lrange 取出指定位置的資料,可以看出下標是倒著來的,

說明rpush把值放在了佇列的最后面

從串列中移除值,可以分為移除左邊的和右邊的

通過下標獲取值

獲取串列長度
llen
移除指定的值,可指定數量

通過下標截取指定的長度

移除串列的最后一個元素,將他移動到新串列中

更新指定位置的值


set





hash
Map集合,key-map,那時候這個值是一個map集合,本質和String型別沒有太大區別,還是一個簡單的key-vlaue

獲取hash表的內容長度

獲取所有的field和所有的值

hash更適合于物件的存盤
Zset(有序集合)
排列

顯示工資小于2000的工資排列

移除指定元素

獲取集合中的個數
zcard salary
獲取指定區間的成員數量

總結:

三種特殊資料型別
Geospatial(地理位置)
geoadd 添加地理位置
geoadd key longitude latitude member [longitude latitude member ...]
geopos獲得地理位置詳細資訊
geopos key member [member ...]
geodist獲得兩個地點之間的距離,可在后面追加獲得結果的單位 km m
geodist key member1 member2 [unit]
georadius獲得以某一點經緯度為圓心,一定距離為半徑之內的元素
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC
georadiusbymember獲得某一成員為圓心,一定距離為半徑之內的元素
geo底層的實作原理是zset,可以使用zset命令來操作geo
hyperloglog
統計基數
可以用作網站的UV(一個人訪問網站多次,但是還是算作一個人)
傳統的方式是用set,如果存盤量太大的話就比較麻煩
測驗

bitmaps
位存盤
位圖,是資料結構,都是操作二進制為來進行操作,只有0和1兩個狀態
統計一周的打卡情況

查看某一天的打卡情況

查看打卡了幾天
127.0.0.1:6379> bitcount si
(integer) 2
事務
本質:一組命令的集合,所有命令都會被序列化,執行程序中,按照順序執行
redis單挑命令保存原子性,但是事務不保證原子性,沒有隔離級別的概念
所有命令在事務中,并不被直接執行,只有發起執行命令的時候才被執行
- 開啟事務
- 命令入隊
- 執行事務
正常執行事務
127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec#執行事務
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379>
放棄事務
discard
編譯型例外(代碼有問題),事務中所有命令都不會被執行
127.0.0.1:6379> get k1 (nil) 127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> getset k3 (error) ERR wrong number of arguments for 'getset' command 127.0.0.1:6379> get k1 QUEUED 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors.#所有事務不會被運行 127.0.0.1:6379>
運行時例外(1/0),其他命令正常執行,錯誤命令拋出例外
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1#字串不會加1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range#屬于運行時例外
2) "v1" #正常執行
127.0.0.1:6379>
監控
樂觀鎖
獲取version,比較version
監視:
watch key [key …]
執行之前,另外一個執行緒如果修改了我們的值,事務就會執行失敗,就要放棄監視,然后重新監視
放棄監視
unwatch key
Jedis
配置依賴
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
創建連接進行測驗
Jedis jedis=new Jedis("127.0.0.1", 6379);
System.out.println(jedis.ping());
springboot整合
底層為lettuce:采用netty,實體可以在多個執行緒中共享,不存在執行緒不安全的情況,NIO模式
jeids采用直連,多執行緒不安全,如想避免不安全,就使用jedis pool連接池,BIO模式
操作各種基本型別

獲得鏈接,操作資料庫

序列化
放入物件需序列化
@Configuration
public class RedisConfig {
//撰寫自己的redisTemplate
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {
RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper=new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//String的序列化
StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();
//key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
//Hash的序列化方式也采用String的方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
———————–固定配置模板
Redis.conf詳解

對大小寫不敏感
包含
可包含多個組態檔
網路
bind 127.0.0.1
protected-mode yes #保護模式
port 6379 #默認埠
系結的IP
通用
# NOT SUPPORTED ON WINDOWS daemonize no
#window端不支持此配置,配置此項須在linux端
daemonize yes #以守護行程的方式運行,默認是no,我們需要自己開啟為yes
# NOT SUPPORTED ON WINDOWS pidfile /var/run/redis.pid
#如果指定為后臺方式運行,則需指定pid檔案
pidfile /var/run/redis.pid
#日志級別
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" #日志檔案位置
databases 16 #默認資料庫數量
快照
持久化:在規定時間內,執行了多少次操作則會持久化到檔案.rdb .aof
reids是記憶體資料庫,如果沒有持久化,那么資料斷電即失,
save 900 1 #如果900s內,有一個key進行了修改,我們將進行持久化操作,以下皆同
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes#持久化出錯,redis是否還繼續作業
rdbcompression yes#是否壓縮rdb檔案
rdbchecksum yes #保存rdb檔案的時候,進行錯誤的檢查校驗
dir ./ #rdb檔案的保存目錄
安全
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> config set requirepass 1234 #設定密碼
OK
127.0.0.1:6379> config get requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 1234 #登錄
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "1234"
127.0.0.1:6379>

客戶端連接相關
# maxclients 10000a 最大客戶端數量
# maxmemory <bytes> 最大記憶體限制
# maxmemory-policy noeviction 記憶體到達極限值的處理策略
maxmemory-policy 六種方式
1、volatile-lru:只對設定了過期時間的key進行LRU(默認值)
2、allkeys-lru : 洗掉lru演算法的key
3、volatile-random:隨機洗掉即將過期key
4、allkeys-random:隨機洗掉
5、volatile-ttl : 洗掉即將過期的
6、noeviction : 永不過期,回傳錯誤
Redis持久化
RDB:Redis Databases
什么是RDB
在指定時間間隔后,將記憶體中的資料集快照寫入資料庫 (復制媒介);在恢復時候,直接讀取快照檔案,進行資料的恢復 ;

默認情況下, Redis 將資料庫快照保存在名字為 dump.rdb的二進制檔案中,檔案名可以在組態檔中進行自定義,
三種觸發方式

還有一種就是自動觸發
作業原理
在進行 RDB 的時候,**redis** 的主執行緒是不會做 io 操作的,主執行緒會 fork 一個子執行緒來完成該操作;
- Redis 呼叫forks,同時擁有父行程和子行程,
- 子行程將資料集寫入到一個臨時 RDB 檔案中,
- 當子行程完成對新 RDB 檔案的寫入時,Redis 用新 RDB 檔案替換原來的 RDB 檔案,并洗掉舊的 RDB 檔案,
這種作業方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益(因為是使用子行程進行寫操作,而父行程依然可以接收來自客戶端的請求,)

觸發機制
- save的規則滿足的情況下,會自動觸發rdb原則
- 執行flushall命令,也會觸發我們的rdb原則
- 退出redis,也會自動產生rdb檔案
優缺點
優點:
- 適合大規模的資料恢復
- 對資料的完整性要求不高
缺點:
耗時,耗性能
- 需要一定的時間間隔進行操作,如果redis意外宕機了,這個最后一次修改的資料就沒有了,由此引入AOF,
- fork行程的時候,會占用一定的內容空間,
AOF
Append Only File
將我們所有的命令都記錄下來,history,恢復的時候就把這個檔案全部再執行一遍
以日志的形式來記錄每個寫的操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,redis啟動之扯訓讀取該檔案重新構建資料,換言之,redis重啟的話就根據日志檔案的內容將寫指令從前到后執行一次以完成資料的恢復作業,
三種策略
always:每條命令都刷盤
everysec:每一秒刷一次
no:作業系統決定
什么是AOF
快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那么服務器將丟失最近寫入、以及未保存到快照中的那些資料, 從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化,
如果要使用AOF,需要修改組態檔:

appendonly no yes則表示啟用AOF
默認是不開啟的,我們需要手動配置,然后重啟redis,就可以生效了!
如果這個aof檔案有錯位,這時候redis是啟動不起來的,我需要修改這個aof檔案
redis給我們提供了一個工具redis-check-aof --fix
優點和缺點
123456appendonly yes # 默認是不開啟aof模式的,默認是使用rdb方式持久化的,在大部分的情況下,rdb完全夠用
appendfilename "appendonly.aof"
# appendfsync always # 每次修改都會sync 消耗性能
appendfsync everysec # 每秒執行一次 sync 可能會丟失這一秒的資料
# appendfsync no # 不執行 sync ,這時候作業系統自己同步資料,速度最快
優點
- 每一次修改都會同步,檔案的完整性會更加好
- 每秒同步一次,可能會丟失一秒的資料
- 從不同步,效率最高
缺點
- 相對于資料檔案來說,aof遠遠大于rdb,修復速度比rdb慢!
- Aof運行效率也要比rdb慢,所以我們redis默認的配置就是rdb持久化
AOF重寫
fork出子行程,一個進行重寫,一個把重寫程序中產生的aof記錄寫到buffer中,最后添加到AOF新檔案中,
RDB和AOP選擇
RDB優勢與劣勢
優勢
- 適合大規模的資料恢復
- 對資料完整性和一致性要求不高
劣勢
-
在一定間隔時間做一次備份,所以如果redis意外down掉的話,就會丟失最后一次快照后的所有修改,
-
Fork的時候,記憶體中的資料被
克隆了一份,大致2倍的膨脹性能需要考慮
AOF優勢/劣勢
優勢
- 每次修改同步:appendfsync always同步持久化,每次發生資料變更會被立即記錄到磁盤,性能較差但資料完整性比較好
- 每秒同步:appendfsync everysec異步操作,每秒記錄,如果一秒內宕機,僅一秒內的資料丟失
劣勢
- 相同資料集的資料而言aof檔案要遠大于rdb檔案,恢復速度慢于rdb
- Aof運行效率要慢于rdb,每秒同步策略效率較好,不同步效率和rdb相同
RDB消耗性能大,如果宕機可能丟失最后一次所做的修改,但是檔案小,恢復快
為什么RDB恢復資料集較快
AOF,存放的指令日志,做資料恢復的時候,其實是要回放和執行所有的指令日志,來恢復出來記憶體中的所有資料的;
RDB,就是一份資料檔案,恢復的時候,直接加載到記憶體中即可

如何選擇使用哪種持久化方式?
一般來說, 如果想達到足以媲美 PostgreSQL 的資料安全性, 你應該同時使用兩種持久化功能,
如果你非常關心你的資料, 但仍然可以承受數分鐘以內的資料丟失, 那么你可以只使用 RDB 持久化,
有很多用戶都只使用 AOF 持久化, 但并不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便于進行資料庫備份, 并且 RDB 恢復資料集的速度也要比 AOF 恢復的速度要快,
常見問題
fork
記憶體越大,fork時間越長,所以設定引數maxmemory引數
降低fork頻率,避免不必要的全量復制

AOF追加阻塞

距離上次同步超過兩秒,就阻塞主執行緒,直到同步完成
參考硬碟優化的相關策略

Redis發布訂閱
訂閱
subscribe hongdou
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "hongdou"
3) (integer) 1
發布
127.0.0.1:6379> publish hongdou hahaha (integer) 1結果:
1) "message" 2) "hongdou" 3) "hahaha"
原理
每個 Redis 服務器行程都維持著一個表示服務器狀態的 redis.h/redisServer 結構, 結構的 pubsub_channels 屬性是一個字典, 這個字典就用于保存訂閱頻道的資訊,其中,字典的鍵為正在被訂閱的頻道, 而字典的值則是一個鏈表, 鏈表中保存了所有訂閱這個頻道的客戶端,

客戶端訂閱,就被鏈接到對應頻道的鏈表的尾部,退訂則就是將客戶端節點從鏈表中移除,
缺點
- 如果一個客戶端訂閱了頻道,但自己讀取訊息的速度卻不夠快的話,那么不斷積壓的訊息會使redis輸出緩沖區的體積變得越來越大,這可能使得redis本身的速度變慢,甚至直接崩潰,
- 這和資料傳輸可靠性有關,如果在訂閱方斷線,那么他將會丟失所有在短線期間發布者發布的訊息,
應用
- 訊息訂閱:公眾號訂閱,微博關注等等(起始更多是使用訊息佇列來進行實作)
- 多人在線聊天室,
稍微復雜的場景,我們就會使用訊息中間件MQ處理,
Redis主從復制
概念
主從復制,是指將一臺Redis服務器的資料,復制到其他的Redis服務器,前者稱為主節點(Master/Leader),后者稱為從節點(Slave/Follower), 資料的復制是單向的!只能由主節點復制到從節點(主節點以寫為主、從節點以讀為主),
默認情況下,每臺Redis服務器都是主節點,一個主節點可以有0個或者多個從節點,但每個從節點只能由一個主節點,
作用
- 資料冗余:主從復制實作了資料的熱備份,是持久化之外的一種資料冗余的方式,
- 故障恢復:當主節點故障時,從節點可以暫時替代主節點提供服務,是一種服務冗余的方式
- 負載均衡:在主從復制的基礎上,配合讀寫分離,由主節點進行寫操作,從節點進行讀操作,分擔服務器的負載;尤其是在多讀少寫的場景下,通過多個從節點分擔負載,提高并發量,
- 高可用基石:主從復制還是哨兵和集群能夠實施的基礎,
為什么使用集群
- 單臺服務器難以負載大量的請求
- 單臺服務器故障率高,系統崩壞概率大
- 單臺服務器記憶體容量有限,
環境配置
我們在講解組態檔的時候,注意到有一個replication模塊 (見Redis.conf中第8條)
查看當前庫的資訊:info replication
123456789101112127.0.0.1:6379> info replication
# Replication
role:master # 角色
connected_slaves:0 # 從機數量
master_replid:3b54deef5b7b7b7f7dd8acefa23be48879b4fcff
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檔案名
-
日志檔案名
-
rdb檔案名
注意:window配置方法:
開啟多個埠服務器
1.組態檔
將redis.windows-service.conf復制一份,改名為相應檔案,并更改組態檔中的埠為指定埠,以6380為例
port 6380
2.安裝服務
redis-server –service-install –service-name redis_6380 redis.windows-service-6380.conf
3.啟動服務
redis-server –service-start –service-name redis_6380
4.停止服務
redis-server –service-stop –service-name redis_6380
5.卸載服務
redis-server –service-uninstall –service-name redis_6380
指定埠啟動客戶端:
redis.cli -p 埠號

啟動單機多服務集群:

一主二從配置
默認情況下,每臺Redis服務器都是主節點;一般情況下只用配置從機就好了!
認老大!一主(79)二從(80,81)
使用SLAVEOF host port就可以為從機配置主機了,


主機截圖:

使用命令搭建是暫時的,真實開發中應該在從機的組態檔中進行配置,這樣的話是永久的,

規則
從機只能讀,不能寫,主機可讀可寫但是多用于寫,
當主機斷電宕機后,默認情況下從機的角色不會發生變化 ,集群中只是失去了寫操作,當主機恢復以后,又會連接上從機恢復原狀,
當從機斷電宕機后,若不是使用組態檔配置的從機,再次啟動后作為主機是無法獲取之前主機的資料的,若此時重新配置稱為從機,又可以獲取到主機的所有資料,這里就要提到一個同步原理
復制原理
從機成功連接到主機后會發送一個同步命令
主機啟動bgsave,開始生成RDB檔案,同時把期間的寫命令快取在記憶體中,RDB檔案生成后發送給slave,slave會先寫入磁盤,再從磁盤加載到記憶體,接著master將快取中的寫命令發送到slave,slave再進行同步

全量復制:主機生成RDB——-》同時快取寫命令———–》發送給從機,從機清空舊資料加載rdb到記憶體中———》同時基于舊資料版本提供服務
增量復制:每次更新資料同步到從機
過期key處理:主機刪掉,模擬一條del指令發給slave
層層鏈路
主機從機成鏈路式連接
如果主機斷開了連接,我們可以使用SLAVEOF no one讓自己變成主機!其他的節點就可以手動連接到最新的主節點
哨兵模式的全部配置
完整的哨兵模式組態檔 sentinel.conf
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970# Example sentinel.conf
# 哨兵sentinel實體運行的埠 默認26379
port 26379
# 哨兵sentinel的作業目錄
dir /tmp
# 哨兵sentinel監控的redis主節點的 ip port
# master-name 可以自己命名的主節點名字 只能由字母A-z、數字0-9 、這三個字符".-_"組成,
# quorum 當這些quorum個數sentinel哨兵認為master主節點失聯 那么這時 客觀上認為主節點失聯了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 1
# 當在Redis實體中開啟了requirepass foobared 授權密碼 這樣所有連接Redis實體的客戶端都要提供密碼
# 設定哨兵sentinel 連接主從的密碼 注意必須為主從設定一樣的驗證密碼
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 指定多少毫秒之后 主節點沒有應答哨兵sentinel 此時 哨兵主觀上認為主節點下線 默認30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
# 這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,
這個數字越小,完成failover所需的時間就越長,
但是如果這個數字越大,就意味著越 多的slave因為replication而不可用,
可以通過將這個值設為 1 來保證每次只有一個slave 處于不能處理命令請求的狀態,
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
# 故障轉移的超時時間 failover-timeout 可以用在以下這些方面:
#1. 同一個sentinel對同一個master兩次failover之間的間隔時間,
#2. 當一個slave從一個錯誤的master那里同步資料開始計算時間,直到slave被糾正為向正確的master那里同步資料時,
#3.當想要取消一個正在進行的failover所需要的時間,
#4.當進行failover時,配置所有slaves指向新的master所需的最大時間,不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了
# 默認三分鐘
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
#配置當某一事件發生時所需要執行的腳本,可以通過腳本來通知管理員,例如當系統運行不正常時發郵件通知相關人員,
#對于腳本的運行結果有以下規則:
#若腳本執行后回傳1,那么該腳本稍后將會被再次執行,重復次數目前默認為10
#若腳本執行后回傳2,或者比2更高的一個回傳值,腳本將不會重復執行,
#如果腳本在執行程序中由于收到系統中斷信號被終止了,則同回傳值為1時的行為相同,
#一個腳本的最大執行時間為60s,如果超過這個時間,腳本將會被一個SIGKILL信號終止,之后重新執行,
#通知型腳本:當sentinel有任何警告級別的事件發生時(比如說redis實體的主觀失效和客觀失效等等),將會去呼叫這個腳本,
#這時這個腳本應該通過郵件,SMS等方式去通知系統管理員關于系統不正常運行的資訊,呼叫該腳本時,將傳給腳本兩個引數,
#一個是事件的型別,
#一個是事件的描述,
#如果sentinel.conf組態檔中配置了這個腳本路徑,那么必須保證這個腳本存在于這個路徑,并且是可執行的,否則sentinel無法正常啟動成功,
#通知腳本
# sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh
# 客戶端重新配置主節點引數腳本
# 當一個master由于failover而發生改變時,這個腳本將會被呼叫,通知相關的客戶端關于master地址已經發生改變的資訊,
# 以下引數將會在呼叫腳本時傳給腳本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>總是“failover”,
# <role>是“leader”或者“observer”中的一個,
# 引數 from-ip, from-port, to-ip, to-port是用來和舊的master和新的master(即舊的slave)通信的
# 這個腳本應該是通用的,能被多次呼叫,不是針對性的,
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
快取穿透與雪崩
快取穿透(查不到)
概念
在默認情況下,用戶請求資料時,會先在快取(Redis)中查找,若沒找到即快取未命中,再在資料庫中進行查找,數量少可能問題不大,可是一旦大量的請求資料(例如秒殺場景)快取都沒有命中的話,就會全部轉移到資料庫上,造成資料庫極大的壓力,就有可能導致資料庫崩潰,網路安全中也有人惡意使用這種手段進行攻擊被稱為洪水攻擊,
解決方案
布隆過濾器
對所有可能查詢的引數以Hash的形式存盤,以便快速確定是否存在這個值,在控制層先進行攔截校驗,校驗不通過直接打回,減輕了存盤系統的壓力,

快取空物件
一次請求若在快取和資料庫中都沒找到,就在快取中方一個空物件用于處理后續這個請求,

這樣做有一個缺陷:存盤空物件也需要空間,大量的空物件會耗費一定的空間,存盤效率并不高,解決這個缺陷的方式就是設定較短過期時間
即使對空值設定了過期時間,還是會存在快取層和存盤層的資料會有一段時間視窗的不一致,這對于需要保持一致性的業務會有影響,
快取擊穿(量太大,快取過期)
概念
相較于快取穿透,快取擊穿的目的性更強,一個存在的key,在快取過期的一刻,同時有大量的請求,這些請求都會擊穿到DB,造成瞬時DB請求量大、壓力驟增,這就是快取被擊穿,只是針對其中某個key的快取不可用而導致擊穿,但是其他的key依然可以使用快取回應,
比如熱搜排行上,一個熱點新聞被同時大量訪問就可能導致快取擊穿,
解決方案
-
設定熱點資料永不過期
這樣就不會出現熱點資料過期的情況,但是當Redis記憶體空間滿的時候也會清理部分資料,而且此種方案會占用空間,一旦熱點資料多了起來,就會占用部分空間,
-
加互斥鎖(分布式鎖)
在訪問key之前,采用SETNX(set if not exists)來設定另一個短期key來鎖住當前key的訪問,訪問結束再洗掉該短期key,保證同時刻只有一個執行緒訪問,這樣對鎖的要求就十分高,
快取雪崩
概念
大量的key設定了相同的過期時間,導致在快取在同一時刻全部失效,造成瞬時DB請求量大、壓力驟增,引起雪崩,

解決方案
-
redis高可用
這個思想的含義是,既然redis有可能掛掉,那我多增設幾臺redis,這樣一臺掛掉之后其他的還可以繼續作業,其實就是搭建的集群
-
限流降級
這個解決方案的思想是,在快取失效后,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量,比如對某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待,
-
資料預熱
資料加熱的含義就是在正式部署之前,我先把可能的資料先預先訪問一遍,這樣部分可能大量訪問的資料就會加載到快取中,在即將發生大并發訪問前手動觸發加載快取不同的key,設定不同的過期時間,讓快取失效的時間點盡量均勻,
-

快取一致性
先更新資料庫,在更新快取,先更新快取,再更新資料庫都會有問題
一般使用先更新資料庫再洗掉快取可以解決,因為快取的寫入要快于資料庫的寫入,但是會影響快取的命中率,
那么快取洗掉失敗怎么辦?
-
先洗掉快取,再更新資料庫
-
此時就引入了延時雙刪:
洗掉快取 更新資料庫 睡眠 需要大于第二個執行緒讀取資料并寫入快取的時間 洗掉快取睡眠時間難以估算,所以還是先更新資料庫再洗掉快取比較好
那么為什么不是更新快取而是洗掉快取呢,就是一個 lazy 計算的思想,不要每次都重新做復雜的計算,不管它會不會用到,而是讓它到需要被使用的時候再重新計算
Redis 過期策略
定期洗掉+惰性洗掉
如果還有大量的過期資料既沒有被用到過,又沒有被定期洗掉掃描到那怎么辦,就引入淘汰策略
淘汰策略
- noeviction: 當記憶體不足以容納新寫入資料時,新寫入操作會報錯,這個一般沒人用吧,實在是太惡心了,
- allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的 key(這個是最常用的),
- allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,隨機移除某個 key,這個一般沒人用吧,為啥要隨機,肯定是把最近最少使用的 key 給干掉啊,
- volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的 key(這個一般不太合適),
- volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,隨機移除某個 key,
- volatile-ttl:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,有更早過期時間的 key 優先移除,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/499683.html
標籤:其他
上一篇:mysql語法使用詳細代碼版

