1. 程式人生 > 資料庫 >由淺入深瞭解Redis

由淺入深瞭解Redis

Redis


1.1概述

redis是什麼?

官網概述

Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,它可以用作資料庫快取訊息中介軟體。 它支援多種型別的資料結構,如 字串(strings),雜湊(hashes),列表(lists), 集合(sets), 有序集合(sorted sets)與範圍查詢(bitmaps), 地理空間(hyperloglogs) 和 索引半徑查詢 (geospatial) 。Redis 內建了複製(replication), LUA指令碼(Lua scripting), LRU驅動事件(LRU eviction), 事務(transactions) 和 不同級別的磁碟持久化(persistence), 並通過 Redis哨兵(Sentinel) 和 自動分割槽(Cluster)提供高可用性(high availability)。

redis特性及功能

Redis (Remote Dictionary Server) 遠端字典服務

開源、免費、非關係型資料庫、K-V資料庫、記憶體資料庫,支援持久化、事務、訂閱和備份(aof 和 rdb )、叢集(支援16個庫)等高可用功能。並且效能極高(可以達到100000+的QPS[每秒內查詢次數]),易擴充套件,豐富的資料型別,所有操作都是單執行緒,原子性的

使用場景

  1. 熱點資料的快取
  2. 限時業務的運用 eg:秒殺、驗證碼
  3. 計數器相關問題 eg:瀏覽數目
  4. 排行榜相關問題 eg:微博熱搜
  5. 分散式鎖 #有待了解
  6. 延時操作 eg:釋出訂閱功能
  7. 分頁、模糊搜尋
  8. 點贊、好友等相互關係的儲存
  9. 佇列

Redis 為什麼單執行緒還這麼快?

誤區

  • 高效能的伺服器一定是多執行緒的?
  • 多執行緒一定比單執行緒效率高?

讀寫速度:CPU>記憶體>硬碟

核心:redis是將所有的資料全部放在記憶體中的,所以說使用單執行緒去操作效率就是最高的,多執行緒(CPU上下文切換:耗時的操作!!!),對記憶體系統來說,如果沒有上下文切換,效率就是最高的。多次讀寫都是在一個CPU上面,在記憶體的情況下,這個是最佳方案!!!

:CPU上下文切換是指CPU從一個程序或執行緒切換到另一個程序或執行緒。

redis安裝

通過docker容器安裝

systemctl start docker.service #啟動docker
docker pull redis  # 下載redis
mkdir /usr/local/docker #在容器外建立放置配置檔案等資訊資料夾
#從官網下載redis.conf檔案到此目錄下 http://download.redis.io/redis-stable/redis.conf
docker run -p 6379:6379 --name redis --privileged=true -v /usr/local/docker/redis.conf:/etc/redis/redis.conf -v /usr/local/docker/data:/data -d docker.io/redis redis-server /etc/redis/redis.conf
# -p 6379:6379 埠對映 主機:docker容器
# --name redis 指定該容器名稱
# -v 掛載目錄 規則  主機目錄:docker容器目錄
# conf 容器啟動時會把主機的redis.conf檔案自動對映到該目錄下,這樣修改redis.conf檔案時候,就不用進入容器內部修改了。
# data 持久化檔案的對映
# -d docker.io/redis 表示後臺啟動redis
# redis-server /etc/redis/redis.conf 以配置檔案形式啟動redis,載入容器內的conf檔案,最終找到掛載目錄 /usr/local/docker/redis.conf 
docker ps #檢視執行容器
docker logs [name、id] # 檢視容器日誌
docker exec -it [name、id] bash
docker exec -it [name、id] /bin/bash
#在執行的容器中執行命令
redis-cli #通過內建客戶端進行連線
exit #退出命令
############################################################
[root@localhost docker]# docker exec -it redis bash
root@5350a5da9f5b:/data# cd /etc/redis/
root@5350a5da9f5b:/etc/redis# ls
redis.conf
root@5350a5da9f5b:/etc/redis# vim redis.conf
bash: vim: command not found                   # 容器內部沒有vim命令
root@5350a5da9f5b:/etc/redis# cd .. 
root@5350a5da9f5b:/etc# cd /data
root@5350a5da9f5b:/data# redis-cli
127.0.0.1:6379> 

1.2資料型別

五種常用資料型別:string、hash、list、set、zset(sorted set)

三種特殊資料型別:geospatial、hyperloglog、bitmaps

公用命令

# 不區分大小寫
set key value  :會覆蓋相同的key的value值
keys * :查詢所有的key
get key:得到key指定的value
del key:移除key
dump key: 序列化給定key,返回被序列化的值
exists key: 檢查key是否存在
expire key seconds:為key設定過期時間
ttl key :返回key剩餘時間 -1表示永不過期,-2表示已過期
persist key:移除key的過期時間,key將永不過期
keys pattern: 查詢所有符號給定模式的key eg: keys *
randomkey:隨機返回一個key
rename key newkey:修改key的名稱
move key db:移動key到指定資料庫中
type key:返回key所儲存的值的型別
flushdb :清除當前庫內容
flushall :清除所有庫內容 

keys pattern 例項演示

127.0.0.1:6379[1]> set zzf1 v1
OK
127.0.0.1:6379[1]> set zzf2 v2
OK
127.0.0.1:6379[1]> set zzf3 v3
OK
127.0.0.1:6379[1]> keys zz* # pattern
1) "zzf2"
2) "zzf1"
3) "zzf3"

expire key second的使用場景

  • 限時的優惠活動
  • 網站資料快取
  • 手機驗證碼
  • 限制網站訪問頻率

key的命名建議

  1. key不要太長,儘量不要超過1024位元組。不僅消耗記憶體,也會降低查詢的效率
  2. key不要太短,太短可讀性會降低
  3. 在一個專案中,key最好使用統一的命名模式。例如user:123:password
  4. key區分大小寫

string

string型別是二進位制安全的,redis的string可以包含任何資料,如影象、序列化物件。一個鍵最多能儲存512MB。二進位制安全是指,在傳輸資料的時候,能保證二進位制資料的資訊保安,也就是不會被篡改、破譯;如果被攻擊,能夠及時檢測出來

常用命令

set key value # 設定值。命令不區分大小寫,但是key區分大小寫。
get key # 獲取值。
keys * # 獲取所有的key值。
exists key # 判斷key是否存在。
append key value # 字串拼接,追加至末尾,如果不存在,就為它設定。相當於 set key value。
strlen key # 獲取key所儲存的字串的長度。
incr key # 將key中儲存的數字值增一,如果key不存在,那麼先給key的值初始化為0,再執行incr自增操作。
incrby key increment # 將key中所儲存的值加上增量increment,如果key不存在同上。 
decr key # 將key中儲存的數字值減一。如果不存在,那麼先給key的值初始化為0,再執行decr自減操作。
decrby key decrement # 將key中所儲存的值減去減量decrement,如果不存在同上。
getrange key start end # 獲取key中字串的子字串,從start開始,end結束。 -1代表最後一個字元,-2 代表倒數第二個 有點python的感覺!!!
setrange key offset value # 用value引數覆寫給定key所對應的字串,從偏移量offset開始。不存在的key當空白字串處理;當字串長度小於offset時,原字串與偏移量之間將用零位元組(“\x00”)填充。
setex key seconds value #將值value關聯到key,並將key的生存時間設為seconds秒。如果key存在,將覆寫舊值。setex 是一個原子性操作,關聯值和設定生存時間兩個動作會在同一時間內完成。
setnx key value #將key的值設定為value,當且僅當key不存在。 set if not exist (在分散式鎖中會常常用到)。
mset key value [key value ...] # 同時設定一個或多個key-value對。如果key存在,則覆寫舊值。具有原子性。
mget key [key ...] #獲取所有(一個或多個)給定key的值。其中有key不存在,返回nil。

