Redis知識總結

PatrickLee666發表於2019-03-03

最近在學校參與了一些專案,其中包含單點登陸(叢集),因為使用的redis,所以這裡簡單對redis做一個學習總結,reids的API的話就不放在本文浪費時間了,主要談談知識的本身

在開始redis之前,我們要了解,現在當作非關係型資料庫遠遠不止redis這一種,當然,以後可能也會更多,若是要依次學習所有的這類資料庫,那是很困難的,但他們都屬於nosql(not only sql非關係型資料庫),所以,我們有必要先了解其根源,找到他們的通性,從其名字也可以看出,他和關係型資料庫不是對立的,更多的是一種補充

Nosql

為什麼要有Nosql?

目前網際網路對技術提出了更多的要求,主要體現在以下方面:

  • 低延遲的讀寫速度:應用快速地反應能極大地提升使用者的滿意度;
  • 海量的資料和流量:對於搜尋這樣大型應用而言,需要利用PB級別的資料和能應對百萬級的流量;
  • 大規模叢集的管理:系統管理員希望分散式應用能更簡單的部署和管理;
  • 龐大運營成本的考量:IT經理們希望在硬體成本、軟體成本和人力成本能夠有大幅度地降低;

但是,關係型資料庫由於自身的特點,讓他很難實現這些需求:

  • 擴充套件困難
  • 讀寫慢
  • 成本高
  • 支撐容量有限

所以,Nosql非常關注併發讀寫,大量資料儲存,它的優點如下:

  • 高可擴充套件性
  • 分散式計算
  • 低成本
  • 架構的靈活性,半結構化資料
  • 沒有複雜的關係

當然,Nosql也有缺點:

  • 不提供SQL語句支援
  • 特性不夠多(例如事務,在等會redis中會總結)

Nosql四大分類

鍵值(Key-Value)儲存資料庫

相關產品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB 典型應用: 內容快取,主要用於處理大量資料的高訪問負載。 資料模型: 一系列鍵值對 優勢: 快速查詢 劣勢: 儲存的資料缺少結構化

列儲存資料庫

相關產品:Cassandra, HBase, Riak 典型應用:分散式的檔案系統 資料模型:以列簇式儲存,將同一列資料存在一起 優勢:查詢速度快,可擴充套件性強,更容易進行分散式擴充套件 劣勢:功能相對侷限

文件型資料庫

相關產品:CouchDB、MongoDB 典型應用:Web應用(與Key-Value類似,Value是結構化的) 資料模型: 一系列鍵值對 優勢:資料結構要求不嚴格 劣勢: 查詢效能不高,而且缺乏統一的查詢語法

圖形(Graph)資料庫

相關資料庫:Neo4J、InfoGrid、Infinite Graph 典型應用:社交網路 資料模型:圖結構 優勢:利用圖結構相關演算法。 劣勢:需要對整個圖做計算才能得出結果,不容易做分散式的叢集方案。

CAP定理

CAP定理意思是在分散式計算系統中只能同時最多滿足以下兩點

  • 一致性(Consistency) (所有節點在同一時間具有相同的資料)
  • 可用性(Availability) (保證每個請求不管成功或者失敗都有響應)
  • 分隔容忍(Partition tolerance) (系統中任意資訊的丟失或失敗不會影響系統的繼續運作)
    CAP理論的核心是:一個分散式系統不可能同時很好的滿足一致性,可用性和分割槽容錯性這三個需求,最多隻能同時較好的滿足兩個。

因此,根據 CAP 原理將 NoSQL 資料庫分成了滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三 大類:

  • CA – 單點叢集,滿足一致性,可用性的系統,通常在可擴充套件性上不太強大。(傳統Oracle資料庫)
  • CP – 滿足一致性,分割槽容忍性的系統,通常效能不是特別高。(Redis、Mongodb)
  • AP – 滿足可用性,分割槽容忍性的系統,通常可能對一致性要求低一些。(大多數網站架構的選擇)
    image

注意:分散式架構的時候必須做出取捨。一致性和可用性之間取一個平衡。多餘大多數web應用,其實並不需要強一致性。因此犧牲C換取P,這是目前分散式資料庫產品的方向

