2.NoSQL之Redis配置與優化

一、關係型數據庫與非關係數據庫

關係型數據庫:

關係型數據庫是一個結構化的數據庫,創建在關係模型(二維表格模型)基礎上,一般面向於記錄。
sQL語句(標準數據查詢語言)就是一種基於關係型數據庫的語言,用於執行對關係型數據庫中數據的檢索和操作主流的關係型數據庫包括 oracle、MySQ、sQI server、Microsoft Access、DB2、PostgresgI等。
以上數據庫在使用的時候必須先建庫建表設計表結構,然後存儲數據的時候按表結構去存,如果數據與表結構不匹配就會存儲失敗。

非關係型數據庫

NoSQL (NosgI = Not only sQL ),意思是”不僅僅是 sQL”,是非關係型數據庫的總稱。除了主流的關係型數據庫外的數據庫,都認為是非關係型。
不需要預先建庫建表定義數據存儲表結構,每條記錄可以有不同的數據類型和字段個數(比如微信群聊里的文字、圖片、視頻、音樂等)。主流的 NosQT數據庫有 Redis、MongBD、Hbase、Memcached、Elasticsearch、TSDB等。

NoSQL(非關係型數據庫)和SQL(關係型數據庫)的主要區別有如下區別:

1、數據存儲方式不同

  • 關係模型的數據結構使用簡單易懂的二維數據表,因此存儲在表的行和列中。他們之間很容易關聯協作存儲,提取數據很方便。

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

在每個二維表格中

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

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

  • NoSQL數據庫則與其相反,它是大塊的組合在一起。通常存儲在數據集中,就像文檔、鍵值對或者圖結構。

2、擴展方式不同

  1. 關係型數據庫數據存儲在關係表中,操作的性能瓶頸可能涉及到多個表,需要通過提升計算機性能來克服,因此更多是採用縱向擴展(提升服務器的性能)
  2. NoSQL數據庫是橫向擴展的,它的存儲天然就是分佈式的,可以通過給資源池添加更多的普通數據庫服務器來分擔負載

3、對事務性的支持不同

關係型數據庫遵循ACID規則(原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability))。

NoSQL數據庫遵循BASE原則(基本可用(Basically Availble)、軟/柔性事務(Soft-state)、最終一致性(Eventual Consistency))。

由於關係型數據庫的數據強一致性,所以對事務的支持很好。關係型數據庫支持對事務原子性細粒度控制,並且易於回滾事務。

NoSQL數據庫是在CAP (一致性、可用性、分區容忍度)中任選兩項,因為基於節點的分佈式系統中,不可能同時全部滿足,所以對事務的支持不是很好。

非關係型數據庫產生背景

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

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

(2) Huge storage——對海量數據高效存儲與訪問需求
(3) High scalability && High Availability—對數據庫高可擴展性與高可用性需求
關係型數據庫和非關係型數據庫都有各自的特點與應用場景,兩者的緊密結合將會給Web2.06的數據庫發展帶來新的思路。讓關係型數據庫關注在關係上和對數據的一致性保障,非關係型數據庫關注在存儲和高效率上。例如,在讀寫分離的uysgL數據庫環境中,可以把經常訪問的數據存儲在非關係型數據庫中,提升訪問速度。
總結:
關係型數據庫:
實例–>數據庫–>表(table)–>記錄行(row)、數據字段(column)
非關係型數據庫:
實例–>數據庫–>集合(collection)–>鍵值對(key-value)非關係型數據庫不需要手動建數據庫和集合(表)。

二、Redis

Redis簡介

  • Redis 是一個開源的、使用 C 語言編寫的 NoSQL 數據庫。

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

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

  • 若在服務器上只運行一個Redis進程,當多個客戶端同時訪問時,服務器的處理能力是會有一定程度的下降.若在同一台服務器上開啟多個Redis進程,Redis在提高並發處理能力的同時會給服務器的CPU造成很大壓力.所以在實際生產環境中,需要根據實際的需求來決定開啟多少個Redis進程。

Redis的優點

  1. 具有極高的數據讀寫速度:數據讀取的速度最高可達到110000次/s,數據寫入速度最高可達到81000次/s
  2. 持豐富的數據類型:支持key-value(鍵值對) 、 String、Lists、Hashes、Sets及Ordered Sets等數據類型操作
  3. 支持數據的持久化:可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用
  4. 原子性:Redis所有操作都是原子性的
  5. 支持數據備份:即master-slave模式的數據備份

Memcache和Redis的區別

Memcache Redis
類型 Key-value數據庫 Key-value數據庫
過期策略 支持 支持
數據類型 單一數據類型 五大數據類型
持久化 不支持 支持
主從複製 不支持 支持
虛擬內存 不支持 支持

