Redis配置與優化


一、關系數據庫和非關系型數據庫

1、關系型數據庫

關系型數據庫是一個結構化的數據庫,創建在關系模型(二維表格模型)基礎上,一般面向於記錄。

SQL語句(標准數據查詢語言)就是一種基於關系型數據庫的語言,用於執行對關系型數據庫中數據的檢索和操作。

主流的關系型數據庫包括 Oracle、MySQL、SQL Server、Microsoft Access、DB2、PostqreSQL 等。

以上數據庫在使用的時候必須先建庫建表設計表結構,然后存儲數據的時候按表結構去存,如果數據與表結構不匹配就會存儲失敗。

 

關系數據庫的存儲結構是二維表格,關系型數據庫大部分將數據存放到硬盤中,可以將有關系的表放在一個庫中

在每個二維表格中

每一行稱為一條記錄,用來描述一個對象的信息

每一列稱為一個字段,用來描述對象的一個屬性 

2、非關系型數據庫

NoSQL(NoSQL = Not Only SQL),意思是"不僅僅是 SQL",是非關系型數據庫的總稱。除了主流的關系型數據庫外的數據庫,都認為是非關系型。

不需要預先建庫建表定義數據存儲表結構,每條記錄可以有不同的數據類型和字段個數 (比如微信群聊甲的文字、圖片、視頻、音樂等)

主流的 NoSQL數據庫有 Redis、MongBD、Hbase、Memcached 等。

二、關系型數據庫和非關系型數據庫區別

1、數據存儲方式不同

關系型和非關系型數據庫的主要差異是數據存儲的方式。

1.1 關系型數據

天然就是表格式的,因此存儲在數據表的行和列中。數據表可以彼此關聯協作存儲,也很容易提取數據。

1.2 非關系型數據庫

與其相反,非關系型數據不適合存儲在數據表的行和列中,而是大塊組合在一起。非關系型數據通常存儲在數據集中,就像文檔、鍵值對或者圖結構。數據及其特性是選擇數據存儲和提取方式的首要影響因素。

2、擴展方式不同

SQL和NoSQL數據庫最大的差別可能是在擴展方式上,要支持日益增長的需求當然要擴展賴支持更多並發量

2.1 SQL數據庫

是縱向擴展,擴展CPU等性能磁盤空間空間,也就是提高處理能力,使用速度更快速的計算機,這樣處理相同的數據集就更快了。因為數據存儲在關系表中,操作的性能瓶頸可能涉及很多個表,這都需要通過提高計算機性能來克服。雖然SOL數據庫有很大擴展空間,但最終肯定會達到縱向擴展的上限。

2.2 NoSQL數據庫

是橫向擴展的。因為非關系型數據存儲天然就是分布式的,NoSQL數據庫的擴展可以通過給資源池添加更多普通的數據庫服務器(節點)來分擔負載。

3、對事務性的支持不同

3.1 SQL數據庫

如果數據操作需要高事務性或者復雜數據查詢需要控制執行計划,那么傳統的SQL數據庫從性能和穩定性方面考慮是最佳選擇。SQL,數據庫支持對事務原子性細粒度控制,並且易於回滾事務。

3.2 NoSQL數據庫

雖然NoSQL數據庫也可以使用事務操作, 但穩定性方面沒法和關系型數據庫比較,所以它們真正閃亮的價值是在操作的擴展性和大數據量處理方面。

• 關系型: 特別適合高事務性要求和需要控制執行計划的任務

• 非關系型: 此處會稍顯弱勢,其價值點在於高擴展性和大數據量處理方面

4、非關系型數據庫產生背景

可用於應對 Web2.0 純動態網站類型的三高問題。

(1)Highperformance——對數據庫高並發讀寫需求

(2)Huge Storage——對海量數據高效存儲與訪問需求

(3)High Scalability && High Availability——對數據庫高可擴展性與高可用性需求

關系型數據庫和非關系型數據庫都有各自的特點與應用場景,兩者的緊密結合將會給web2.0的數據庫發展帶來新的思略。讓關系數據庫關注在關系上,非關系型數據庫關注在存儲上。

例如,在讀寫分離的MySQL數據庫環境中,可以把經常訪問的數據存儲在非關系型數據庫中,提升訪問速度。

5、SQL和NoSQL數據的存儲過程

5.1 關系型數據庫

實例-->數據庫-->表(table)-->記錄行(row)、數據字段(column)

5.2 非關系型數據庫

實例-->數據庫-->集合(collection)-->鍵值對(key-value)、文檔、圖結構

非關系型數據庫不需要手動建數據庫和集合 (表)。

三、Redis數據庫

1. Redis數據庫的概述

Redis(遠程字典服務器)是一個開源的、使用C語言編寫的NoSQL數據庫

Redis 基於內存運行並支持持久化,采用key-value(鍵值對)的存儲形式,是目前分布式架構中不可或缺的一環。

Redis服務器程序是單進程模型,也就是在一台服務器上可以同時啟動多個Redis進程,Redis的實際處理速度則是完全依靠於主進程的執行效率。

若在服務器上只運行一個Redis進程,當多個客戶端同時訪問時,服務器的處理能力是會有一定程度的下降; 若在同一台服務器上開啟多個Redis進程,Redis在提高並發處理能力的同時會給服務器的CPU造成很大壓力。