Nosql總結

綜上所述,Nosql的出現更多的是為了解決資料量大,分散式中的問題,為了資料吞吐量上的數量而對資料一致性打一點折扣。

e.g:

微博上一篇文章的點贊數,可能三秒內就會新增幾百個贊(行為資料),這時,不可能保證使用者點一個贊就更新一次,這時,就可以使用Nosql了。

而對於像轉賬這類(交易資料)的事務型操作,只能使用關係型資料庫了。

Redis

Redis是什麼

它是一個快取資料庫,由C語言編寫,key-value儲存系統,屬於nosql

五大基本資料型別

1.字串型別(String)
2.雜湊型別(hash)
3.列表型別(list)
4.集合型別(set)
5.有序集合型別(zset)

因為redis中都是存取的k-v鍵值對形式,這裡的基本資料型別指的是value的資料型別,所有的key都是字串型別

關於它的API,這裡就不贅述了,看官方文件即可

字串型別

字串是Redis最基本的資料型別,不僅所有key都是字串型別,其它幾種資料型別構成的元素也是字串。注意字串的長度不能超過512M。

這裡的字串可以是字串,整數或者是浮點數,例如想知道一個ip訪問了多少次本網站,就可以用INCRBY實現遞增。

列表型別

一個List結構可以有序的儲存多個字串,並且是允許元素重複的,可以按照插入順序排序,可以新增一個元素到列表的頭部(左邊)或者尾部(右邊),它的底層實際上是個雙向連結串列結構。

Set集合型別

集合物件 set 是 string 型別(整數也會轉換成string型別進行儲存)的無序集合。通過雜湊表來保證自己儲存的每個字串都是各不相同的,即內部使用值為空的雜湊表。

集合和列表的區別:集合中的元素是無序的,因此不能通過索引來操作元素;集合中的元素不能有重複。

Hash雜湊型別

雜湊物件的鍵是一個字串型別,值是一個鍵值對集合。

有序集合ZSET

有序集合物件是有序的。與列表使用索引下標作為排序依據不同,有序集合為每個元素設定一個分數(score)作為排序依據。

應用場景

  • 對於string 資料型別,因為string 型別是二進位制安全的,可以用來存放圖片,視訊等內容,另外由於Redis的高效能讀寫功能,而string型別的value也可以是數字,可以用作計數器(INCR,DECR),比如分散式環境中統計系統的線上人數,秒殺等。
  • 對於 hash 資料型別,value 存放的是鍵值對,比如可以做單點登入存放使用者資訊。
  • 對於 list 資料型別,可以實現簡單的訊息佇列,另外可以利用lrange命令,做基於redis的分頁功能
  • 對於 set 資料型別,由於底層是字典實現的,查詢元素特別快,另外set 資料型別不允許重複,利用這兩個特性我們可以進行全域性去重,比如在使用者註冊模組,判斷使用者名稱是否註冊;另外就是利用交集、並集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。
  • 對於 zset 資料型別,有序的集合,可以做範圍查詢,排行榜應用,取 TOP N 操作等。

配置檔案介紹

#redis.conf
# Redis configuration file example.
# ./redis-server /path/to/redis.conf

################################## INCLUDES ###################################
#這在你有標準配置模板但是每個redis伺服器又需要個性設定的時候很有用。
# include /path/to/local.conf
# include /path/to/other.conf

################################ GENERAL #####################################

#是否在後臺執行,yes:後臺執行;no:不是後臺執行(老版本預設)
daemonize yes

  #3.2裡的引數,是否開啟保護模式,預設開啟。要是配置裡沒有指定bind和密碼。開啟該引數後,redis只會本地進行訪問,拒絕外部訪問。要是開啟了密碼   和bind,可以開啟。否   則最好關閉,設定為no。
  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

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

#配置unix socket來讓redis支援監聽本地連線。
# unixsocket /var/run/redis/redis.sock
#配置unix socket使用檔案的許可權
# unixsocketperm 700