Redis常見的數據結構

常見的5種

  • String:字符串,最基礎的數據類型

  • List:列表

  • Hash:哈希對象

  • Set:集合

  • Sorted Set:有序集合, Set 的基礎上加了個分值

Redis作為基於內存運行的數據庫,是一個高性能的緩存,一般應用在session緩存、隊列、排行榜、計數器、最近最熱文章、最近最熱評論、發佈訂閱等。

Redis適用於數據實時性要求高、數據存儲有過期和淘汰特徵的、不需要持久化或者需要保證一致性、邏輯簡單的場景。

Redis為什麼讀寫速度這麼快

  1. Redis 是一款純內存結構,避免了磁盤I/O等耗時操作
  2. Redis 命令處理的核心模塊為單線程,減少了鎖競爭,以及頻繁創建線程和銷毀線程的代價,減少了線程上下文切換的消耗
  3. 採用了 I/O 多路復用機制,大大提升了並發效率

注:在Redis 6.0 中新增加的多線程也只是爭對處理網絡請求過程採用了多線程,二數據的讀寫命令,仍然是單線程處理。

Redis的請求過程

dbab66e82d6c6c2e6ed69d213008dd4

三、Redis安裝部署

1.編譯安裝redis

#準備工作
systemctl stop firewalld
setenforce 0
#安裝依賴包
yum install -y gcc-c++ make
cd /opt/
#把解壓包放在opt下並解壓
tar zxvf redis-5.0.7.tar.gz
cd /opt/redis-5.0.7/
make
#編譯安裝指定安裝目錄
make PREFIX=/usr/local/redis install
#由於Redis源碼包中直接提供了Makefile文件,所以在解壓完軟件包後,不用先執行./configure進行配置,可直接執行make與make install命令進行安裝

2.執行軟件包自帶的install_server.sh腳本文件設置redis服務相關配置

cd /opt/redis-5.0.7/utils
./install_server.sh
#慢慢回車
Selected config:
Port #第一個設置默認偵聽端口6379
Config file #第二個設置配置文件路徑/etc/redis/6379.conf
Log file#第三個設置日誌文件路徑/var/log/redis_6379.log
Data dir#第四個設置數據文件目錄/var/lib/redis/6379(持久化文件在這裡)
Executable#第五個設置Redis執行命令的路徑手動設置一下/usr/local/redis/bin/redis-server
Cli Executable#客戶端命令工具/usr/local/bin/redis-cli

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