在實際生產環境中,需要根據實際的需求來決定開啟多少個Redis進程。若對高並發要求更高一些,可能會考慮在同一台服務器上開啟多個進程。若CPU資源比較緊張,采用單進程即可。

*Redis6.0之前都是單線程,6.0版本之后支持多線程,但一般只針對網絡,讀寫方面還是使用單線程

2、Redis的特點

(1)具有極高的數據讀寫速度∶數據讀取的速度最高可達到 110000 次/s,數據寫入速度最高可達到 81000 次/s。

(2)支持豐富的數據類型∶使用key-value存儲模式,Strings、Lists、Hashes、Sets 及 Sorted Sets 等數據類型操作。

(3)支持數據的持久化∶可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用。

(4)原子性∶Redis所有操作都是原子性的。

(5)支持數據備份∶即 master-salve 模式的數據備份。

Redis作為基於內存運行的數據庫,緩存是其最常應用的場景之一。

除此之外, Redis常見應用場景還包括獲取最新N個數據的操作、排行榜類應用、計數器應用、存儲關系、實時分析系統、日志記錄(根據不同的數據類型實現不同場景的支持)。

3、Redis五種數據類型

3.1 String數據類型

概述:String是redis最基本的類型,最大能存儲512MB的數據,String類型是二進制安全的,即可以存儲任何數據、比如數字、圖片、序列化對象等

3.2 List數據類型

概述:列表的元素類型為string,按照插入順序排序,在列表的頭部或尾部添加元素

3.3 Hash數據類型(散列類型)

概述:hash用於存儲對象。可以采用這樣的命名方式:對象類別和ID構成鍵名,使用字段表示對象的屬性,而字段值則存儲屬性值。如:存儲ID為2的汽車對象。

如果Hash中包含很少的字段,那么該類型的數據也將僅占用很少的磁盤空間。每一個Hash可以存儲4294967295個鍵值對。

3.4 Set數據類型(無序集合)

概述:無序集合,元素類型為String類型,元素具有唯一性,不允許存在重復的成員。多個集合類型之間可以進行並集、交集和差集運算。

應用范圍:

1.可以使用Redis的Set數據類型跟蹤一些唯一性數據,比如訪問某一博客的唯一IP地址信息。對於此場景,我們僅需在每次訪問該博客時將訪問者的IP存入Redis中,Set數據類型會自動保證IP地址的唯一性。

2.充分利用Set類型的服務端聚合操作方便、高效的特性,可以用於維護數據對象之間的關聯關系。比如所有購買某一電子設備的客戶ID被存儲在一個指定的Set中,而購買另外一種電子產品的客戶ID被存儲在另外一個Set中,如果此時我們想獲取有哪些客戶同時購買了這兩種商品時,Set的intersections命令就可以充分發揮它的方便和效率的優勢了。

3.5  Sorted Set數據類型(zset、有序集合)

概述:有序集合,元素類型為Sting,元素具有唯一性,不能重復。

每個元素都會關聯一個double類型的分數score(表示權重),可以通過權重的大小排序,元素的score可以相同。

應用范圍:

1)可以用於一個大型在線游戲的積分排行榜。每當玩家的分數發生變化時,可以執行ZADD命令更新玩家的分數,此后再通過ZRANGE命令獲取積分TOP10的用戶信息。當然我們也可以利用ZRANK命令通過username來獲取玩家的排行信息。最后我們將組合使用ZRANGE和ZRANK命令快速的獲取和某個玩家積分相近的其他用戶的信息。

2)Sorted-Set類型還可用於構建索引數據。

4、Redis效率快的原因

(1)Redis 是一款純內存結構,避免了磁盤I/O等耗時操作。

(2)Redis 命令處理的核心模塊為單線程,減少了鎖競爭,以及頻繁創建線程和銷毀線程的代價,減少了線程上下文切換的消耗。

(3)采用了 I/O 多路復用機制,大大提升了並發效率。 

I/O多路復用程序雖然會同時監聽多個 Socket 連接,但是其會將監聽的 Socket 都放到一個隊列里面,然后通過這個隊列有序的,同步的將每個 Socket 對應的事件傳送給文件事件分派器,再由文件事件分派器分派給對應的事件處理器進行處理,只有當一個 Socket 所對應的事件被處理完畢之后,I/O多路復用程序才會繼續向文件事件分派器傳送下一個 Socket所對應的事件,這也可以驗證上面的結論,處理客戶端的命令請求是單線程的方式逐個處理,但是事件處理器內並不是只有一個線程。

5、 Memcached和Redis兩款主流NoSQL數據庫對比

memcached和redis就是將數據存儲在內存中,按照key-value的方式查詢,可以大幅度提高效率。

所以一般它們都用做緩存服務器,緩存常用的數據,需要查詢的時候,直接從它們那兒獲取,減少查詢數據庫的次數,提高查詢效率。

 

類型

Memcached

Reids

Key-value數據庫

Key-value數據庫

過期策略

支持

支持

數據類型

單一數據類型(Strings)

五大數據類型

持久化

不支持

支持

主從復制

不支持

支持

虛擬內存

不支持

支持

四、Redis 部署以及相關命令

1、Redis安裝部署的操作步驟

1.1   關閉防火牆和SElinux

systemctl stop firewalld
setenforce 0

1.2  安裝gcc gcc-c++ 編譯器  

yum install -y gcc gcc-c++ make  