getset key value # 將給定key設定為value,並返回key的舊值;如果key不存在,返回nil,並給key設定值。
##################################
getset 和 incr 組合使用 實現計數器

string應用場景

  • string通常用於儲存單個字串或JSON字串資料。
  • 保密要求高的圖片檔案內容作為字串來儲存。
  • 計數器 如粉絲數 點贊數 。incr 本身就具有原子性,不會有執行緒安全問題。

hash

redis hash是一個string型別的field和value的對映表,hash特別適合用於儲存物件。每個hash可以儲存2^32-1(鍵值對)。可以看成key和value的map容器。相比於JSON,hash佔用很少的記憶體空間。

常用命令

hset key field value #為指定的key設定field和value
hmset key field value [field value ...] # 同時設定多個
hsetnx key field value # 當且僅當域field不存在 設定值為value;若存在,則操作無效。
hget key field #返回雜湊表 key 中給定域 field 的值。
hmget key field [field ...] # 同上
hgetall key #獲取hash表 key中欄位和值。
hkeys key # 獲取hash表 key中所有欄位。
hvals key #獲取hash表 key中所有值。
hlen key # 獲取hash表 key中欄位數目。
hdel key field [field ...] #刪除一個或多個hash表 key中的欄位。
hexists key field # 判斷hash表 key中欄位是否存在。
hincrby key field increment #hash表key中欄位field 自增 increment。若 field 不存在,那麼在執行命令前,域的值被初始化為 0 。

hash應用場景

  • 通常用於儲存使用者的物件資料。
  • hash更適合於物件的儲存,string更適合字串的儲存。

list

redis list類似於Java中的LinkedList雙向佇列的形式。是一個字串連結串列;操作頭尾效率高,中間效率低。特點 如果key不存在,則建立新的列表;如果值全移除,對應的列表也就消失。

常用命令

lpush list1 value #從左邊新增值
rpush list1 value #從後邊新增值
lpushx list1 value # list不存在,則不操作
rpushx list1 value #同上
lrange list1 start stop # 獲取 list1 [start,end]區間元素 
lrange list1 0 -1 #獲取list1中值
lpop list1   #從左邊移除值
rpop list1   #從右邊移除值
lindex list1 index #通過下標獲取list中的某一個值
llen list1 #獲取list1的長度
lrem list1 count value #移除指定個數的value
ltrim list1 index1 index2 #通過下標擷取長度,這個list已經改變了,截斷了只剩下擷取的元素
rpoplpush list1 otherlist# 移除list列表的最後一個元素,移動到新的列表otherlist中。
lset list1 index value # 更新列表對應下標的值,如果列表或下標不存在,則報錯。
linsert list1 before|after pivot value # 將value值插入列表key,位於pivot值之前或之後。如果key或pivot不存在,則不執行;若key不是列表型別,則報錯。
blpop key [key ...] timeout # 返回並移除列表第一個元素,如果沒有元素,則會阻塞列表,等待超時或發現可彈出元素為止。
brpop key [key ...] timeout #返回並移除列表最後一個元素,如果沒有元素,則會阻塞列表,等待超時或發現可彈出元素為止。

list應用場景

  • 對資料大的集合資料刪減 eg:列表顯式、關注列表、粉絲列表、留言評價、熱點新聞等。
  • 訊息佇列

補充:

​ rpoplpush list1 otherlist# 移除list列表的最後一個元素,移動到新的列表otherlist中。

可以用此命令實現訂單下單流程

set

redis set 類似Java中的set無序、不可重複

常用命令

sadd key value # 向集合中新增元素
scard key # 返回指定set中元素個數
smembers key # 返回指定set中所有元素
sismember key member # 判斷member是否在指定set中
srandmember key [count] #隨機返回指定set中一個或多個元素
spop key #隨機移除並返回指定set中的一個元素
srem key member [member ...] #移除指定set中一個和多個元素
smove source destination member # 將member元素從source集合移動到destination集合
sdiff key [key ...] # 返回第一個set集合與其他集合的差集
sinter key [key ...] # 返回所有集合的交集
sunion key [key ...] #返回所有集合的並集

set應用場景

  • 共同關注、共同愛好、二度好友等
  • 唯一性,可以統計訪問網站的所有獨立的IP

zset

redis zset(sorted set) 有序且不可重複。每一個元素都會關聯一個double型別的分數,通過分數進行從小到大的排序,分數可以重複

常用命令

zadd key score member [[score member] ...] #新增一個或多個值 ;如果member已經存在,那麼就更新這個member的score值
zcard key # 獲取集合元素個數
zcount key min max #獲取集合在指定區間分數的元素個數 
zrange key start stop # 獲取指定區間的元素,元素位置通過score從小到大排序
zrevrange key start stop # 元素位置通過score從大到小排序
zrangebyscore key min max #獲取指定score區間的元素
zrank key member #獲取元素排名(索引)
zscore key memeber #獲取元素的分數值
zrem key member [member] #移除集合中指定元素
zremrangebyscore key min max #移除給定score區間中元素
zremrangebyrank key start stop # 移除有序集 key中,指定排名(rank)區間內的所有成員

zset應用場景

  • 儲存成績、工資
  • 帶權重進行判斷
  • 排行榜

geospatial

geospatial 地理位置。可以推算地理位置資訊,兩地之間的距離,方圓周邊人數等資訊。

常用命令

###
有效的經度從-180度到180度。
有效的緯度從-85.05112878度到85.05112878度。
###
geoadd key 緯度 經度 member [緯度 經度 名稱] # 新增一個或多個地理位置資訊。
geopos key member [member] # 返回所有給定位置元素的位置(經度和緯度)。
geodist key member1 member2 [unit (m、km、mi、ft)] # 返回兩個給定位置之間的距離。
georadius key 緯度 經度 radius unit [withcoord、withdist、withhash] count # 以給定的經緯度為中心,返回鍵包含的位置元素當中,與中心的距離不超過給定最大距離的所有(選取前count個)位置元素。
withcoord: 將位置元素的經度和維度也一併返回。
withdist: 在返回位置元素的同時, 將位置元素與中心之間的距離也一併返回。 距離的單位和使用者給定的範圍單位保持一致。
withhash: 以 52 位有符號整數的形式, 返回位置元素經過原始 geohash 編碼的有序集合分值。 這個選項主要用於底層應用或者除錯, 實際中的作用並不大。
georadiusbymember key member radius unit [withcoord、withdist、withhash] count # 可以找出位於指定範圍內的元素,心點是由給定的member位置元素決定的
geohash key member [member ...] # 返回一個或多個位置元素的 11個字元Geohash字串 二維經緯度轉換成一維字串

注意:由於使用的距離公式是Haversine公式,因此僅假設地球是一個球體。當應用於地球時,該公式只是一個近似值,它不是一個完美的球體。當在需要按半徑和大多數其他應用程式查詢的社交網站的上下文中使用時,引入的錯誤不是問題。但是,在最壞的情況下,錯誤可能高達0.5%,因此您可能需要考慮將其他系統用於關鍵錯誤的應用程式。

geo的底層使用了zset實現,可以使用zset命令操作

hyperloglog

hyperloglog 基數統計的演算法(高階資料結構 )