#做個軟連接
ln -s /usr/local/redis/bin/* /usr/local/bin/
#當install_server.sh 腳本運行完畢,Redis服務就已經啟動,默認偵聽端口為6379
netstat -natp | grep redis

#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			#狀態

4.修改配置/etc/redis/6379.conf

vim /etc/redis/6379.conf

#第70行;監聽的主機地址
bind 127.0.0.1 192.168.239.40
#93行;Redis默認的監聽端口
port 6379									
#137行;啟用守護進程
daemonize yes							
#159行;指定 PID 文件
pidfile /var/run/redis_6379.pid				
#167行;日誌級別
loglevel notice								
#172行;指定日誌文件
logfile /var/log/redis_6379.log	

/etc/init.d/redis_6379 restart
netstat -natp | grep redis

四、Redis命令工具

redis-server		用於啟動 Redis 的工具
redis-benchmark		用於檢測 Redis 在本機的運行效率
redis-check-aof		修復 AOF 持久化文件
redis-check-rdb		修復 RDB 持久化文件
redis-cli	 		Redis命令行工具

1.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.239.40 -p 6379
#此時無密碼,不需要-a直接登陸

2.redis-benchmark測試工具

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

基本的測試語法:redis-benchmark [選項] [選項值]
選項 參數
-h 指定服務器主機名
-p 指定服務器端口
-s 指定服務器socket
-c 指定並發連接數
-n 指定請求數
-d 以位元組的形式指定 SET/GET值的數據大小
-k 1=keep alive 0=reconnect
-r SET/GET/INCR 使用隨機 key,SADD使用隨機值
-p 通過管道傳輸請求
-q 強制退出redis。僅顯示query/sec的值
-csv 以CSV格式輸出
-l 生成循環,永久執行測試
-t 僅運行以逗號分隔的測試命令列表
-i Idle 模式。僅打開N個idle連接並等待
  • 向IP地址為192.168.239.40、端口為6379的Redis服務器發送100個並發連接和100000個請求測試性能
redis-benchmark -h 192.168.239.40 -p 6379 -c 100 -n 100000
  • 測試存取大小為100位元組的數據包的性能
redis-benchmark -h 192.168.239.40 -p 6379 -q -d 100
  • 測試本機上Redis服務在進行set與lpush操作時的性能
redis-benchmark -t set,lpush -n 100000 -q

3.Redis數據庫常用命令

1、set/get存放/獲取數據

set		存放數據,命令格式為 set key value   #set 鍵  鍵所對應的值
get		獲取數據,命令格式為 get key         #get 鍵
#例子:
redis-cli -p 6379
192.168.239.40:6379> set name Davin
OK
192.168.239.40:6379> get name
"Davin"

2、 keys 取值

keys 命令可以取符合規則的鍵值列表,通常情況可以結合*、?等選項來使用
127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> set k2 2
OK
127.0.0.1:6379> set k3 3
OK
127.0.0.1:6379> set k4 4
OK
127.0.0.1:6379> set k5 5
OK
127.0.0.1:6379> set v1 6
OK
127.0.0.1:6379> set v22 7
OK
keys *   #查看當前Redis數據庫中有多少個鍵 
keys k*  #查看以k為開頭的鍵(0個或者多個任意字符)
keys k?  #查看以k為開頭(1個任意字符)
keys v?? #查看以v開頭且後面2個任意字符

3、 exists 判斷值是否存在

127.0.0.1:6379> EXISTS name
(integer) 1                    #1表示teacher鍵存在
127.0.0.1:6379> EXISTS ww
(integer) 0                    #0表示teacher不存在

4、 del刪除當前數據庫指定key

del  命令可以刪除當前數據庫指定key
127.0.0.1:6379> del k1 k2
(integer) 2
127.0.0.1:6379> KEYS k?
1) "k3"
2) "k5"
3) "k4"
127.0.0.1:6379> EXISTS k1
(integer) 0
127.0.0.1:6379> EXISTS k2
(integer) 0

5、 type獲取值的類型

type  命令可以獲取 key 對應 value 值類型
#例
1、
192.168.239.40:6379> TYPE name
string
2、
192.168.239.40:6379> hset myhash field1 "zhang"
(integer) 1
192.168.239.40:6379> TYPE myhash
hash

6、 rename重命名

rename:命令是對已有key進行重命名。(覆蓋)
命令格式:rename 源key 目標key

使用rename命令進行重命名時,無論目標key是否存在都進行重命名,且源key的值會覆蓋目標key的值。在實際使用過程中,建議先用 exists 命令查看目標 key 是否存在,然後再決定是否執行 rename 命令,以避免覆蓋重要數據。

192.168.239.40:6379> get v22
"7"
192.168.239.40:6379> RENAME v22 v2 #直接改名,不存在v2
OK
192.168.239.40:6379> KEYS *
 1) "myhash"
 2) "k5"
 3) "v1"
 4) "k3"
 5) "k4"
 6) "counter:__rand_int__"
 7) "myset:__rand_int__"
 8) "v2"
 9) "key:__rand_int__"
10) "mylist"
11) "name"
192.168.239.40:6379> get v22  #返回空值
(nil)
192.168.239.40:6379> get v2  #
"7"
192.168.239.40:6379> get v1
"6"
192.168.239.40:6379> RENAME v2 v1
OK
192.168.239.40:6379> KEYS *
 1) "myhash"
 2) "k5"
 3) "v1"
 4) "k3"
 5) "k4"
 6) "counter:__rand_int__"
 7) "myset:__rand_int__"
 8) "key:__rand_int__"
 9) "mylist"
10) "name"
192.168.239.40:6379> get v1
"7"

7、 renamenx重命名(不覆蓋)

renamenx 命令的作用是對已有 key 進行重命名,並檢測新名是否存在,如果目標 key 存在則不進行重命名。(不覆蓋)
命令格式:renamenx 源key 目標key
192.168.239.40:6379> get v1
"7"
192.168.239.40:6379> get k3
"3"
192.168.239.40:6379> RENAMENX v1 k3
(integer) 0          #renamenx重命名,如果新名存在,則不執行重命名
192.168.239.40:6379> get k3
"3"
192.168.239.40:6379> get v1
"7"

8、 dbsize 查看庫中key的數量

dbsize 命令的作用是查看當前數據庫中 key 的數目
192.168.239.40:6379> DBSIZE
(integer) 10

9、 設置密碼

使用config set requirepass password命令設置密碼
使用config get requirepass命令查看密碼(一旦設置密碼,必須先驗證通過密碼,否則所有操作不可用)
#例
192.168.239.40:6379> config set requirepass 123456
OK
192.168.239.40:6379> get name
(error) NOAUTH Authentication required.
192.168.239.40:6379> auth 123456
OK
192.168.239.40:6379> get name
"Davin"
192.168.239.40:6379> quit
[root@localhost ~]# redis-cli -h 192.168.239.40 -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.239.40:6379> KEYS *
 1) "myhash"
 2) "k5"
 3) "v1"
 4) "k3"
 5) "k4"
 6) "counter:__rand_int__"
 7) "myset:__rand_int__"
 8) "key:__rand_int__"
 9) "mylist"
10) "name"
192.168.239.40:6379> CONFIG GET requirepass  #查看當前密碼
1) "requirepass"
2) "123456"

192.168.239.40:6379> config set requirepass ''#設置空密碼
OK
192.168.239.40:6379> CONFIG GET requirepass
1) "requirepass"
2) ""

4.Redis多數據庫常用命令

  • Redis支持多數據庫,Redis默認情況下包含16個數據庫,數據庫名稱時用數字0-15來依次命名的。多數據庫相互獨立,互不干擾。

(1)多數據庫間切換

命令格式:select 序號
使用 redis-cli 連接 Redis 數據庫後,默認使用的是序號為 0 的數據庫。
192.168.239.40:6379> select 10
OK
192.168.239.40:6379[10]> KEYS *
(empty list or set)
192.168.239.40:6379[10]> SELECT 15
OK
192.168.239.40:6379[15]> SELECT 0
OK
192.168.239.40:6379> KEYS *
 1) "myhash"
 2) "k5"
 3) "v1"
 4) "k3"
 5) "k4"
 6) "counter:__rand_int__"
 7) "myset:__rand_int__"
 8) "key:__rand_int__"
 9) "mylist"
10) "name"

(2)多數據庫間移動數據

格式:move 鍵值 序號

192.168.239.40:6379> move v1 10   #從0移動到10
(integer) 1
192.168.239.40:6379> SELECT 10    #切換到10
OK
192.168.239.40:6379[10]> KEYS *   #查看所有的鍵
1) "v1"
192.168.239.40:6379[10]> get v1   #查看v1鍵的值
"7"
192.168.239.40:6379[10]> SELECT 0 #切回0
OK
192.168.239.40:6379> get v1       #查看v1值 為空
(nil)

(3)清除數據庫內數據

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

192.168.239.40:6379> SELECT 10    
OK
192.168.239.40:6379[10]> KEYS *
1) "v1"
192.168.239.40:6379[10]> set v2 20
OK
192.168.239.40:6379[10]> set v3 30
OK
192.168.239.40:6379[10]> KEYS *
1) "v2"
2) "v3"
3) "v1"
192.168.239.40:6379[10]> FLUSHDB   #清空當前數據庫
OK
192.168.239.40:6379[10]> KEYS *
(empty list or set)
192.168.239.40:6379[10]> SELECT 0
OK
192.168.239.40:6379> KEYS *
1) "myhash"
2) "k5"
3) "k3"
4) "k4"
5) "counter:__rand_int__"
6) "myset:__rand_int__"
7) "key:__rand_int__"
8) "mylist"
9) "name"
192.168.239.40:6379> SELECT 10
OK
192.168.239.40:6379[10]> set v2 20
OK
192.168.239.40:6379[10]> set v3 30
OK
192.168.239.40:6379[10]> KEYS *
1) "v2"
2) "v3"
192.168.239.40:6379[10]> FLUSHALL  #清空所有的數據庫數據
OK
192.168.239.40:6379[10]> KEYS *
(empty list or set)
192.168.239.40:6379[10]> SELECT 0
OK
192.168.239.40:6379> KEYS *
(empty list or set)

五、Redis高可用

在web服務器中,高可用是指服務器可以正常訪問的時間,衡量的標準是在多長時間內可以提供正常服務(99.9%、99.99%、99.999%等等)。 但是在Redis語境中,高可用的含義似乎要寬泛一些,除了保證提供正常服務(如主從分離、快速容災技術),還需要考慮數據容量的擴展、數據安全不會丟失等。

在Redis中,實現高可用的技術主要包括持久化、主從複製、哨兵和集群,下面分別說明它們的作用,以及解決了什麼樣的問題 。

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

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

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

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

六、Redis持久化

持久化的功能:Redis是內存數據庫,數據都是存儲在內存中,為了避免服務器斷電等原因導致Redis進程異常退出後數據的永久丟失,需要定期將Redis中的數據以某種形式(數據或命令)從內存保存到硬盤;當下次Redis重啟時,利用持久化文件實現數據恢復。除此之外,為了進行災難備份,可以將持久化文件拷貝到一個遠程位置。

Redis 提供兩種方式進行持久化

  • RDB 持久化:原理是將 Reids在內存中的數據庫記錄定時保存到磁盤上。
  • AOF 持久化(append only file):原理是將 Reids 的操作日誌以追加的方式寫入文件,類似於MySQL的binlog。

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

1.RDB持久化

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

(1)觸發條件
RDB持久化的觸發分為手動觸發自動觸發兩種。

①手動觸發

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