1.3 將redis-5.0.7.tar.gz壓縮包上傳到/opt目錄中,解壓,並編譯安裝

tar zxvf redis-5.0.7.tar.gz -C /opt/

cd /opt/redis-5.0.7/
make
make PREFIX=/usr/local/redis install  

由於Redis源碼包中直接提供了Makefile文件,所以在解壓完軟件包后,不用先執行./configure進行配置,可直接執行make與make install命令進行安裝

1.4 執行軟件包提供的installserver.sh腳本文件設置Redis服務所需要的相關配置文件

cd /opt/redis-5.0.7/utils
./install_server.sh
......
#一直回車.
Please select the redis executable path [/usr/local/bin/redis-server]
/usr/local/redis/bin/redis-server
#需要手動修改為/usr/local/redis/bin/redis-server 注意要一次性正確輸入

Selected config:
Port : 6379	#默認偵聽端口為6379
Config file : /etc/redis/6379.conf	#配置文件路徑
Log file : /var/log/redis_6379.log	#日志文件路徑
Data dir : /var/lib/redis/6379	#數據文件路徑
Executable : /usr/local/redis/bin/redis-server	#可執行文件路徑
Cli Executable : /usr/local/bin/redis-cli	#客戶端命令工具  

1.5 把redis的可執行程序文件放入路徑環境變量的目錄中便於系統識別

ln -s /usr/local/redis/bin/* /usr/local/bin/

#當install_server.sh 腳本運行完畢,Redis 服務就已經啟動,默認偵聽端口為6379
netstat -natp | grep redis  

1.6 Redis服務控制

/etc/init.d/redis_6379 stop
#停止
/etc/init.d/redis_6379 start
#啟動
/etc/init.d/redis_6379 restart
#重啟
/etc/init.d/redis_6379 status
#狀態  

 

 

chmod +x /etc/init.d/redis_6379                                #加入全局系統環境,使用systemctl命令管理

chkconfig --add /etc/init.d/redis_6379     

systemctl start redis_6379.service  

 

1.7 修改配置/etc/redis/6379.conf參數

vim /etc/redis/6379.conf
bind 127.0.0.1 192.168.226.129
#70行,添加監聽的主機地址
port 6379
#93行,Redis默認的監聽端口
daemonize yes
#137行,啟用守護進程
pidfile /var/run/redis_6379.pid
#159行,指定PID文件
loglevel notice
#167行,日志級別
logfile /var/log/redis_6379.log
#172行,指定日志文件

/etc/init.d/redis_6379 restart

2、實例操作:Redis安裝部署

2.1   關閉防火牆和SElinux

 

2.2  安裝gcc gcc-c++ 編譯器 

2.3 將redis-5.0.7.tar.gz壓縮包上傳到/opt目錄中,解壓,並編譯安裝

2.4 執行軟件包提供的installserver.sh腳本文件設置Redis服務所需要的相關配置文件

2.5 把redis的可執行程序文件放入路徑環境變量的目錄中便於系統識別

2.6 Redis服務控制

2.7 修改配置/etc/redis/6379.conf參數

  

 

3、Redis命令工具

redis-server 用於啟動 Redis 的工具

redis-benchmark 用於檢測 Redis 在本機的運行效率

redis-check-aof 修復 AOF 持久化文件

redis-check-rdb 修復 RDB 持久化文件

redis-cli Redis命令行工具

rdb和aof是redis服務中持久化功能的兩種形式RDB AOF

redis-cli 常用於登陸至redis數據庫

4、redis-cli命令行工具(遠程登錄)

語法: redis-cli -h host -p port -a password
選項:
	-h :指定遠程主機
	-p :指定Redis 服務的端口號
	-a :指定密碼,未設置數據庫密碼可以省略-a選項
若不添加任何選項表示,則使用127.0.0.1:6379 連接本機上的 Redis 數據庫,

redis-cli -h 192.168.229.60 -p 6379

5、redis-benchmark 測試工具

redis-benchmark 是官方自帶的 Redis 性能測試工具,可以有效的測試 Redis 服務的性能。

-h:指定服務器主機名
-p:指定服務器端口
-s:指定服務器 socket
-c:指定並發連接數
-n:指定請求數
-d:以字節的形式指定 SET/GET 值的數據大小
-k:1=keep alive 0=reconnect 
-r: SET/GET/INCR 使用隨機 key, SADD 使用隨機值
-P:通過管道傳輸<numred>請求
-q:強制退出 redis。僅顯示 query/sec 值
–csv:以 CSV 格式輸出
-l:生成循環,永久執行測試
-t:僅運行以逗號分隔的測試命令列表
-I:Idle 模式。僅打開 N 個 idle 連接並等待


#向 IP 地址為 192.168.229.60、端口為 6379 的 Redis 服務器發送 100 個並發連接與 100000 個請求測試性能
redis-benchmark -h 192.168.229.60 -p 6379 -c 100 -n 100000

#測試存取大小為 100 字節的數據包的性能
redis-benchmark -h 192.168.229.60 -p 6379 -q -d 100

#測試本機上 Redis 服務在進行 set 與 lpush 操作時的性能
redis-benchmark -t set,lpush -n 100000 -q

5.1  向 IP 地址為 192.168.229.60、端口為 6379 的 Redis 服務器發送 100 個並發連接與 100000 個請求測試性能

5.2  測試存取大小為 100 字節的數據包的性能

5.3  測試本機上 Redis 服務在進行 set 與 lpush 操作時的性能

6、Redis數據庫常用命令 

6.1 常用命令

命令

解釋

set [key] [value]     

存放數據

get [key]

獲取某個key的數據

keys [*/?]