常用命令

pfadd key element [element ...] #新增元素
pfcount key  #統計元素數目
pfmerge destkey sourcekey [sourcekey...] # 多個合併到一個新的集合中

hyperloglog 優點:佔用的記憶體是固定的,只需要12kb記憶體

缺點:有 0.81% 標準錯誤(standard error)的近似值.

使用 :統計一個網站訪問的使用者數目 (允許容錯)

bitmaps

bitmaps 點陣圖 資料結構,都是操作二進位制來記錄,就只有0和1兩個狀態

常用命令

setbit key offset value #給點陣圖指定索引設定值,返回該索引位置的原始值  
getbit key offset # 獲取點陣圖指定索引的值
bitcount key [start end] #獲取點陣圖指定範圍(start到end,單位為位元組,如果不指定就是獲取全部)位值為1的個數。

bitmaps應用場景

  • 統計使用者狀態人數 eg:活躍 、不活躍,登入、未登入
  • 打卡狀態 、統計打卡天數

1.3解析配置檔案

################################## network ##############################################
#是否在後臺執行;no:不是後臺執行 
daemonize yes 

#指定 redis 只接收來自於該 IP 地址的請求,如果不進行設定,那麼將處理所有請求 
bind 127.0.0.1 

#是否開啟保護模式,預設開啟。要是配置裡沒有指定bind和密碼。開啟該引數後,redis只會本地進行訪問,拒絕外部訪
#問。 
protected-mode yes 

#redis的程序檔案 
pidfile /var/run/redis/redis-server.pid 

#redis監聽的埠號。 
port 6379 

#此引數確定了TCP連線中已完成佇列(完成三次握手之後)的長度, 當然此值必須不大於Linux系統定義
#的/proc/sys/net/core/somaxconn值,預設是511,而Linux的預設引數值是128。當系統併發量大並且客戶端速度
#緩慢的時候,可以將這二個引數一起參考設定。該核心引數預設值一般是128,對於負載很大的服務程式來說大大的不
#夠。一般會將它修改為2048或者更大。在/etc/sysctl.conf中新增:net.core.somaxconn = 2048,然後在終端中
#執sysctl -p。 
tcp-backlog 511 

# 此引數為設定客戶端空閒超過timeout,服務端會斷開連線,為0則服務端不會主動斷開連線,不能小於0。
timeout 0 

#tcp keepalive引數。如果設定不為0,就使用配置tcp的SO_KEEPALIVE值,使用keepalive有兩個好處:檢測掛掉的
#對端。降低中間裝置出問題而導致網路看似連線卻已經與對端埠的問題。在Linux核心中,設定了keepalive,redis
#會定時給對端傳送ack。檢測到對端關閉需要兩倍的設定值。 
tcp-keepalive 0 

#指定了服務端日誌的級別。級別包括:
#debug(很多資訊,方便開發、測試)
#verbose(許多有用的資訊,但是沒有debug級別資訊多)
#notice(適當的日誌級別,適合生產環境)
#warn(只有非常重要的資訊) 
loglevel notice 

#指定了記錄日誌的檔案。空字串的話,日誌會列印到標準輸出裝置。後臺執行的redis標準輸出是/dev/null。 
logfile /var/log/redis/redis-server.log 

#是否開啟記錄syslog功能 
# syslog-enabled no 

#syslog的識別符號。 
# syslog-ident redis 

#日誌的來源、裝置 
# syslog-facility local0 

#資料庫的數量,預設使用的資料庫是DB 0。可以通過SELECT命令選擇一個db 
databases 16 


############################# snapshotting(快照) #########################################
# redis是基於記憶體的資料庫,可以通過設定該值定期寫入磁碟。 
# 註釋掉“save”這一行配置項就可以讓儲存資料庫功能失效 
# 900秒(15分鐘)內至少1個key值改變(則進行資料庫儲存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行資料庫儲存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行資料庫儲存--持久化)
# 可以通過save命令立即儲存資料
save 900 1 
save 300 10 
save 60 10000 

#當RDB持久化出現錯誤後,是否依然進行繼續進行工作,yes:不能進行工作,no:可以繼續進行工作,可以通過info中
#的rdb_last_bgsave_status瞭解RDB持久化是否有錯誤 
stop-writes-on-bgsave-error yes 

#使用壓縮rdb檔案,rdb檔案壓縮使用LZF壓縮演算法,yes:壓縮,但是需要一些cpu的消耗。no:不壓縮,需要更多的磁
#盤空間 
rdbcompression yes

#是否校驗rdb檔案。從rdb格式的第五個版本開始,在rdb檔案的末尾會帶上CRC64的校驗和。這更有利於檔案的容錯性,
#但是在儲存rdb檔案的時候,會有大概10%的效能損耗,所以如果你追求高效能,可以關閉該配置。 
rdbchecksum yes 

#rdb檔案的名稱 
dbfilename dump.rdb 

#資料目錄,資料庫的寫入會在這個目錄。rdb、aof檔案也會寫在這個目錄 
dir /var/data/redis



################################### 主從複製 #############################################
#複製選項,slave複製對應的master。
# replicaof <masterip> <masterport>

#如果master設定了requirepass,那麼slave要連上master,需要有master的密碼才行。masterauth就是用來配置
#master的密碼,這樣可以在連上master後進行認證。
# masterauth <master-password>

#當從庫同主機失去連線或者複製正在進行,從機庫有兩種執行方式:1) 如果slave-serve-stale-data設定為yes(默
#認設定),從庫會繼續響應客戶端的請求。2) 如果slave-serve-stale-data設定為no,除去INFO和SLAVOF命令之
#外的任何請求都會返回一個錯誤”SYNC with master in progress”。
replica-slave-serve-stale-data yes

#作為從伺服器,預設情況下是隻讀的(yes),可以修改成NO,用於寫(不建議)。
replica-read-only yes

#是否使用socket方式複製資料。目前redis複製提供兩種方式,disk和socket。如果新的slave連上來或者重連的
#slave無法部分同步,就會執行全量同步,master會生成rdb檔案。有2種方式:disk方式是master建立一個新的程序
#把rdb檔案儲存到磁碟,再把磁碟上的rdb檔案傳遞給slave。socket是master建立一個新的程序,直接把rdb檔案以
#socket的方式發給slave。disk方式的時候,當一個rdb儲存的過程中,多個slave都能共享這個rdb檔案。socket的
#方式就的一個個slave順序複製。在磁碟速度緩慢,網速快的情況下推薦用socket方式。
repl-diskless-sync no

#diskless複製的延遲時間,防止設定為0。一旦複製開始,節點不會再接收新slave的複製請求直到下一個rdb傳輸。所
#以最好等待一段時間,等更多的slave連上來。
repl-diskless-sync-delay 5

#slave根據指定的時間間隔向伺服器傳送ping請求。時間間隔可以通過 repl_ping_slave_period 來設定,預設10
#秒。
# repl-ping-slave-period 10

#複製連線超時時間。master和slave都有超時時間的設定。master檢測到slave上次傳送的時間超過repl-timeout,
#即認為slave離線,清除該slave資訊。slave檢測到上次和master互動的時間超過repl-timeout,則認為master離
#線。需要注意的是repl-timeout需要設定一個比repl-ping-slave-period更大的值,不然會經常檢測到超時。 
# repl-timeout 60

