1.1 什麼是redis
Redis是用C語言開發的一個開源的高性能 ( key-value ) ,它是一種NOSQL的數據庫。
redis是單進程單線程的內存數據庫, 所以說不存在線程安全問題
redis
支持10wQPS, 可以說性能非常優秀. 之所以單進程單線程性能還那麼好, 是因為底層採用了[IO多路複用(NIO思想)]
1.2 redis數據類型
redis提供了五種數據類型:
string(字符串)
list(鏈表)
set(集合)
zset(有序集合)
hash(哈希類型)
記得有一次面試, 面試官特意問了zset數據類型的用法, 平時開發中很少用到zset數據類型, 但是zset經典的應用就是排序, 後面會介紹到.
1.3 redis和memcached的對比
- 持久化:
- redis可以用來做緩存, 也可以做存儲, 支持aof和rdb兩種持久化方式
- memecached只能做緩存, 沒法持久化數據
- 數據結構:
- redis有豐富的數據類型: 五種常用的數據結構
- memcached一般就是字符串和對象
1.4 redis官網
- 官網地址: http://redis.io
- 中文官網地址: http://www.redis.cn
- 下載地址: http://download.redis.io/releases/
1.5 redis應用場景
- 內存數據庫(登陸信息, 購物車信息, 用戶瀏覽器記錄)
- 緩存服務器(商品數據, 廣告數據等等)(使用的最多)
- session共享
- 任務隊列(秒殺, 搶購, 12306等)
- 分佈式鎖的實現
- 支持發佈訂閱的消息模式
- 應用排行榜(有序集合)
- 網站訪問統計
- 數據過期處理
2. redis的多用模式
2.1 redis單機版
- 執行如下命令:
<code>#第一步 安裝C語言環境
yum install -y gcc-c++
yum install -y wget
# 第二步 下載源碼包
wget http://download.redis.io/releases/redis-5.0.6.tar.gz
tar xzvf redis-5.0.6.tar.gz
# 第三步 編譯安裝
cd redis-5.0.6
make install prefix=/usr/local/redis-5.0.6/<code>
- 啟動redis
<code>cd redis-5.0.6./redis-server/<code>
如果出現如下的界面, 說明啟動成功了:
- 守護進程啟動
redis-5.0.6下面有一個配置文件redis.conf, 修改如下:
<code>vim redis.conf
# 將`daemonize`由`no`改為`yes`
daemonize yes
# 默認綁定的是迴環地址,默認不能被其他機器訪問
# bind 127.0.0.1
# 是否開啟保護模式,由yes該為
noprotected-mode no/<code>
啟動
<code>./redis-server redis.conf/<code>
- 後端啟動關閉方式
<code>./redis-cli shutdown/<code>
- redis的其他主要命令
- redis-benchmark: 性能測試工具
- redis-check-aof: 檢查 AOF 日誌
- redis-check-dump: 檢查 RDB 日誌
- redis-cli: 啟動命令行客戶端
- redis-sentinel: redis的哨兵服務, 在redis2.8+以後加入的
- Redis-server: 啟動Redis服務
在redis的解壓目錄中, 有一個redis的配置文件
2.2 主從模式
1. 主從複製的作用
- 主從備份 防止主機宕機
- 讀寫分離,分擔 master 的任務
- 任務分離,如從服分別分擔備份工作與計算工作
2. redis主從複製的兩種方式
3. redis主從服務通信的原理
4. 配置redis主從模式
如果主服務器上需要增加redis的密碼, 增加如下配置:
<code>requirepass xxxxxx/<code>
redis的主, 從的安裝方式, 步驟都一樣, 從的配置文件從主拷貝過來, 然後在從節點的配置文佳中加上如下配置:
<code>slaveof localhost 6379
#如果主上有密碼, 則從服務器上的配置文件需要增加以下配置:
masterauth xxxxxx/<code>
2.3 哨兵模式
redis的哨兵模式是建立在主從模式上的, 因為主從模式如果主發生故障, 我們的從並無法直接提升為主共我們使用, 所以有了哨兵模式, 簡單的說, 哨兵模式就是增加的投票機制, 增加幾臺服務器作為哨兵節點, 即監控節點, 如果超過半數的哨兵即: 2 / n + 1的個數認為主掛了, 就會自動提升從服務器為主服務器, 並且, 哨兵是可以實時改動redis主從的配置文件的.而自己的配置文件是實時發生變化.
2.3.1 sentinel結構
2.3.2 sentinel功能
Sentinel實現如下功能:
(1)monitoring——redis實例是否正常運行。
(2)notification——通知application錯誤信息。
(3)failover——某個master死掉,選擇一個slave升級為master,修改其他slave的slaveof關係,更新client連接。
(4)configurationprovider——client通過sentinel獲取redis地址,並在failover時更新地址。
Redis 2.8及以上版本可用。
2.3.3 sentinel集群
很顯然,只使用單個sentinel進程來監控redis集群是不可靠的,當sentinel進程宕掉後(sentinel本身也有單點問題,single-point-of-failure)整個集群系統將無法按照預期的方式運行。所以有必要將sentinel集群,這樣有幾個好處:
即使有一些sentinel進程宕掉了,依然可以進行redis集群的主備切換;
如果只有一個sentinel進程,如果這個進程運行出錯,或者是網絡堵塞,那麼將無法實現redis集群的主備切換(單點問題);
如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關於redis集群中的信息。
最少建立3個sentinel節點(sentinel-26380.conf、sentinel-26381.conf、sentinel-26382.conf)的部署方法完全是一致的(端口不同).
2.3.4 配置sentinel
根據官網給出的配置文件如下:
<code>sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
# 監控其他集群
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5/<code>
- 第一行配置指示 Sentinel 去監視一個名為 mymaster 的主服務器, 這個主服務器的 IP 地址為 127.0.0.1 , 端口號為 6379 , 而將這個主服務器判斷為失效至少需要 2 個 Sentinel 同意 (只要同意 Sentinel 的數量不達標,自動故障遷移就不會執行)。不過要注意, 無論你設置要多少個 Sentinel 同意才能判斷一個服務器失效, 一個 Sentinel 都需要獲得系統中多數(majority) Sentinel 的支持, 才能發起一次自動故障遷移, 並預留一個給定的配置紀元 (configuration Epoch ,一個配置紀元就是一個新主服務器配置的版本號)。換句話說, 在只有少數(minority) Sentinel 進程正常運作的情況下, Sentinel 是不能執行自動故障遷移的。
- down-after-milliseconds 選項指定了 Sentinel 認為服務器已經斷線所需的毫秒數。
如果服務器在給定的毫秒數之內, 沒有返回 Sentinel 發送的 PING 命令的回覆, 或者返回一個錯誤, 那麼 Sentinel 將這個服務器標記為主觀下線(subjectively down,簡稱 SDOWN )。
不過只有一個 Sentinel 將服務器標記為主觀下線並不一定會引起服務器的自動故障遷移:只有在足夠數量的 Sentinel 都將一個服務器標記為主觀下線之後, 服務器才會被標記為客觀下線(objectively down, 簡稱 ODOWN ), 這時自動故障遷移才會執行。
將服務器標記為客觀下線所需的 Sentinel 數量由對主服務器的配置決定。
- parallel-syncs 選項指定了在執行故障轉移時, 最多可以有多少個從服務器同時對新的主服務器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長。
如果從服務器被設置為允許使用過期數據集(參見對 redis.conf 文件中對 slave-serve-stale-data 選項的說明), 那麼你可能不希望所有從服務器都在同一時間向新的主服務器發送同步請求, 因為儘管複製過程的絕大部分步驟都不會阻塞從服務器, 但從服務器在載入主服務器發來的 RDB 文件時, 仍然會造成從服務器在一段時間內不能處理命令請求:如果全部從服務器一起對新的主服務器進行同步, 那麼就可能會造成所有從服務器在短時間內全部不可用的情況出現。
你可以通過將這個值設為 1 來保證每次只有一個從服務器處於不能處理命令請求的狀態。
2.3.5 啟動sentinel
線上一般是不同的機器, 我們這裡使用的是一個機器的不同端口
<code>./redis-sentinel sentinel-26380.conf &
./redis-sentinel sentinel-26381.conf ./redis-sentinel sentinel-26382.conf &/<code>
2.3.6 sentinel的工作原理
- 每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 實例發送一個 PING 命令
- 如果一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記為主觀下線。
- 如果一個Master被標記為主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。
- 當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記為客觀下線
- 在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有Master,Slave發送 INFO 命令
- 當Master被 Sentinel 標記為客觀下線時,Sentinel 向下線的 Master 的所有 Slave 發送 INFO 命令的頻率會從 10 秒一次改為每秒一次
- 若沒有足夠數量的 Sentinel 同意 Master 已經下線, Master 的客觀下線狀態就會被移除。若 Master 重新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除。
2.4 redis cluster
2.4.1 什麼是redis cluster
Redis Cluster 是 Redis 的分佈式解決方案,在 Redis 3.0 版本正式推出 的,有效解決了 Redis 分佈式方面的需求。當遇到單機內存、併發、流 量等瓶頸時,可以採用 Cluster 架構達到負載均衡的目的。
redis-cluster的優勢:
- 官方推薦,毋庸置疑。
- 去中心化,集群最大可增加1000個節點,性能隨節點增加而線性擴展。
- 管理方便,後續可自行增加或摘除節點,移動分槽等等。
- 簡單,易上手。
2.4.2數據分佈理論與redis的數據分區
分佈式數據庫首要解決把整個數據集按照分區規則映射到多個節點 的問題,即把數據集劃分到多個節點上,每個節點負責整個數據的一個 子集。常見的分區規則有哈希分區和順序分區。Redis Cluster 採用哈希 分區規則。
虛擬槽分區巧妙地使用了哈希空間,使用分散度良好的哈希函數把 所有的數據映射到一個固定範圍內的整數集合,整數定義為槽(slot)。比如 Redis Cluster 槽的範圍是 0 ~ 16383。槽是集群內數據管理和遷移 的基本單位。
Redis Cluster 採用虛擬槽分區,所有的鍵根據哈希函數映射到 0 ~16383,計算公式:slot = CRC16(key)&16383。每一個節點負責維護一部 分槽以及槽所映射的鍵值數據。
redis-cluster把所有的物理節點映射到[0-16383] 上,cluster 負責維護node slot value
2.4.3 redis cluster的體系架構
我們以 6 個節點為例,來介紹 Redis Cluster 的體系架構。其中:三個為
master 節點,另外三個為 slave 節點。
2.4.4 redis cluster一致性保證(官網)
Redis 並不能保證數據的強一致性. 這意味著在實際中集群在特定的條件下可能會丟失寫操作.
第一個原因是因為集群使用了異步複製. 寫操作過程:
- 客戶端向主節點B寫入一條命令.
- 主節點B向客戶端回覆命令狀態.
- 主節點將寫操作複製給他的從節點 B1, B2 和 B3.
主節點對命令的複製工作發生在返回命令回覆之後, 因為如果每次處理命令請求都需要等待複製操作完成的話, 那麼主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。注意:Redis 集群可能會在將來提供同步寫的方法。Redis 集群另外一種可能會丟失命令的情況是集群出現了網絡分區, 並且一個客戶端與至少包括一個主節點在內的少數實例被孤立。
舉個例子 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, A1 、B1 、C1 為A,B,C的從節點, 還有一個客戶端 Z1 假設集群中發生網絡分區,那麼集群可能會分為兩方,大部分的一方包含節點 A 、C 、A1 、B1 和 C1 ,小部分的一方則包含節點 B 和客戶端 Z1 .
Z1仍然能夠向主節點B中寫入, 如果網絡分區發生時間較短,那麼集群將會繼續正常運作,如果分區的時間足夠讓大部分的一方將B1選舉為新的master,那麼Z1寫入B中的數據便丟失了.
注意, 在網絡分裂出現期間, 客戶端 Z1 可以向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱為節點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
2.4.5 安裝redis cluster
Redis cluster最少需要三臺主服務器, 三臺從服務器(自己做實驗的話, 可以使用一臺服務器, 不同的端口)
- 安裝Ruby環境和Ruby Redis接口
由於創建和管理需要使用到 redis-trib 工具,該工具位於 Redis 源碼的 src 文 件夾中,它是一個 Ruby 程序,這個程序通過向實例發送特殊命令來完成創建新 集群,檢查集群,或者對集群進行重新分片(reshared)等工作,所以需要安裝 Ruby環境和相應的 Redis 接口
下面是可以使用 yum 來安裝 Ruby, 添加yum源, 然後yum安裝
<code>[media]
name=Red Hat Enterprise Linux 7.4 baseurl=file:///cdroom
enabled=1
gpgcheck=1
gpgkey=file:///cdroom/RPM-GPG-KEY-redhat-release/<code>
yum 安裝配置:
<code>yum -y install ruby ruby-devel ruby
gems rpm-buildgem install redis/<code>
如果在安裝過程中出現ERROR: Error installing redis redis requires Ruby version >= 2.2.2.
請參考該博客地址, 講的十分清楚: https://blog.csdn.net/chenxinchongcn/article/details/78666374
- 以6個節點為例, 安裝和部署redis cluster
- 主節點: 6379, 6380, 6381
- 從節點: 6382, 6383, 6384
- 每個配置文件的地方都需要修改, 修改成端口所對應的
<code>daemonize yes
#各個節點的端口不同
port 6379
#開啟集群服務
cluster-enabled yes
#節點的配置文件名字, 需要更改成不同的端口
cluster-config-file nodes/nodes-6379.conf cluster-node-timeout 15000
# rdb 文件名字改成不同的端口
dbfilename dump6379.rdb
appendonly yes
#aof 文件名字改成不同的端口
appendfilename "appendonly6379.aof"/<code>
- 配置文件一共有6個
- redis6379.conf
- redis6380.conf
- redis6381.conf
- redis6382.conf
- redis6383.conf
- redis6384.conf
- 啟動redis實例
<code>bin/redis-server conf/redis6379.conf
bin/redis-server conf/redis6380.conf
bin/redis-server conf/redis6381.conf
bin/redis-server conf/redis6382.conf
bin/redis-server conf/redis6383.conf
bin/redis-server conf/redis6384.conf/<code>
查看redis的進程
<code>ps -ef |grep redis/<code>
- 使用 redis-trib.rb 自動部署方式
<code>bin/redis-trib.rb create --replicas 1 192.168.56.72:6379 192.168.56.72:6380 192.168.56.72:6381 192.168.56.72:6382 192.168.56.72:6383 192.168.56.72:6384/<code>
注意: –replicas 1 表示我們希望為集群中的每個主節點創建一個從節點。
開始配置集群
- 測試redis cluster
- 使用客戶端登陸:
<code>bin/redis-cli -c -p 6379/<code>
可以使用cluster nodes 命令查看集群中的節點
2.4.6 維護節點
1. 添加主節點
- 在終端打開一個新的標籤頁.
- 進入cluster-test 目錄.
- 創建並進入 7006文件夾.
- 和其他節點一樣,創建redis.conf文件,需要將端口號改成7006.
- 最後啟動節點 ../redis-server ./redis.conf
- 如果正常的話,節點會正確的啟動.
<code>bin/redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:6379/<code>
<code>redis 127.0.0.1:7006> cluster nodes
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:6380 master - 0 1385543178575 0 connected 5960-10921
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:6383 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected
f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:6381 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:6382 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:6379 master - 0 1385543179080 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:6384 master - 0 1385543177568 3 connected 11423-16383/<code>
新節點現在已經連接上了集群, 成為集群的一份子, 並且可以對客戶端的命令請求進行轉向了, 但是和其他主節點相比, 新節點還有兩點區別:
a. 新節點沒有包含任何數據, 因為它沒有包含任何哈希槽.
b. 儘管新節點沒有包含任何哈希槽, 但它仍然是一個主節點, 所以在集群需要將某個從節點升級為新的主節點時, 這個新節點不會被選中。
2. has槽重新分配(數據遷移)
a. 先連接集群上任意一個節點
<code>bin/redis-cli --cluster reshard 127.0.0.1:6379/<code>
b. 輸入要分配的槽數量
<code>bin/redis-trib.rb reshard 127.0.0.1:6379
#有個提示輸入1-16384, 屬於多少, 代表分配多少個槽/<code>
c. 輸入要接收槽的節點id
<code>通過cluster nodes 查看7006的節點id為: 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0
輸入到提示信息中/<code>
d. 輸入源節點id
- 輸入源節點id, 槽將從源節點中拿, 分配後的槽在源及誒單中就不存在了, 輸入all, 就是把所有源節點中獲取槽, 輸入done取消分配
3. 添加從節點
<code>./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:6379/<code>
4. 刪除節點
<code>bin/redis-trib del-node 127.0.0.1:6379 `<node-id>`
#可以通過cluster nodes 查看
node-idcluster nodes/<node-id>/<code>
閱讀更多 故事凌 的文章