查找符合的鍵值列表,可搭配(*)、(?)使用

exists key [key...]   

判斷鍵值是否存在,返回0為不存在,1為存在

del key [key ...]    

刪除指定的key

type [key]    

查看key對應的value值類型

rename 源key 目標key  

對已有的key進行重命名,改名后會覆蓋同名的key的值

renamenx源key目標key

對已有的key進行重命名,但會判斷新名字是否存在,存在則不執行

dbszie      

查看當前數據庫key的數目

config set requirepass [密碼]   

設置密碼

auth [密碼]

設置密碼后需要驗證否則無法進行任何操作

config get requirepass     

查看密碼

config set requirepass ''

刪除密碼(即設置空密碼)

6.2 set與get用法

set: 存放數據,命令格式為 set key value

get: 獲取數據,命令格式為 get key 

[root@cm ~]# redis-cli -h 192.168.229.60 -p 6379
192.168.229.60:6379> set name lili
OK
192.168.229.60:6379> get name
"lili"

  

6.3 keys 命令

keys 命令可以取符合規則的鍵值列表,通常情況可以結合*、?等選項來使用。

192.168.229.60:6379> set name lili
OK
192.168.229.60:6379> get name
"lili"
192.168.229.60:6379> set a1 1
OK
192.168.229.60:6379> set a2 2
OK
192.168.229.60:6379> set a12 12
OK
192.168.229.60:6379> set a122 122
OK
192.168.229.60:6379> set v1 3
OK
192.168.229.60:6379> set k1 4
OK
192.168.229.60:6379> keys *   #查看當前數據庫中所有的鍵
 1) "k1"
 2) "name"
 3) "v1"
 4) "myset:__rand_int__"
 5) "mylist"
 6) "a12"
 7) "counter:__rand_int__"
 8) "a1"
 9) "a2"
10) "key:__rand_int__"
11) "a122"
192.168.229.60:6379> keys a*   #查看當前數據中以a開頭的所有數據
1) "a12"
2) "a1"
3) "a2"
4) "a122"
192.168.229.60:6379> keys a?   #查看當前數據中以a開頭,a開頭后面包含任意一位的數據
1) "a1"
2) "a2"
192.168.229.60:6379> keys a??  #查看當前數據中以a開頭,a開頭后面包含任意兩位的數據
1) "a12"

 

6.4 exists 命令

可以判斷鍵值是否存在 

192.168.229.60:6379> exists name 
(integer) 1
192.168.229.60:6379> exists a1 a2 a12 a122
(integer) 4
192.168.229.60:6379> exists a3
(integer) 0

6.5.del 命令

可以刪除當前數據庫的指定key  

192.168.229.60:6379> keys *
 1) "name"
 2) "v1"
 3) "myset:__rand_int__"
 4) "mylist"
 5) "a12"
 6) "counter:__rand_int__"
 7) "a1"
 8) "a2"
 9) "key:__rand_int__"
10) "a122"
192.168.229.60:6379> keys *
 1) "name"
 2) "v1"
 3) "myset:__rand_int__"
 4) "mylist"
 5) "a12"
 6) "counter:__rand_int__"
 7) "a1"
 8) "a2"
 9) "key:__rand_int__"
10) "a122"
192.168.229.60:6379> del v1
(integer) 1
192.168.229.60:6379> exists v1
(integer) 0
192.168.229.60:6379> del a1 a2 a12 a122
(integer) 4
192.168.229.60:6379> keys *
1) "name"
2) "myset:__rand_int__"
3) "mylist"
4) "counter:__rand_int__"
5) "key:__rand_int__"

  

6.6 type 命令

可以獲取key對應的 value 值類型

192.168.229.60:6379> keys *
1) "name"
2) "myset:__rand_int__"
3) "mylist"
4) "counter:__rand_int__"
5) "key:__rand_int__"
192.168.229.60:6379> type name
string

6.7 rename 命令

是對已有key進行重命名。 (覆蓋)

命令格式: rename 源key 目標key

使用rename命令進行重命名時,無論目標key是否存在都進行重命名,且源key的值會覆蓋目標key的值。

在實際使用過程中,建議先用 exists命令查看目標key是否存在,然后再決定是否執行rename命令,以避免覆蓋重要數據。

192.168.229.60:6379> keys *
1) "name"
2) "myset:__rand_int__"
3) "mylist"
4) "counter:__rand_int__"
5) "a1"
6) "a2"
7) "key:__rand_int__"
192.168.229.60:6379> get a1
"1"
192.168.229.60:6379> get a2
"2"
192.168.229.60:6379> rename a1 a2
OK
192.168.229.60:6379> keys *
1) "name"
2) "myset:__rand_int__"
3) "mylist"
4) "counter:__rand_int__"
5) "a2"
6) "key:__rand_int__"
192.168.229.60:6379> get a2
"1"

6.8 renamenx 命令

作用是對已有key進行重命名,並檢測新名是否存在

如果目標key存在則不進行重命名。 (不覆蓋)

命令格式: renamenx 源key 目標key  

 

6.9 dbsize命令

作用是查看當前數據庫中key的數目。

 