# 此引數為設定客戶端空閒超過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 ################################
# 快照配置
# 註釋掉“save”這一行配置項就可以讓儲存資料庫功能失效
# 設定sedis進行資料庫映象的頻率。
# 900秒(15分鐘)內至少1個key值改變(則進行資料庫儲存--持久化) 
# 300秒(5分鐘)內至少10個key值改變(則進行資料庫儲存--持久化) 
# 60秒(1分鐘)內至少10000個key值改變(則進行資料庫儲存--持久化)
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/lib/redis

################################# REPLICATION #################################
#複製選項,slave複製對應的master。
# slaveof <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”。
slave-serve-stale-data yes

#作為從伺服器,預設情況下是隻讀的(yes),可以修改成NO,用於寫(不建議)。
slave-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的一段時間,記憶體會被釋放出來,預設1m。
# repl-backlog-size 5mb

#master沒有slave一段時間會釋放複製緩衝區的記憶體,repl-backlog-ttl用來設定該時間長度。單位為秒。
# repl-backlog-ttl 3600

#當master不可用,Sentinel會根據slave的優先順序選舉一個master。最低的優先順序的slave,當選master。而配置成0,永遠不會被選舉。
slave-priority 100

#redis提供了可以讓master停止寫入的方式,如果配置了min-slaves-to-write,健康的slave的個數小於N,mater就禁止寫入。master最少得有多少個健康的slave存活才能執行寫命令。這個配置雖然不能保證N個slave都一定能接收到master的寫操作,但是能避免沒有足夠健康的slave的時候,master不能寫入來避免資料丟失。設定為0是關閉該功能。
# min-slaves-to-write 3

#延遲小於min-slaves-max-lag秒的slave才認為是健康的slave。
# min-slaves-max-lag 10

# 設定1或另一個設定為0禁用這個特性。
# Setting one or the other to 0 disables the feature.
# By default min-slaves-to-write is set to 0 (feature disabled) and
# min-slaves-max-lag is set to 10.

################################## SECURITY ###################################
#requirepass配置可以讓使用者使用AUTH命令來認證密碼,才能使用其他命令。這讓redis可以使用在不受信任的網路中。為了保持向後的相容性,可以註釋該命令,因為大部分使用者也不需要認證。使用requirepass的時候需要注意,因為redis太快了,每秒可以認證15w次密碼,簡單的密碼很容易被攻破,所以最好使用一個更復雜的密碼。
# requirepass foobared

#把危險的命令給修改成其他名稱。比如CONFIG命令可以重新命名為一個很難被猜到的命令,這樣使用者不能使用,而內部工具還能接著使用。
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52

#設定成一個空的值,可以禁止一個命令
# rename-command CONFIG ""
################################### LIMITS ####################################

# 設定能連上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

############################## APPEND ONLY MODE ###############################
#預設redis使用的是rdb方式持久化,這種方式在許多應用中已經足夠用了。但是redis如果中途當機,會導致可能有幾分鐘的資料丟失,根據save來策略進行持久化,Append Only File是另一種持久化方式,可以提供更好的持久化特性。Redis會把每次寫入的資料在接收後都寫入 appendonly.aof 檔案,每次啟動時Redis都會先把這個檔案的資料讀入記憶體裡,先忽略RDB檔案。
appendonly no

#aof檔名
appendfilename "appendonly.aof"

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

# 在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

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

################################ REDIS CLUSTER ###############################
#叢集開關,預設是不開啟叢集模式。
# 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-slave-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 ###################################
###slog log是用來記錄redis執行中執行比較慢的命令耗時。當命令的執行超過了指定時間,就記錄在slow log中,slog 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

#資料量小於等於list-max-ziplist-entries用ziplist,大於list-max-ziplist-entries用list。
list-max-ziplist-entries 512
#value大小小於等於list-max-ziplist-value的用ziplist,大於list-max-ziplist-value用list。
list-max-ziplist-value 64

#資料量小於等於set-max-intset-entries用iniset,大於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

#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 slave 256mb 64mb 60
#對於pubsub client,如果client-output-buffer一旦超過32mb,又或者超過8mb持續60秒,那麼伺服器就會立即斷開客戶端連線。
client-output-buffer-limit pubsub 32mb 8mb 60