#是否禁止複製tcp連結的tcp nodelay引數,可傳遞yes或者no。預設是no,即使用tcp nodelay。如果master設定
#了yes來禁止tcp nodelay設定,在把資料複製給slave的時候,會減少包的數量和更小的網路頻寬。但是這也可能帶來
#資料的延遲。預設我們推薦更小的延遲,但是在資料量傳輸很大的場景下,建議選擇yes
repl-disable-tcp-nodelay no
 
#複製緩衝區大小,這是一個環形複製緩衝區,用來儲存最新複製的命令。這樣在slave離線的時候,不需要完全複製
#master的資料,如果可以執行部分同步,只需要把緩衝區的部分資料複製給slave,就能恢復正常複製狀態。緩衝區的大
#小越大,slave離線的時間可以更長,複製緩衝區只有在有slave連線的時候才分配記憶體。沒有slave的一段時間,記憶體
#會被釋放出來,預設1mb
# repl-backlog-size 1mb
 
# master沒有slave一段時間會釋放複製緩衝區的記憶體,repl-backlog-ttl用來設定該時間長度。單位為秒。
# repl-backlog-ttl 3600
 
# 當master不可用,Sentinel會根據slave的優先順序選舉一個master。最低的優先順序的slave,當選master。而配置
#成0,永遠不會被選舉
replica-priority 100
 
#redis提供了可以讓master停止寫入的方式,如果配置了min-replicas-to-write,健康的slave的個數小於N,
#mater就禁止寫入。master最少得有多少個健康的slave存活才能執行寫命令。這個配置雖然不能保證N個slave都一定
#能接收到master的寫操作,但是能避免沒有足夠健康的slave的時候,master不能寫入來避免資料丟失。設定為0是關
#閉該功能
# min-replicas-to-write 3
# 延遲小於min-replicas-max-lag秒的slave才認為是健康的slave
# min-replicas-max-lag 10


################################### 安全特性 ##############################################
#requirepass配置可以讓使用者使用AUTH命令來認證密碼,才能使用其他命令。這讓redis可以使用在不受信任的網路
#中。為了保持向後的相容性,可以註釋該命令,因為大部分使用者也不需要認證。使用requirepass的時候需要注意,因為
#redis太快了,每秒可以認證15w次密碼,簡單的密碼很容易被攻破,所以最好使用一個更復雜的密碼
# requirepass foobared
#把危險的命令給修改成其他名稱。比如CONFIG命令可以重新命名為一個很難被猜到的命令,這樣使用者不能使用,而內部工具
#還能接著使用
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#設定成一個空的值,可以禁止一個命令
# rename-command CONFIG ""

################################### 客戶端 ############################################## 
# 設定能連上redis的最大客戶端連線數量。預設是10000個客戶端連線。由於redis不區分連線是客戶端連線還是內部打
#開檔案或者和slave連線等,所以maxclients最小建議設定到32。如果超過了maxclients,redis會給新的連線
#傳送’max number of clients reached’,並關閉連線
# maxclients 10000
 
################################### 記憶體管理 ############################################
#redis配置的最大記憶體容量。當記憶體滿了,需要配合maxmemory-policy策略進行處理。注意slave的輸出緩衝區是不計
#算在maxmemory內的。所以為了防止主機記憶體使用完,建議設定的maxmemory需要更小一些
# maxmemory <bytes>
 
#記憶體容量超過maxmemory後的處理策略。
#volatile-lru:利用LRU演算法移除設定過過期時間的key。
#volatile-random:隨機移除設定過過期時間的key。
#volatile-ttl:移除即將過期的key,根據最近過期時間來刪除(輔以TTL)
#allkeys-lru:利用LRU演算法移除任何key。
#allkeys-random:隨機移除任何key。
#noeviction:不移除任何key,只是返回一個寫錯誤。
#上面的這些驅逐策略,如果redis沒有合適的key驅逐,對於寫命令,還是會返回錯誤。redis將不再接收寫請求,只接
#收get請求。寫命令包括:set setnx setex append incr decr rpush lpush rpushx lpushx linsert 
#lset rpoplpush sadd sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby 
#zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby getset mset msetnx exec 
#sort。
# maxmemory-policy noeviction
 
# lru檢測的樣本數。使用lru或者ttl淘汰演算法,從需要淘汰的列表中隨機選擇sample個key,選出閒置時間最長的key移除
# maxmemory-samples 5
 
# 是否開啟salve的最大記憶體
# replica-ignore-maxmemory yes


################################### aof持久化 ###########################################
#Redis 預設不開啟。它的出現是為了彌補RDB的不足(資料的不一致性),所以它採用日誌的形式來記錄每個寫操作,並
#追加到檔案中。Redis 重啟的會根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作預設redis使用的
#是rdb方式持久化,這種方式在許多應用中已經足夠用了。但是redis如果中途宕機,會導致可能有幾分鐘的資料丟失,
#根據save來策略進行持久化,Append Only File是另一種持久化方式,可以提供更好的持久化特性。Redis會把每次
#寫入的資料在接收後都寫入 appendonly.aof 檔案,每次啟動時Redis都會先把這個檔案的資料讀入記憶體裡,先忽略
#RDB檔案。若開啟aof則將no改為yes
appendonly no
 
#指定本地資料庫檔名,預設值為 appendonly.aof
appendfilename "appendonly.aof"
 
#aof持久化策略的配置
#no表示不執行fsync,由作業系統保證資料同步到磁碟,速度最快
#always表示每次寫入都執行fsync,以保證資料同步到磁碟
#everysec表示每秒執行一次fsync,可能會導致丟失這1s資料
# appendfsync always
appendfsync everysec
# appendfsync no
 
# 在aof重寫或者寫入rdb檔案的時候,會執行大量IO,此時對於everysec和always的aof模式來說,執行fsync會造成
#阻塞過長時間,no-appendfsync-on-rewrite欄位設定為預設設定為no。如果對延遲要求很高的應用,這個欄位可以
#設定為yes,否則還是設定為no,這樣對持久化特性來說這是更安全的選擇。設定為yes表示rewrite期間對新寫操作不
#fsync,暫時存在記憶體中,等rewrite完成後再寫入,預設為no,建議yes。Linux的預設fsync策略是30秒。可能丟失
#30秒資料
no-appendfsync-on-rewrite no
 
#aof自動重寫配置。當目前aof檔案大小超過上一次重寫的aof檔案大小的百分之多少進行重寫,即當aof檔案增長到一定
#大小的時候Redis能夠呼叫bgrewriteaof對日誌檔案進行重寫。當前AOF檔案大小是上次日誌重寫得到AOF檔案大小的
#二倍(設定為100)時,自動啟動新的日誌重寫過程
auto-aof-rewrite-percentage 100
 
#設定允許重寫的最小aof檔案大小,避免了達到約定百分比但尺寸仍然很小的情況還要重寫
auto-aof-rewrite-min-size 64mb
 
#aof檔案可能在尾部是不完整的,當redis啟動的時候,aof檔案的資料被載入記憶體。重啟可能發生在redis所在的主機操
#作系統宕機後,尤其在ext4檔案系統沒有加上data=ordered選項(redis宕機或者異常終止不會造成尾部不完整現
#象。)出現這種現象,可以選擇讓redis退出,或者匯入儘可能多的資料。如果選擇的是yes,當截斷的aof檔案被匯入的
#時候,會自動釋出一個log給客戶端然後load。如果是no,使用者必須手動redis-check-aof修復AOF檔案才可以
aof-load-truncated yes
 
#載入redis時,可以識別AOF檔案以“redis”開頭。
#字串並載入帶字首的RDB檔案,然後繼續載入AOF尾巴
aof-use-rdb-preamble yes

############################### LUA SCRIPTING (lua指令碼)################################
# 如果達到最大時間限制(毫秒),redis會記個log,然後返回error。當一個指令碼超過了最大時限。只有SCRIPT 
#KILL和SHUTDOWN NOSAVE可以用。第一個可以殺沒有調write命令的東西。要是已經呼叫了write,只能用第二個命令
#殺
lua-time-limit 5000

###############################REDIS CLUSTER redis 叢集 ################################
# 叢集開關,預設是不開啟叢集模式
# cluster-enabled yes
 
#叢集配置檔案的名稱,每個節點都有一個叢集相關的配置檔案,持久化儲存叢集的資訊。這個檔案並不需要手動配置,這
#個配置檔案有Redis生成並更新,每個Redis叢集節點需要一個單獨的配置檔案,請確保與例項執行的系統中配置檔名
#稱不衝突
# cluster-config-file nodes-6379.conf
 
#節點互連超時的閥值。叢集節點超時毫秒數
# cluster-node-timeout 15000
 
#在進行故障轉移的時候,全部slave都會請求申請為master,但是有些slave可能與master斷開連線一段時間
#了,導致資料過於陳舊,這樣的slave不應該被提升為master。該引數就是用來判斷slave節點與master斷線的時
#間是否過長。判斷方法是:
#比較slave斷開連線的時間和(node-timeout * slave-validity-factor) + repl-ping-slave-period
#如果節點超時時間為三十秒, 並且slave-validity-factor為10,假設預設的repl-ping-slave-period是10
#秒,即如果超過310秒slave將不會嘗試進行故障轉移
# cluster-replica-validity-factor 10
 
# master的slave數量大於該值,slave才能遷移到其他孤立master上,如這個引數若被設為2,那麼只有當一
#個主節點擁有2 個可工作的從節點時,它的一個從節點會嘗試遷移
# cluster-migration-barrier 1
 
#預設情況下,叢集全部的slot有節點負責,叢集狀態才為ok,才能提供服務。設定為no,可以在slot沒有全
#部分配的時候提供服務。不建議開啟該配置,這樣會造成分割槽的時候,小分割槽的master一直在接受寫請求,而
#造成很長時間資料不一致
# cluster-require-full-coverage yes

###############################SLOW LOG  ################################
# slow log是用來記錄redis執行中執行比較慢的命令耗時。當命令的執行超過了指定時間,就記錄在slow log
#中,slow log儲存在記憶體中,所以沒有IO操作。
#執行時間比slowlog-log-slower-than大的請求記錄到slowlog裡面,單位是微秒,所以1000000就是1秒。注
#意,負數時間會禁用慢查詢日誌,而0則會強制記錄所有命令。
slowlog-log-slower-than 10000
 
#慢查詢日誌長度。當一個新的命令被寫進日誌的時候,最老的那個記錄會被刪掉。這個長度沒有限制。只要有足
#夠的記憶體就行。你可以通過 SLOWLOG RESET 來釋放記憶體
slowlog-max-len 128

################################ LATENCY MONITOR ##############################
#延遲監控功能是用來監控redis中執行比較緩慢的一些操作,用LATENCY列印redis例項在跑命令時的耗時圖表。
#只記錄大於等於下邊設定的值的操作。0的話,就是關閉監視。預設延遲監控功能是關閉的,如果你需要開啟,也
#可以通過CONFIG SET命令動態設定
latency-monitor-threshold 0

############################# EVENT NOTIFICATION 訂閱 ##############################
#鍵空間通知使得客戶端可以通過訂閱頻道或模式,來接收那些以某種方式改動了 Redis 資料集的事件。因為開啟鍵空間#通知功能需要消耗一些 CPU ,所以在預設配置下,該功能處於關閉狀態。
#notify-keyspace-events 的引數可以是以下字元的任意組合,它指定了伺服器該傳送哪些型別的通知:
##K 鍵空間通知,所有通知以 __keyspace@__ 為字首
##E 鍵事件通知,所有通知以 __keyevent@__ 為字首
##g DEL 、 EXPIRE 、 RENAME 等型別無關的通用命令的通知
##$ 字串命令的通知
##l 列表命令的通知
##s 集合命令的通知
##h 雜湊命令的通知
##z 有序集合命令的通知
##x 過期事件:每當有過期鍵被刪除時傳送
##e 驅逐(evict)事件:每當有鍵因為 maxmemory 政策而被刪除時傳送
##A 引數 g$lshzxe 的別名
#輸入的引數中至少要有一個 K 或者 E,否則的話,不管其餘的引數是什麼,都不會有任何 通知被分發。詳細使用可以參考http://redis.io/topics/notifications
 
notify-keyspace-events ""

############################### ADVANCED CONFIG 高階配置 ###############################
# 資料量小於等於hash-max-ziplist-entries的用ziplist,大於hash-max-ziplist-entries用hash
hash-max-ziplist-entries 512
 
# value大小小於等於hash-max-ziplist-value的用ziplist,大於hash-max-ziplist-value用hash
hash-max-ziplist-value 64
 
#-5:最大大小:64 KB<--不建議用於正常工作負載
#-4:最大大小:32 KB<--不推薦
#-3:最大大小:16 KB<--可能不推薦
#-2:最大大小:8kb<--良好
#-1:最大大小:4kb<--良好
list-max-ziplist-size -2
 
#0:禁用所有列表壓縮
#1:深度1表示“在列表中的1個節點之後才開始壓縮,
#從頭部或尾部
#所以:【head】->node->node->…->node->【tail】
#[頭部],[尾部]將始終未壓縮;內部節點將壓縮。
#2:[頭部]->[下一步]->節點->節點->…->節點->[上一步]->[尾部]
#2這裡的意思是:不要壓縮頭部或頭部->下一個或尾部->上一個或尾部,
#但是壓縮它們之間的所有節點。
#3:[頭部]->[下一步]->[下一步]->節點->節點->…->節點->[上一步]->[上一步]->[尾部]
list-compress-depth 0
 
# 資料量小於等於set-max-intset-entries用intset,大於set-max-intset-entries用set
set-max-intset-entries 512
 
#資料量小於等於zset-max-ziplist-entries用ziplist,大於zset-max-ziplist-entries用zset
zset-max-ziplist-entries 128
 
#value大小小於等於zset-max-ziplist-value用ziplist,大於zset-max-ziplist-value用zset
zset-max-ziplist-value 64
 
#value大小小於等於hll-sparse-max-bytes使用稀疏資料結構(sparse),大於hll-sparse-max-bytes使
#用稠密的資料結構(dense)。一個比16000大的value是幾乎沒用的,建議的value大概為3000。如果對CPU要
#求不高,對空間要求較高的,建議設定到10000左右
hll-sparse-max-bytes 3000
 
#巨集觀節點的最大流/專案的大小。在流資料結構是一個基數
#樹節點編碼在這項大的多。利用這個配置它是如何可能#大節點配置是單位元組和
#最大專案數,這可能包含了在切換到新節點的時候
# appending新的流條目。如果任何以下設定來設定
# ignored極限是零,例如,作業系統,它有可能只是一集
#通過設定限制最大#紀錄到最大位元組0和最大輸入到所需的值
stream-node-max-bytes 4096
stream-node-max-entries 100
 
#Redis將在每100毫秒時使用1毫秒的CPU時間來對redis的hash表進行重新hash,可以降低記憶體的使用。當你
#的使用場景中,有非常嚴格的實時性需要,不能夠接受Redis時不時的對請求有2毫秒的延遲的話,把這項配置
#為no。如果沒有這麼嚴格的實時性要求,可以設定為yes,以便能夠儘可能快的釋放記憶體
activerehashing yes
 
##對客戶端輸出緩衝進行限制可以強迫那些不從伺服器讀取資料的客戶端斷開連線,用來強制關閉傳輸緩慢的客戶端。
#對於normal client,第一個0表示取消hard limit,第二個0和第三個0表示取消soft limit,normal 
#client預設取消限制,因為如果沒有尋問,他們是不會接收資料的
client-output-buffer-limit normal 0 0 0
 
#對於slave client和MONITER client,如果client-output-buffer一旦超過256mb,又或者超過64mb持續
#60秒,那麼伺服器就會立即斷開客戶端連線
client-output-buffer-limit replica 256mb 64mb 60
 
#對於pubsub client,如果client-output-buffer一旦超過32mb,又或者超過8mb持續60秒,那麼伺服器就
#會立即斷開客戶端連線
client-output-buffer-limit pubsub 32mb 8mb 60
 
# 這是客戶端查詢的快取極限值大小
# client-query-buffer-limit 1gb
 
#在redis協議中,批量請求,即表示單個字串,通常限制為512 MB。但是您可以更改此限制。
# proto-max-bulk-len 512mb
 
#redis執行任務的頻率為1s除以hz
hz 10
 
#當啟用動態赫茲時,實際配置的赫茲將用作作為基線,但實際配置的赫茲值的倍數
#在連線更多客戶端後根據需要使用。這樣一個閒置的例項將佔用很少的CPU時間,而繁忙的例項將反應更靈敏
dynamic-hz yes
 
#在aof重寫的時候,如果打開了aof-rewrite-incremental-fsync開關,系統會每32MB執行一次fsync。這
#對於把檔案寫入磁碟是有幫助的,可以避免過大的延遲峰值
aof-rewrite-incremental-fsync yes
 
#在rdb儲存的時候,如果打開了rdb-save-incremental-fsync開關,系統會每32MB執行一次fsync。這
#對於把檔案寫入磁碟是有幫助的,可以避免過大的延遲峰值
rdb-save-incremental-fsync yes

1.4持久化

rdb

介紹

rdb (redis dataBase)在指定的時間間隔內生成記憶體中整個資料集的持久化快照。快照檔案預設被儲存在當前資料夾中,名稱為dump.rdb。可以通過dir和dbfilename引數來修改預設值。

redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到臨時檔案中。待持久化過程都結束了,再用這個臨時檔案替換上次持久化的檔案。整個過程中,主程序是不進行任何的IO操作的,這保證了極高的效能

fork的作用相當於複製一個與當前程序一樣的程序。但是是一個全新的程序,並作為原程序的子程序。

配置檔案

# redis是基於記憶體的資料庫,可以通過設定該值定期寫入磁碟。 
# 註釋掉“save”這一行配置項就可以讓儲存資料庫功能失效 
# 900秒(15分鐘)內至少1個key值改變(則進行資料庫儲存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行資料庫儲存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行資料庫儲存--持久化)
# 可以通過save命令立即儲存資料
save 900 1 
save 300 10 
save 60 10000 

#當RDB持久化出現錯誤後,是否依然進行繼續進行工作,yes:不能進行工作,no:可以繼續進行工作,可以通過info中
#的rdb_last_bgsave_status瞭解RDB持久化是否有錯誤 
stop-writes-on-bgsave-error yes 

#使用壓縮rdb檔案,rdb檔案壓縮使用LZF壓縮演算法,yes:壓縮,但是需要一些cpu的消耗。no:不壓縮,需要更多的磁
#盤空間 
rdbcompression yes

#是否校驗rdb檔案。從rdb格式的第五個版本開始,在rdb檔案的末尾會帶上CRC64的校驗和。這更有利於檔案的容錯性,
#但是在儲存rdb檔案的時候,會有大概10%的效能損耗,所以如果你追求高效能,可以關閉該配置。 
rdbchecksum yes 

#rdb檔案的名稱 
dbfilename dump.rdb  #可以自定義檔名

#資料目錄,資料庫的寫入會在這個目錄。rdb、aof檔案也會寫在這個目錄 
dir /var/data/redis  #可以自定義路徑

觸發機制

  1. 配置檔案中save的規則滿足情況下,會自動觸發rdb規則
  2. 手動通過命令來觸發
    • save : save時只管儲存,其他命令操作全部阻塞。
    • bgsave:redis會在後臺非同步進行快照操作,快照同時還可以響應客戶端請求。可以通過lastsave命令獲取最後一次執行快照的時間。
    • flushall:會產生dump.rdb檔案,但裡面是空的,無意義。
    • shutdown:安全退出,也會生成dump.rdb檔案。

恢復

恢復rdb檔案

開發中應做好備份rdb檔案,以防flushall命令清空資料。

將備份檔案(dump.rdb)移到redis安裝目錄並啟動服務即可。

恢復資料

當配置檔案中 appendonly 設定為no時,預設rdb持久化。redis啟動時,會載入dir 設定的目錄下的dump.rdb檔案來進行資料恢復。

config get dir 獲取目錄

優點

  • 適合大規模的資料恢復
  • 對資料的完整性和一致性要求不高

缺點

  • 需要一定的時間間隔程序操作!如果redis意外宕機了,會丟失最後一次快照後的所有修改資料。
  • fork程序的時候,記憶體中資料被克隆了一份,大致2倍的膨脹性需要考慮。

aof

介紹

aof (append only file)以日誌的形式來記錄每一個寫操作,將redis執行過的所有寫指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,儲存的是appendonly.aof檔案。

aof機制預設關閉,可以通過appendonly = yes 開啟aof機制。重啟生效!!!

配置檔案

aof持久化的一些策略配置

#aof持久化策略的配置 
#no表示不執行fsync,由作業系統保證資料同步到磁碟,速度最快。 
#always表示每次寫入都執行fsync,以保證資料同步到磁碟。 
#everysec表示每秒執行一次fsync,可能會導致丟失這1s資料。 
appendfsync everysec

對於觸發aof重寫機制也可以通過配置檔案來進行設定

#aof自動重寫配置。當目前aof檔案大小超過上一次重寫的aof檔案大小的百分之多少進行重寫,即當aof檔案增長到一定
#大小的時候Redis能夠呼叫bgrewriteaof對日誌檔案進行重寫。當前AOF檔案大小是上次日誌重寫得到AOF檔案大小的
#二倍(設定為100)時,自動啟動新的日誌重寫過程
auto-aof-rewrite-percentage 100
 
#設定允許重寫的最小aof檔案大小,避免了達到約定百分比但尺寸仍然很小的情況還要重寫
auto-aof-rewrite-min-size 64mb

當aop重寫時會引發重寫和持久化追加同時發生的問題

# 在aof重寫或者寫入rdb檔案的時候,會執行大量IO,此時對於everysec和always的aof模式來說,執行fsync會造成
#阻塞過長時間,no-appendfsync-on-rewrite欄位設定為預設設定為no。如果對延遲要求很高的應用,這個欄位可以
#設定為yes,否則還是設定為no,這樣對持久化特性來說這是更安全的選擇。設定為yes表示rewrite期間對新寫操作不
#fsync,暫時存在記憶體中,等rewrite完成後再寫入,預設為no,建議yes。Linux的預設fsync策略是30秒。可能丟失
#30秒資料
no-appendfsync-on-rewrite no

如何恢復

正常恢復

​ 將檔案放到dir指定的資料夾下,當redis啟動的時候會自動載入資料,注意:aof檔案的優先順序比dump大

異常恢復
  • 有些操作可以直接到appendonly.aof檔案裡去修改。

    eg:使用了flushall這個命令,此刻持久化檔案中就會有這麼一條命令記錄,把它刪掉就可以了

  • 寫壞的檔案可以通過 redis-check-aof --fix進行修復

優點

  • 根據不同的策略,可以實現每秒,每一次修改操作的同步持久化,就算在最惡劣的情況下只會丟失不會超過兩秒資料。
  • 當檔案太大時,會觸發重寫機制,確保檔案不會太大。
  • 檔案可以簡單的讀懂

缺點

  • aof檔案的大小太大,就算有重寫機制,但重寫所造成的阻塞問題是不可避免的
  • aof檔案恢復速度慢

總結

  1. 如果你只希望你的資料在伺服器執行的時候存在,可以不使用任何的持久化方式

  2. 一般建議同時開啟兩種持久化方式。AOF進行資料的持久化,確保資料不會丟失太多,而RDB更適合用於備份資料集,留著一個做萬一的手段。

  3. 效能建議:

    因為RDB檔案只用做後備用途,建議只在slave上持久化RDB檔案,而且只要在15分鐘備份一次就夠了,只保留save 900 1這條規則。

    如果Enalbe AOF,好處是在最惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自己的AOF檔案就可以了。代價:1、帶來了持續的IO;2、AOF rewrite的最後將rewrite過程中產生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上。預設超過原大小100%大小時重寫可以改到適當的數值。

    如果不Enable AOF,僅靠Master-Slave Replication 實現高可用性也可以。能省掉一大筆IO也減少了rewrite時帶來的系統波動。代價是如果Master/Slave同時宕掉,會丟失10幾分鐘的資料,啟動指令碼也要比較兩個Master/Slave中的RDB檔案,載入較新的那個。新浪微博就選用了這種架構。

1.5redis事務

是什麼?

可以一次執行多個命令,本質是一組命令的集合。一個事務中所有命令都會被序列化,按順序的序列執行而不會被其他命令插入,不許加塞。

能幹什麼?

一個佇列中,一次性,順序的,排他的執行一系列命令。

常用命令

命令描述
multi標記一個事務的開始
exec執行所有事務塊內的命令
discard取消事務,放棄執行事務塊內的所有命令
watch key [key]監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。
unwatch取消watch命令對所有 key 的監視。

怎麼玩?

  1. 正常執行

    1. 放棄事務

    2. 全體連坐

    3. 冤頭債主

悲觀鎖:當要對資料庫中的一條資料進行修改的時候,為了避免同時被其他人修改,最好的辦法就是直接對該資料進行加鎖以防止併發。

樂觀鎖,樂觀鎖假設資料一般情況下不會造成衝突,所以在資料進行提交更新的時候,才會正式對資料的衝突與否進行檢測,如果發現衝突了,則返回給使用者錯誤的資訊,讓使用者決定如何去做。

watch監控

watch指令,類似樂觀鎖,如果key的值已經被修改了,那麼整個事務佇列都不會被執行,同時返回一個nli應答以通知呼叫者事務執行失敗。

注意:一旦執行了exec或者discard,之前加的所有監控鎖都會被取消掉了。

例子:

  1. 無加塞修改

    1. 有加塞修改,當watch的key被修改,後面的那個事務全部執行失敗

  2. unwatch

    1. 二處同時操作一個數據時

3階段

開啟:以multi開啟事務

入隊:將多個命令入隊到事務中,接到這些命令不會立刻執行,而是放到等待執行的事務佇列裡面

執行:有exec命令觸發事務

3特性

  1. 單獨的隔離操作:事務中的所有命令都會序列化,按順序的執行。事務在等待執行的時候,不會被其他客戶端傳送來的命令請求打斷。
  2. 沒有隔離級別的概念:佇列中的所有命令沒有提交exec之前都是不會被執行的。
  3. 不保證原子性:redis中如果一條命令執行失敗,其後的命令仍然會被執行,沒有回滾。

1.6redis釋出訂閱(一般不用)

釋出訂閱

Redis 釋出訂閱(pub/sub)是一種訊息通訊模式:傳送者(pub)傳送訊息,訂閱者(sub)接收訊息。

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

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關係:

當有新訊息通過 PUBLISH 命令傳送給頻道 channel1 時, 這個訊息就會被髮送給訂閱它的三個客戶端:

命令

subscribe channel [channel…] #訂閱一個或多個頻道的資訊
psubscribe pattern [pattern…] #訂閱一個或多個符合規定模式的頻道
publish channel message  #將資訊傳送到指定頻道
unsubscribe [channel[channel…]] #退訂頻道
punsubscribe [pattern[pattern…]] #退訂所有給定模式的頻道

舉例

127.0.0.1:6379> subscribe codelnn #訂閱一個頻道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "codelnn"
3) (integer) 1
#等待讀取推送的訊息
1) "message" #訊息
2) "codelnn" #頻道名稱
3) "hello lnn" #內容
127.0.0.1:6379> publish codelnn "hello lnn" # 釋出者釋出訊息到頻道
(integer) 1 
127.0.0.1:6379> 

應用場景:

1、構建實時的訊息系統,比如普通聊天、群聊等功能。

2、部落格網站訂閱,當作者釋出就可以推送給粉絲 。

3、微信公眾號模式。

1.7redis主從複製

是什麼?

主從複製:是指將一臺Redis伺服器的資料,複製到其他的Redis伺服器。前者稱為主節點(master/leader),後者稱為從節點(slave/follower);資料的複製是單向的,只能由主節點到從節點。Master以寫為主,Slave 以讀為主。預設情況下,每臺Redis伺服器都是主節點;且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。

能幹什麼?

  • 讀寫分離
  • 容災恢復

怎麼玩?

準備啟動三個redis容器進行實驗

redis.conf
需修改埠 port
pid名字
log名字
dump.rdb名字
protected-mode no

# 6379 主機
docker run -d -p 6379:6379 --name redis6379 --privileged=true -v /usr/data/redis/redis6379/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6379/data:/data docker.io/redis redis-server /etc/redis/redis.conf
#6380 從機
 docker run -d -p 6380:6380 --name redis6380 --privileged=true -v /usr/data/redis/redis6380/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6380/data:/data docker.io/redis redis-server /etc/redis/redis.conf
#6381 從機
docker run -d -p 6381:6381 --name redis6381 --privileged=true -v /usr/data/redis/redis6381/redis.conf:/etc/redis/redis.conf -v /usr/data/redis/redis6381/data:/data docker.io/redis redis-server /etc/redis/redis.conf

進入容器

配從不配主

從庫配置

#配置從庫
slaveof 主庫ip 主庫埠
#檢視主從資訊
info replication

#主機6379
172.17.0.2:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.4,port=6381,state=online,offset=84,lag=0
slave1:ip=172.17.0.3,port=6380,state=online,offset=84,lag=1
master_replid:082fca9124ab941709644f16c77111552b588440
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84
#從機6380
172.17.0.4:6381> info replication
# Replication
role:slave
master_host:172.17.0.2
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:84
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:082fca9124ab941709644f16c77111552b588440
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

每次與master斷開後,都需要重新連線,除非你配置進redis.conf檔案。

常用的主從方式

一主二僕 :一個master兩個slave

注意點

  • 第一次slave1和slave2切入點,是全量複製,之後是增量複製。
  • 主機可以寫,但是從機不可以寫,從機只能讀。
  • 主機shutdown後從機待機狀態,等主機回來後,主機新增記錄從機可以順利複製。
  • 從機複製到的資料,會被從機持久化,就算shutdown斷開連線依然會有資料。
  • 重新連線或者變更master,會清除之前的資料,重新建立拷貝最新的資料。

薪火相傳:上一個slave可以是下一個slave的master,slave同樣可以接收其他slaves的連線和同步請求,那麼該slave作為了鏈條中下一個的master,可以有效減輕master的寫壓力。

注意點

​ 同上一主二僕

反客為主

如果主機斷開了連線,我們可以使用 slaveof no one 讓自己變成主機!其他的節點就可以手動連線到最新的這個主節點(手動)。

哨兵模式

反客為主的自動版,能夠後臺監控master庫是否故障,如果故障了根據投票自動將slave庫轉換為主庫。一組sentinel能同時監控多個master。底層是一個投票演算法。

使用步驟

  1. 在對應redis.conf同目錄下新建sentinel.conf檔案,名字絕對不能錯。

  2. 配置哨兵,在sentinel.conf檔案中填入內容(可以配置多個)

    #說明:最後一個數字1,表示主機掛掉後slave投票看讓誰接替成為主機,得票數多則成為主機。
    sentinel monitor 被監控資料庫名字(自己起名字) ip port 1
    sentinel monitor mymaster 172.17.0.2 6379 1
    
    
    port 26379
    dir "/data"
    logfile "sentinel-26379.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
    port 26380
    dir "/data"
    logfile "sentinel-26380.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
    port 26381
    dir "/data"
    logfile "sentinel-26381.log"
    sentinel monitor mymaster 172.17.0.2 6379 1
    sentinel down-after-milliseconds mymaster 10000
    sentinel failover-timeout mymaster 60000
    
  3. 啟動哨兵

    docker run -d -p 26379:26379 --name sentinel26379 --privileged=true -v /usr/data/redis/redis6379/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6379/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    
    docker run -d -p 26380:26380 --name sentinel26380 --privileged=true -v /usr/data/redis/redis6380/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6380/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    
    docker run -d -p 26381:26381 --name sentinel26381 --privileged=true -v /usr/data/redis/redis6381/sentinel.conf:/etc/redis/sentinel.conf -v /usr/data/redis/redis6381/data:/data docker.io/redis redis-sentinel /etc/redis/sentinel.conf
    

    1. 日誌記錄

注意點

  • 當master掛掉後,會通過選票進行選出下一個master。而且只有使用了sentinel.conf啟動的才能開啟選票。
  • 當原來的master回來後,會變成slave。

複製原理

slave 啟動成功連線到 master 後,會發送個sync同步命令,master 接到命令,啟動後臺的存檔程序,同時收集所有接收到的用於修改資料集命令,在後臺程序執行完畢之後,master將傳送整個資料檔案到slave,並完成一次完全同步。

全量複製:slave服務在接收到資料庫檔案資料後,將其存檔並載入到記憶體中。

增量複製:master 繼續將新的所有收集到的修改命令依次傳給slave,完成同步但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行! 我們的資料一定可以在從機中看到!

1.8redis快取穿透、擊穿和雪崩

快取處理流程

前臺請求,後臺先從快取中取資料,取到直接返回結果,取不到時從資料庫中取,資料庫取到更新快取,並返回結果,資料庫也沒取到,那直接返回空結果。

快取穿透

概念

快取穿透:key對應的資料在資料庫並不存在,每次針對此key的請求從快取獲取不到,請求都會到資料庫,從而可能壓垮資料來源。比如用一個不存在的使用者id獲取使用者資訊,不論快取還是資料庫都沒有,若黑客利用此漏洞進行攻擊可能壓垮資料庫。

解決方法

  • 快取空物件:當他第一次查詢時,判斷快取沒有就會去資料庫查詢,可以在快取中新增這個key,並且賦值為null,第二次查詢時就會查詢快取,不會再查詢資料庫,就可以避免這個問題,如果之後確實添加了這個key的值,也會將之前的值覆蓋 。缺點就是這樣做的話,如果傳送了很多不存在的key,會給redis造成大量的空間浪費,也是治標不治本。

  • 布隆過濾器:將所有可能存在的key雜湊到一個足夠大的bitmap中,一個一定不存在的key會被這個bitmap攔截掉,從而避免了對底層儲存系統的查詢壓力。

快取擊穿

概念

對於一些設定了過期時間的key,如果這些key可能會在某些時間點被超高併發地訪問,是一種非常“熱點”的資料。這個時候,需要考慮一個問題:快取被“擊穿”的問題,快取在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的併發請求過來,這些請求發現快取過期一般都會從後端DB載入資料並回設到快取,這個時候大併發的請求可能會瞬間把後端DB壓垮。

解決方法

  • 設定熱點資料永不過期 :從快取層面來看,沒有設定過期時間,所以不會出現熱點 key 過期後產生的問題。

  • 加互斥鎖:使用分散式鎖,保證對於每個key同時只有一個執行緒去查詢後端服務,其他執行緒沒有獲得分散式鎖的許可權,因此只需要等待即可。這種方式將高併發的壓力轉移到了分散式鎖,因此對分散式鎖的考驗很大。

    SETNX,是「SET if Not eXists」的縮寫,也就是隻有不存在的時候才設定,可以利用它來實現鎖的效果。

    public String get(key) {
          String value = redis.get(key);
          if (value == null) { //代表快取值過期
              //設定3min的超時,防止del操作失敗的時候,下次快取過期一直不能load db
    		  if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表設定成功
                   value = db.get(key);
                          redis.set(key, value, expire_secs);
                          redis.del(key_mutex);
                  } else {  //這個時候代表同時候的其他執行緒已經load db並回設到快取了,這時候重試獲取快取值即可
                          sleep(50);
                          get(key);  //重試
                  }
              } else {
                  return value;      
              }
     }
    

快取雪崩

概念

快取雪崩,是指在某一個時間段,快取集中過期失效或者Redis 宕機!

產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了快取,假設快取一個小時。那麼到了凌晨一點鐘的時候,這批商品的快取就都 過期了。而對這批商品的訪問查詢,都落到了資料庫上,對於資料庫而言,就會產生週期性的壓力波峰。於是所有的請求都會達到儲存層,儲存層的呼叫量會暴增,造成儲存層也會掛掉的情況。

解決方法

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

才設定,可以利用它來實現鎖的效果。

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //代表快取值過期
          //設定3min的超時,防止del操作失敗的時候,下次快取過期一直不能load db
		  if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表設定成功
               value = db.get(key);
                      redis.set(key, value, expire_secs);
                      redis.del(key_mutex);
              } else {  //這個時候代表同時候的其他執行緒已經load db並回設到快取了,這時候重試獲取快取值即可
                      sleep(50);
                      get(key);  //重試
              }
          } else {
              return value;      
          }
 }

快取雪崩

概念

快取雪崩,是指在某一個時間段,快取集中過期失效或者Redis 宕機!

產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了快取,假設快取一個小時。那麼到了凌晨一點鐘的時候,這批商品的快取就都 過期了。而對這批商品的訪問查詢,都落到了資料庫上,對於資料庫而言,就會產生週期性的壓力波峰。於是所有的請求都會達到儲存層,儲存層的呼叫量會暴增,造成儲存層也會掛掉的情況。

解決方法

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

參考連結