6.10  使用config set requirepass 命令設置密碼

6.11 使用config get requirepass 命令查看密碼

(一旦設置密碼,必須先驗證通過密碼,否則所有操作不可用)

6.12  刪除密碼  

7、Redis 多數據庫常用命令

Redis支持多數據庫,Redis 默認情況下包含16個數據庫,數據庫名稱是用數字0-15 來依次命名的

多數據庫相互獨立,互不干擾

7.1 多數據庫間切換

命令格式: select 序號

使用 redis-cli 連接Redis數據庫后,默認使用的是序號為 0 的數據庫。

192.168.229.60:6379> select 0
OK
192.168.229.60:6379> keys *
1) "a3"
2) "key:__rand_int__"
3) "myset:__rand_int__"
4) "mylist"
5) "name"
6) "b2"
7) "counter:__rand_int__"
192.168.229.60:6379> select 6
OK
192.168.229.60:6379[6]> keys *
(empty list or set)

7.2 多數據庫間移動數據

格式: move 鍵值 序號

192.168.229.60:6379> keys *
1) "a3"
2) "key:__rand_int__"
3) "myset:__rand_int__"
4) "mylist"
5) "name"
6) "b2"
7) "counter:__rand_int__"
192.168.229.60:6379> get a3
"1"
192.168.229.60:6379> move a3 6
(integer) 1
192.168.229.60:6379> select 6
OK
192.168.229.60:6379[6]> keys *
1) "a3"
192.168.229.60:6379[6]> get a3
"1"
192.168.229.60:6379[6]> select 0
OK
192.168.229.60:6379> keys *
1) "key:__rand_int__"
2) "myset:__rand_int__"
3) "mylist"
4) "name"
5) "b2"
6) "counter:__rand_int__"

  

7.3 清除數據庫內數據

FLUSHDB :清空當前數據庫數據

FLUSHALL :清空所有數據庫的數據,慎用!!!   

192.168.229.60:6379[6]> keys *
1) "a3"
2) "aa2"
3) "aa1"
192.168.229.60:6379[6]> flushdb 
OK
192.168.229.60:6379[6]> keys *
(empty list or set)
192.168.229.60:6379[6]> flushall
OK
192.168.229.60:6379[6]> select 0
OK
192.168.229.60:6379> keys *
(empty list or set)

  

五、Redis 高可用

在web服務器中,高可用是指服務器可以正常訪問的時間,衡量的標准是在多長時間內可以提供正常服務(99.9%、99.99%、99.999%等等)。

但是在Redis語境中,高可用的含義似乎要寬泛一些,除了保證提供正常服務(如主從分離、快速容災技術),還需要考慮數據容量的擴展,數據安全不會丟失等。

 

在Redis中,實現高可用的技術主要包括持久化、主從復制、哨兵和集群,作用如下:

持久化 :持久化是最簡單的高可用方法(有時甚至不被歸為高可用的手段),主要作用是數據備份,即將數據存儲在硬盤,保證數據不會因進程退出而丟失。

主從復制 :主從復制是高可用Redis的基礎,哨兵和集群都是在主從復制基礎上實現高可用的。主從復制主要實現了數據的多機備份,以及對於讀操作的負載均衡和簡單的故障恢復。

缺陷:故障恢復無法自動化;寫操作無法負載均衡;存儲能力受到單機的限制。

哨兵 :在主從復制的基礎上,哨兵實現了自動化的故障恢復。缺陷 :寫操作無法負載均衡;存儲能力受到單機的限制。

集群 : 通過集群, Redis解決了寫操作無法負載均衡,以及存儲能力受到單機限制的問題,實現了較為完善 的高可用方案。

六、Redis持久化

1、持久化的功能 :

Redis是內存數據庫,數據都是存儲在內存中,為了避免服務器斷電等原因導致Redis進程異常退出后數據的永久丟失,需要定期將Redis中的數據以某種形式( 數據或命令)從內存保存到硬盤;當下次Redis重啟時,利用持久化文件實現數據恢復。

除此之外,為了進行災難備份,可以將持久化文件拷貝到一個遠程位置(NFS)

2、Redis提供兩種方式持久化:

• RDB持久化 : 原理是將Reids在內存中的數據庫記錄定時保存到磁盤上

• AOF持久化(append only file) : 原理是將Reids的操作日志以追加的方式寫入文件,類似於MySQL的binlog

由於AOF持久化的實時性更好,即當進程意外退出時丟失的數據更少,因此AOF是目前主流的持久化方式,不過RDB持久化仍然有其用武之地

七、RDB持久化

RDB持久化是指在指定的時間間隔內將內存中當前進程中的數據生成快照保存到硬盤(因此也稱作快照持久化),用二進制壓縮存儲,保存的文件后綴是rdb;當Redis重新啟動時,可以讀取快照文件恢復數據

1、觸發條件

RDB持久化的觸發分為手動觸發和自動觸發兩種

1.1 手動觸發

• save命令和bgsave命令都可以生成RDB文件

• save命令會阻塞Redis服務器進程,直到RDB文件創建完畢為止,在Redis服務器阻塞期間,服務器不能處理任何命令請求

•而bgsave命令會創建一個子進程,由子進程來負責創建RDB文件,父進程 (即Redis主進程) 則繼續處理請求

• bgsave命令執行過程中,只有fork 子進程時會阻塞服務器,而對於save命令,整個過程都會阻塞服務器,因此save已基本被廢棄,線上環境要杜絕save的使用!!!