#redis執行任務的頻率為1s除以hz。
hz 10

#在aof重寫的時候,如果開啟了aof-rewrite-incremental-fsync開關,系統會每32MB執行一次fsync。這對於把檔案寫入磁碟是有幫助的,可以避免過大的延遲峰值。
aof-rewrite-incremental-fsync yes
複製程式碼

持久化

前文說過,redis是記憶體資料庫,為了保證資料在斷電後不會丟失,需要將它持久化到硬碟上。redis持久化分為兩種。

RDB持久化

RDB持久化是指在指定的時間間隔內將記憶體中的資料集快照寫入磁碟。

也是預設的持久化方式,這種方式是就是將記憶體中資料以快照的方式寫入到二進位制檔案中,預設的檔名為dump.rdb。

可以通過配置設定自動做快照持久化的方式。我們可以配置redis在n秒內如果超過m個key被修改就自動做快照,下面是預設的快照儲存配置

  • save 900 1 #900秒內如果超過1個key被修改,則發起快照儲存
  • save 300 10 #300秒內容如超過10個key被修改,則發起快照儲存
  • save 60 10000
RDB儲存過程
  • redis呼叫fork,現在有了子程式和父程式
  • 父程式繼續處理client請求,子程式負責將記憶體內容寫入到臨時檔案。由於os的寫時複製機制(copy on write)父子程式會共享相同的物理頁面,當父程式處理寫請求時os會為父程式要修改的頁面建立副本,而不是寫共享的頁面。所以子程式的地址空間內的數 據是fork時刻整個資料庫的一個快照。
  • 當子程式將快照寫入臨時檔案完畢後,用臨時檔案替換原來的快照檔案,然後子程式退出。
如何觸發快照

client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主執行緒中儲存快照的,由於redis是用一個主執行緒來處理所有 client的請求,這種方式會阻塞所有client請求。所以不推薦使用。

另一點需要注意的是,每次快照持久化都是將記憶體資料完整寫入到磁碟一次,並不 是增量的只同步髒資料。如果資料量大的話,而且寫操作比較多,必然會引起大量的磁碟io操作,可能會嚴重影響效能。

優勢
  • 一旦採用該方式,那麼你的整個Redis資料庫將只包含一個檔案,這樣非常方便進行備份
  • 方便備份,我們可以很容易的將一個一個RDB檔案移動到其他的儲存介質上
  • RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快。
  • RDB 可以最大化 Redis 的效能:父程式在儲存 RDB 檔案時唯一要做的就是 fork 出一個子程式,然後這個子程式就會處理接下來的所有儲存工作,父程式無須執行任何磁碟 I/O 操作。
劣勢
  • 如果你需要儘量避免在伺服器故障時丟失資料,那麼 RDB 不適合你。 雖然 Redis 允許你設定不同的儲存點(save point)來控制儲存 RDB 檔案的頻率, 但是, 因為RDB 檔案需要儲存整個資料集的狀態, 所以它並不是一個輕鬆的操作。 因此你可能會至少 5 分鐘才儲存一次 RDB 檔案。 在這種情況下, 一旦發生故障停機, 你就可能會丟失好幾分鐘的資料。(丟失資料)
  • 每次儲存 RDB 的時候,Redis 都要 fork() 出一個子程式,並由子程式來進行實際的持久化工作。 在資料集比較龐大時, fork() 可能會非常耗時,造成伺服器在某某毫秒內停止處理客戶端; 如果資料集非常巨大,並且 CPU 時間非常緊張的話,那麼這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行 fork() ,但無論 AOF 重寫的執行間隔有多長,資料的耐久性都不會有任何損失。(耗時)
rdb總結
image

AOF持久化

AOF儲存過程

redis會將每一個收到的寫命令都通過write函式追加到檔案中(預設是 appendonly.aof)。