往往生產環境 bgsave 依然不允許輕易使用

1.2 自動觸發

• 在自動觸發RDB持久化時,Redis也 會選擇bgsave而不是save來進行持久化

save m n

• 自動觸發最常見的情況是在配置文件中通過save m n,指定當m秒內發生n次變化時,會觸發bgsave

vim /etc/redis/6379.conf
--219行--以下三個save條件滿足任意一個時,都會引起bgsave的調用
save 900 1 :當時間到900秒時,如果redis數據發生了至少1次變化,則執行bgsave
save 300 10 :當時間到300秒時, 如果redis數據發生了至少10次變化,則執行bgsave
save 60 10000 :當時間到60秒時,如果redis數據發生了至少10000次變化, 則執行bgsave
--242行--是否開啟RDB文件壓縮
rdbcompression yes
--254行--指定RDB文件名
dbfilename dump.rdb
--264行--指定RDB文件和AOF文件所在目錄
dir /var/lib/redis/6379

1.3 其他自動觸發機制

除了 save m n 以外,還有一些其他情況會觸發bgsave:

在主從復制場景下,如果從節點執行全量復制操作,則主節點會執行bgsave命令,並將rdb文件發送給從節點

執行shutdown命令時,自動執行rdb持久化

2、執行流程

(1) Redis父進程首先判斷 :當前是否在執行save,或bgsave/bgrewriteaof的子進程,如果在執行,則bgsave命令直接返回bgsave/bgrewriteaof 的子進程不能同時執行,主要是基於性能方面的考慮:兩個並發的子進程同時執行大量的磁盤寫操作,可能引起嚴重的性能問題

(2) 父進程執行fork操作創建子進程,這個過程中父進程是阻塞的,Redis不能執行來自客戶端的任何命令

(3) 父進程fork后,bgsave 命令返回”Background saving started" 信息並不再阻塞父進程,並可以響應其他命令

(4) 子進程創建RDB文件,根據父進程內存快照生成臨時快照文件,完成后對原有文件進行原子替換

(5) 子進程發送信號給父進程表示完成,父進程更新統計信息

3、啟動時加載

• RDB文件的載入工作是在服務器啟動時自動執行的,並沒有專門的命令。但是由於A0F的優先級更高,因此當AOF開啟時,Redis會優先載入AOF文件來恢復數據;只有當A0F關閉時,才會在Redis服務器啟動時檢測RDB文件,並自動載入。服務器載入RDB文件期間處於阻塞狀態,直到載入完成為止

• Redis載入RDB文件時,會對RDB文件進行校驗,如果文件損壞,則日志中會打印錯誤,Redis啟動失敗

八.AOF持久化

• RDB持久化是將進程數據寫入文件,而AOF持久化,則是將Redis執行的每次寫、刪除命令記錄到單獨的日志文件中,查詢操作不會記錄; 當Redis重啟時再次執行AOF文件中的命令來恢復數據。

• 與RDB相比,AOF的實時性更好,因此已成為主流的持久化方案

1、開啟AOF

Redis服務器默認開啟RDB,關閉AOF: 要開啟AOF,需要在配置文件中配置:

vim /etc/redis/6379.conf
- 700行--修改, 開啟AOF
appendonly yes
--704行--指定A0F文件名稱
appendfilename "appendonly.aof"
--796行--是否忽略最后一條可能存在問題的指令
aof-load-truncated yes

/etc/init.d/redis_6379 restart

2、執行流程

由於需要記錄Redis的每條寫命令,因此A0F不需要觸發,AOF的執行流程如下:

2.1 AOF的執行流程包括:

• 命令追加(append): 將Redis的寫命令追加到緩沖區aof_ buf;

• 文件寫入(write)和文件同步(sync):根據不同的同步策略將aof_buf中的內容同步到硬盤;

• 文件重寫(rewrite): 定期重寫AOF文件,達到壓縮的目的。

① 命令追加 (append)

Redis先將寫命令追加到緩沖區,而不是直接寫入文件,主要是為了避免每次有寫命令都直接寫入硬盤,導致硬盤IO成為Redis負載的瓶頸。

命令追加的格式是Redis命令請求的協議格式,它是一種純文本格式,具有兼容性好、可讀性強、容易處理、操作簡單避免二次開銷等優點。在A0F文件中,除了用於指定數據庫的select命令 (如select0為選中0號數據庫) 是由Redis添加的,其他都是客戶端發送來的寫命令

② 文件寫入(write) 和文件同步 (sync)

Redis 提供了多種AOF緩存區的同步文件策略,策略涉及到操作系統的write函數和fsync函數,說明如下:

為了提高文件寫入效率,在現代操作系統中,當用戶調用write函數將數據寫入文件時,操作系統通常會將數據暫存到一個內存緩沖區里,當緩沖區被填滿或超過了指定時限后,才真正將緩沖區的數據寫入到硬盤里。這樣的操作雖然提高了效率,但也帶來了安全問題:如果計算機停機,內存緩沖區中的數據會丟失;因此系統同時提供了fsync、fdatasync等同步函數,可以強制操作系統立刻將緩沖區中的數據寫入到硬盤里,從而確保數據的安全性

AOF緩存區的同步文件策略存在三種同步方式,它們分別是:

vim /etc/redis/6379.conf
---729---
● appendfsync always:
命令寫入aof_buf后立即調用系統fsync操作同步到AOF文件,fsync完成后線程返回。這種情況下,每次有寫命令都要同步到AOF文件,硬盤IO成為性能瓶頸,Redis只能支持大約幾百TPS寫入,嚴重降低了Redis的性能;即便是使用固態硬盤(SSD),每秒大約也只能處理幾萬個命令,而且會大大降低SSD的壽命。

● appendfsync no:
命令寫入aof_buf后調用系統write操作,不對AOF文件做fsync同步;同步由操作系統負責,通常同步周期為30秒。這種情況下,文件同步的時間不可控,且緩沖區中堆積的數據會很多,數據安全性無法保證。

● appendfsynceverysec:
命令寫入aof_buf后調用系統write操作,write完成后線程返回; fsync同步文件操作由專門的線程每秒調用一次。everysec是前述兩種策略的折中,是性能和數據安全性的平衡,因此是Redis的默認配置,也是我們推薦的配置。

③ 文件重寫 (rewrite)

• 隨着時間流逝,Redis服務器執行的寫命令越來越多,AOF文件也會越來越大:過大的AOF文件不僅會影響服務器的正常運行,也會導致數據恢復需要的時間過長。

文件重寫是指定期重寫AOF文件,減小AOF文件的體積。需要注意的是,AOF重寫是把Redis進程內的數據轉化為寫命令,同步到新的AOF文件;不會對舊的AOF文件進行任何讀取、寫入操作!

• 關於文件重寫需要注意的另一點是:對於AOF持久化來說,文件重寫雖然是強烈推薦的,但並不是必須的;即使沒有文件重寫,數據也可以被持久化並在Redis啟動的時候導入:因此在一些實現中,會關閉自動的文件重寫,然后通過定時任務在每天的某一時刻定時執行

文件重寫之所以能夠壓縮AOF文件,原因在於:

• 過期的數據不再寫入文件
• 無效的命令不再寫入文件:如有些數據被重復設值(set mykey v1, set mykey v2)、有些數據被刪除了(sadd myset v1, del myset) 等。
• 多條命令可以合並為一個:如sadd myset v1, sadd myset v2, sadd myset v3可以合並為sadd myset v1 v2 v3。

通過上述內容可以看出,由於重寫后AOF執行的命令減少了,文件重寫既可以減少文件占用的空間,也可以加快恢復速度

手動觸發:直接調用bgrewriteaof命令,該命令的執行與bgsave有些類似:都是fork子進程進行具體的工作,且都只有在fork時阻塞

自動觸發:通過設置auto-aof - rewrite-min-size選項和auto- aof - rewrite- percentage選項來自動執行BGREWRITEAOF

只有當auto-aof- rewrite- -min-size和auto-aof -rewrite-percentage兩個選項同時滿足時,才會自動觸發AOF重寫,即bgrewriteaof操作

vim /etc/redis/ 6379. conf
----729----
● auto-aof- rewrite-percentage 100
:當前AOF文件大小(即aof_current_size)是上次日志重寫時AOF文件大小(aof_base_size)兩倍時,發生BGREWRITEAOF操作
● auto-aof - rewrite-min-size 64mb
:當前A0F文件執行BGREWRITEAOF命令的最小值,避免剛開始啟動Reids時由於文件尺寸較小導致頻繁的BGREWRITEAOF

關於文件重寫的流程,有兩點需要特別注意:

♢ 重寫由父進程fork子進程進行;
♢ 重寫期間Redis執行的寫命令,需要追加到新的AOF文件中,為此Redis引入了aof_ rewrite_buf緩存

文件重寫的流程如下:

(1) Redis父進程首先判斷當前是否存在正在執行bgsave/bgrewriteaof的子進程,如果存在則bgrewriteaof命令直接返回,如果存在bgsave命令則等bgsave執行完成后再執行

(2) 父進程執行fork操作創建子進程,這個過程中父進程是阻塞的

(3.1) 父進程fork后,bgrewriteaof 命令返回"Background append only file rewrite started" 信息並不再阻塞父進程,並可以響應其他命令。Redis的所有寫命令依然寫入AOF緩沖區,並根據appendfsync策略同步到硬盤,保證原有A0F機制的正確

(3.2) 由於fork操作使用寫時復制技術,子進程只能共享fork操作時的內存數據。由於父進程依然在響應命令,因此Redis使用AOF重寫緩沖區(aof_ rewrite_buf) 保存這部分數據,防止新AOF文件生成期間丟失這部分數據。也就是說,bgrewriteaof執行 期間,Redis的寫 命令同時追加到aof_ buf和aof_ rewirte_ buf兩個緩沖區

(4) 子進程根據內存快照,按照命令合並規則寫入到新的AOF文件

(5.1) 子進程寫完新的AOF文件后,向父進程發信號,父進程更新統計信息,具體可以通過info persistence查看

(5.2) 父進程把AOF重寫緩沖區的數據寫入到新的AOF文件,這樣就保證了新AOF文件所保存的數據庫狀態和服務器當前狀態一致

(5.3) 使用新的AOF文件替換老文件,完成AOF重寫

3.啟動時加載

• 當AOF開啟時,Redis啟 動時會優先載入AOF文件來恢復數據;只有當AOF關閉時,才會載入RDB文件恢復數據