當redis重啟時會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。當然由於os會在核心中快取 write做的修改,所以可能不是立即寫到磁碟上。這樣aof方式的持久化也還是有可能會丟失部分修改。不過我們可以通過配置檔案告訴redis我們想要 通過fsync函式強制os寫入到磁碟的時機。有三種方式如下(預設是:每秒fsync一次)

appendonly yes //啟用aof持久化方式

appendfsync always //每次收到寫命令就立即強制寫入磁碟,最慢的,但是保證完全的持久化,不推薦使用

appendfsync everysec //每秒鐘強制寫入磁碟一次,在效能和持久化方面做了很好的折中,推薦

appendfsync no //完全依賴os,效能最好,持久化沒保證

aof 的方式也同時帶來了另一個問題。持久化檔案會變的越來越大。例如我們呼叫incr test命令100次,檔案中必須儲存全部的100條命令,其實有99條都是多餘的。因為要恢復資料庫的狀態其實檔案中儲存一條set test 100就夠了。

為了壓縮aof的持久化檔案。redis提供了bgrewriteaof命令。收到此命令redis將使用與快照類似的方式將記憶體中的資料以命令的方式儲存到臨時檔案中,最後替換原來的檔案。具體過程如下

redis呼叫fork,現在有父子兩個程式子程式根據記憶體中的資料庫快照,往臨時檔案中寫入重建資料庫狀態的命令父程式繼續處理client請求,除了把寫命令寫入到原來的aof檔案中。同時把收到的寫命令快取起來。這樣就能保證如果子程式重寫失敗的話並不會出問題。當子程式把快照內容寫入已命令方式寫到臨時檔案中後,子程式發訊號通知父程式。然後父程式把快取的寫命令也寫入到臨時檔案。現在父程式可以使用臨時檔案替換老的aof檔案,並重新命名,後面收到的寫命令也開始往新的aof檔案中追加。 需要注意到是重寫aof檔案的操作,並沒有讀取舊的aof檔案,而是將整個記憶體中的資料庫內容用命令的方式重寫了一個新的aof檔案,這點和快照有點類似

優勢
  • 耐久
  • 不斷電
  • 易讀
劣勢
  • 資料量大

抉擇

一般來說,應該同時使用兩種持久化功能。 如果你非常關心你的資料, 但仍然可以承受數分鐘以內的資料丟失, 那麼你可以只使用 RDB 持久化。

redis事務

是什麼

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

能幹嘛

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

3個階段

  • 開啟:以MULTI開始一個事務
  • 入隊:將多個命令入隊到事務中,接到這些命令並不會立即執行,而是放到等待執行的事務佇列裡面
  • 執行:由EXEC命令觸發事務

3特性

  • 單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端傳送來的命令請求所打斷。
  • 沒有隔離級別的概念:佇列中的命令沒有提交之前都不會實際的被執行,因為事務提交前任何指令都不會被實際執行,
  • 也就不存在”事務內的查詢要看到事務裡的更新,在事務外查詢不能看到”這個讓人萬分頭痛的問題
  • 不保證原子性:redis同一個事務中如果有一條命令執行失敗,其後的命令仍然會被執行,沒有回滾

關於redis事務

首先,讓我們來看一個例子:

image

這個操作採用了事務模式,並在第6個指令進入佇列的時候就已經出錯,所以導致整個事務的命令都不會被執行

接下來,再看一個操作

image

實際上這個問題很簡單,這個incr name錯誤指令在入隊的時候沒有出錯,卻在執行的時候出錯了,redis預設跳過這個命令執行後續命令

所以,這就是為什麼我在開頭說redis的事務只是部分事務

redis的鎖機制

redis的鎖CAS類似於樂觀鎖,使用方式為用watch關鍵字監視一個(或多個)資料,例如:

假設現在兩個客戶端A,B

1.客戶端A監控count,並修改count

image

2.待A執行完畢後,客戶端B修改count

image

3.待B執行完畢後,A提交事務

image

可以看到,顯示了(nil),即這次事務失敗,count變為50

事務總結

  • 單獨的隔離操作:事務中的所有命令會被序列化、按順序執行,在執行的過程中不會被其他客戶端傳送來的命令打斷
  • 沒有隔離級別的概念:佇列中的命令在事務沒有被提交之前不會被實際執行
  • 不保證原子性:redis中的一個事務中如果存在命令執行失敗,那麼其他命令依然會被執行,沒有回滾機制

訊息釋出訂閱

Redis提供了釋出訂閱功能,可用於訊息傳輸,程式間的一種通訊方式,Redis的釋出訂閱機制包括三個部分,釋出者,訂閱者和Channel。

釋出者和訂閱者都是Redis客戶端,Channel則為Redis伺服器端,釋出者將訊息傳送到某個的頻道,訂閱了這個頻道的訂閱者就能接收到這條訊息。

當然,一般很少人用redis的釋出訂閱,取而代之的是訊息佇列MQ(ActiveMQ),但還是有必要了解redis有該功能的。

主從複製

為什麼有它

  • 讀寫分離:和關係型資料庫一樣,雖然redis作為記憶體資料庫,他同樣面臨讀寫壓力,通過設定主從redis可以實現讀寫分離減輕壓力
  • 容災恢復:假設某位程式設計師不小心把庫房燒了?,主庫沒了,如果我們設計了從庫,這時我們將完全不用擔心資料沒了的問題,因為從庫和主庫有同樣的資料

是什麼

行話:也就是我們所說的主從複製,主機資料更新後根據配置和策略,自動同步到備機的master/slaver機制,Master以寫為主,Slave以讀為主,一個從伺服器只能有一個主伺服器,並且不支援主主複製。

複製原理

全量同步

Redis全量複製一般發生在Slave初始化階段,這時Slave需要將Master上的所有資料都複製一份。具體步驟如下:

1.從伺服器連線主伺服器,傳送SYNC命令;

2.主伺服器接收到SYNC命名後,開始執行BGSAVE命令生成RDB檔案並使用緩衝區記錄此後執行的所有寫命令;

3.主伺服器BGSAVE執行完後,向所有從伺服器傳送快照檔案,並在傳送期間繼續記錄被執行的寫命令;

4.從伺服器收到快照檔案後丟棄所有舊資料,載入收到的快照;

5.主伺服器快照傳送完畢後開始向從伺服器傳送緩衝區中的寫命令;

6.從伺服器完成對快照的載入,開始接收命令請求,並執行來自主伺服器緩衝區的寫命令;

增量同步

Redis增量複製是指Slave初始化後開始正常工作時主伺服器發生的寫操作同步到從伺服器的過程。 增量複製的過程主要是主伺服器每執行一個寫命令就會向從伺服器傳送相同的寫命令,從伺服器接收並執行收到的寫命令。

現在,出現了幾個問題:

  • 從機是否可以寫?
  • 如果從庫死了之後活了他還是從庫嗎?
  • 如果主庫死了之後它的從庫該怎麼辦?(普通模式和哨兵模式)主庫活了之後還是主庫嗎?
為了減少閱讀量,這裡就不實驗論證了,客官們可以自行嘗試
先回答第一個問題:

從機不可寫

先回答第二個問題:

在Redis2.8版本之前,從庫死後復活會傳送sync請求和主機全量同步,所以死後復活還是從庫,但是,當多個從庫同時復活的話會導致主機IO劇增而當機

2.8版本之後,主伺服器只需要將斷線期間執行的命令發給從伺服器即可

第三個問題:

主機死後,從機待命。並且主庫回來後,他將仍然是主庫

哨兵模式:反客為主,即哨兵模式在後臺監控,主庫死後根據投票將它的從庫設定為新的主庫

哨兵模式的出現正是為了解決主庫死後無人領導的狀態。

那麼有了哨兵模式後,原來死掉的主庫回來後會發生什麼呢?答案是原來的主庫回來後就變為了從庫。

最後一點點

對於一個slave從庫他同樣可以接收其他從庫的連線請求,即該slave作為下一個的master

Redis適用場景

  • 資料高併發讀寫
  • 海量資料讀寫
  • 擴充套件性要求高的資料

例子:

1.儲存熱點資訊
2.排行榜
3.計數
4.單點登陸(解決session共享問題)
5.等等。。。