• 當AOF開啟,但AOF文件不存在時,即使RDB文件存在也不會加載

• Redis載入AOF文件時,會對AOF文件進行校驗,如果文件損壞,則日志中會打印錯誤,Redis啟動失敗。但如果是AOF文件結尾不完整 (機器突然宕機等容易導致文件尾部不完整),且aof-load- truncated參數開啟,則日志中會輸出警告,Redis 忽略掉AOF文件的尾部,啟動成功

• aof-load-truncated參數默認是開啟的

九.RDB和AOF的優缺點

1.RDB持久化

優點:
•vRDB文件緊湊,體積小,網絡傳輸快,適合全量復制;恢復速度比AOF快很多。當然,與AOF相比, RDB最 重要的優點之一是對性能的影響相對較小

缺點:
• RDB文件的致命缺點在於其數據快照的持久化方式決定了必然做不到實時持久化,而在數據越來越重要的今天,數據的大量丟失很多時候是無法接受的,因此AOF持久化成為主流。此外,RDB文件需要滿足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)

• 對於RDB持久化,一方面是bgsave在進行fork操作時Redis主進程會阻塞,另一方面,子進程向硬盤寫數據也會帶來IO壓力

2.AOF持久化

• 與RDB持久化相對應,AOF的優點在於支持秒級持久化、兼容性好,缺點是文件大、恢復速度慢、對性能影響大

• 對於AOF持久化,向硬盤寫數據的頻率大大提高(everysec策略下為秒級),IO壓力更大,甚至可能造成AOF追加阻塞問題

• AOF文件的重寫與RDB的bgsave類似,會有fork時的阻塞和子進程的I0壓力問題。相對來說,由於AOF向硬盤中寫數據的頻率更高,因此對Redis主進程性能的影響會更大

十.Redis性能管理

1.查看Redis內存使用

192.168.229.60: 7001> info memory

2.內存碎片率

操作系統分配的內存值used_ memory_ rss除以Redis使用的內存值used_ memory計算得出內存碎片是由

操作系統低效的分配/回收物理內存導致的 (不連續的物理內存分配)

跟蹤內存碎片率對理解Redis實例的資源性能是非常重要的:
• 內存碎片率稍大於1是合理的,這個值表示內存碎片率比較低
• 內存碎片率超過1.5,說明Redis消耗了實際需要物理內存的150號, 其中50號是內存碎片率。需要在redis-cli工具.上輸入shutdown save命令,並重啟Redis 服務器
• 內存碎片率低於1的,說明Redis內存分配超出了物理內存,操作系統正在進行內存交換。需要增加可用物理內存或減少Redis內存占用

3.內存使用率

redis實例的內存使用率超過可用最大內存,操作系統將開始進行內存與swap空間交換

避免內存交換發生的方法:
• 針對緩存數據大小選擇安裝Redis 實例
• 盡可能的使用Hash數據結構存儲
• 設置key的過期時間

4.內回收key

• 保證合理分配redis有限的內存資源

• 當達到設置的最大閥值時,需選擇一種key的回收策略,默認情況下回收策略是禁止刪除

配置文件中修改maxmemory- policy屬性值:

vim /etc/redis/6379.conf
--598--
maxmemory-policy noenviction
●volatile-lru :使用LRU算法從已設置過期時間的數據集合中淘汰數據
●volatile-ttl :從已設置過期時間的數據集合中挑選即將過期的數據淘汰
●volatile-random :從已設置過期時間的數據集合中隨機挑選數據淘汰
●allkeys-lru :使用LRU算法從所有數據集合中淘汰數據
●allkeys-random :從數據集合中任意選擇數據淘汰
●noenviction :禁止淘汰數據

總結

1.redis 是一種非關數據庫(內存/緩存)

redis相比於其他非關數據庫優勢的地方主要在於:

①數據類型豐富

②持久化(可以將內存種的數據保存在磁盤中)形式為:RDB與AOF

2.redis 集群模式:哨兵、主從、cluster (集群)

redis的集群模式,同時也可以理解為是redis的高可用模式

主從: 提供了備份冗余,缺點:無法針對故障進行自動修復,寫操作無法負載均衡

哨兵: 以主從為基礎提供了故障自動修復的功能,寫操作無法負載均衡

集群: 基於主從基礎,解決了故障自動修復、寫操作負載均衡的問題,同時對於資源需求相較於前兩種集群得到了一定的改善

3.高可用中的持久化

RDB和AOF

(1)持久化方式:

① RDB:周期性的快照

② AOF :接近實時的持久化(以everysec方式)

(2) redis 啟用的優先級
AOF>RDB,同時僅當AOF功能關閉的情況下,redis才會在重新啟動時使用RDB的方式進行恢復

(3)RDB和AOF中持久化模式

①RDB:

由redis主進程(周期性) fork 派生出子進程對redis內存中的數據進行持久化,生成到. rdb文件中
②AOF:

根據持久化策略(alawys、 no、 everysec (默認) ),先將redis中的語句保存在緩沖區中,再從緩沖

區同步到.aof文件中

4.redis的恢復策略/優勢

redis與其他常用非關數據庫類似,都是將數據保存在內存中;

而保存在內存中時,當redis 重啟,內存數據丟失,但redis 通過RDB或AOF的持久化功能可以在redis 進行重啟之后,優先讀取AOF文件,基於AOF文件進行數據恢復這種方式來“持久化保存"數據

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM