之前我們分析過喜馬拉雅的爬取信息,使用分布式爬取,而且需要修改scrapy-redis的過濾算法為布隆過濾來減少redis內存占用,最后考慮這樣還是不一定夠,那么redis集群就是更好的一種選擇方式了。
Redis 集群介紹
Redis 集群是一個提供在多個Redis節點間共享數據的程序集。
Redis集群並不支持處理多個keys的命令,因為這需要在不同的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤.
Redis 集群通過分區來提供一定程度的可用性,在實際環境中當某個節點宕機或者不可達的情況下繼續處理命令. Redis 集群的優勢:
自動分割數據到不同的節點上。
整個集群的部分節點失敗或者不可達的情況下能夠繼續處理命令。
Redis集群分區原理
Redis 集群鍵分布算法使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384 個哈希槽(hash slot), 它們的編號為0、1、2、3……16382、16383,這個槽是一個邏輯意義上的槽,實際上並不存在。redis中的每個key都屬於這 16384 個哈希槽的其中一個,存取key時都要進行key->slot的映射計算。
Redis 集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽.集群的每個節點負責一部分hash槽,舉個例子,比如當前集群有3個節點,那么:
節點 A 包含 0 到 5500號哈希槽.
節點 B 包含5501 到 11000 號哈希槽.
節點 C 包含11001 到 16384號哈希槽.
這種結構很容易添加或者刪除節點. 比如如果我想新添加個節點D, 我需要從節點 A, B, C中得部分槽到D上. 如果我想移除節點A,需要將A中的槽移到B和C節點上,然后將沒有任何槽的A節點從集群中移除即可. 由於從一個節點將哈希槽移動到另一個節點並不會停止服務,所以無論添加刪除或者改變某個節點的哈希槽的數量都不會造成集群不可用的狀態.
Redis 集群的主從復制模型
為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用,所以集群使用了主從復制模型,每個節點都會有N-1個復制品.
在我們例子中具有A,B,C三個節點的集群,在沒有復制模型的情況下,如果節點B失敗了,那么整個集群就會以為缺少5501-11000這個范圍的槽而不可用.
然而如果在集群創建的時候(或者過一段時間)我們為每個節點添加一個從節點A1,B1,C1,那么整個集群便有三個master節點和三個slave節點組成,這樣在節點B失敗后,集群便會選舉B1為新的主節點繼續服務,整個集群便不會因為槽找不到而不可用了
不過當B和B1 都失敗后,集群是不可用的.
Redis 一致性保證
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中得數據便丟失了.
Redis集群搭建
Redis安裝
CentOS和Mac的安裝請看:Linux/Mac安裝Redis數據庫
Linux通用的安裝方式:
mkdir /home/redis-cluster
cd /home/redis-cluster
# 下載穩定版redis
wget http://download.redis.io/releases/redis-stable.tar.gz
tar xvf redis-stable.tar.gz
cd redis-stable
make
make install
安裝完以后,redis命令會在/usr/local/bin目錄下,我們還需要將src/redis-trib.rb文件拷貝到/usr/local/bin目錄下,我們直接在命令行使用redis-server就可以啟動服務
在redis-stable目錄下有redis.conf文件,先修改文件配置
port 7000(每個節點的端口號)
daemonize yes(后台運行)
bind 192.168.1.110(綁定當前機器 IP)
dir /home/redis-cluster/7000/data/(數據文件存放位置)
pidfile /var/run/redis_7000.pid(pid 7000和port要對應)
cluster-enabled yes(啟動集群模式)
cluster-config-file nodes-7000.conf(7000和port要對應)
cluster-node-timeout 15000
appendonly yes
在單機配置
先創建集群目錄
cd /home/redis-cluster
mkdir -p 7000/data 7001/data 7002/data 7003/data 7004/data 7005/data
將上面的redis.conf文件分別復制到這幾個文件夾中,修改其中端口相關的部分
port 7001
dir /home/redis-cluster/7001/data/
pidfile /var/run/redis_7001.pid
pidfile /var/run/redis_7001.pid
cluster-config-file nodes-7001.conf
啟動節點
redis-server /home/redis-cluster/7000/data/redis.conf
redis-server /home/redis-cluster/7001/data/redis.conf
redis-server /home/redis-cluster/7002/data/redis.conf
redis-server /home/redis-cluster/7003/data/redis.conf
redis-server /home/redis-cluster/7004/data/redis.conf
redis-server /home/redis-cluster/7005/data/redis.conf
到這里先別急,離成功已經很近了,我們還需要安裝集群所需的軟件
安裝集群所需軟件
CentOS安裝
yum install ruby
yum install rubygems
gem install redis
壓縮包安裝
下載ruby網址:https://www.ruby-lang.org/en/downloads/

下載rubygems網址:https://rubygems.org/pages/download

# 下載ruby
wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.1.tar.gz
tar xf ruby-2.5.1.tar.gz
cd ruby-2.5.1
./configure
make
make install
#下載rubygems
wget https://rubygems.org/rubygems/rubygems-2.7.7.tgz
tar xf rubygems-2.7.7.tgz
cd rubygems-2.7.7
ruby setup.rb
#安裝完rubygems后,就可以使用gem命令安裝redis支持
gem install redis
啟動集群
redis-trib.rb create --replicas 1 192.168.1.110:7000 192.168.1.110:7001 192.168.1.110:1002 192.168.1.110:7003 192.168.1.110:7004 192.168.1.110:7005
參數:
--replicas 1 表示主從復制比例為 1:1,即一個主節點對應一個從節點;然后,默認給我們分配好了每個主節點和對應從節點服務,以及 solt 的大小,因為在 Redis 集群中有且僅有 16383 個 solt ,默認情況會給我們平均分配,當然你可以指定,后續的增減節點也可以重新分配。
我們現在有六個節點,三個主節點三個從節點,默認最少需要六個節點才能組成集群。
錯誤日志:如果報node 192.168.1.xx:7001 is not empty之類的錯誤說明集群未正確關閉或是存有日志文件則
針對錯誤信息執行集群修復命令:./redis-trib.rb fix 192.168.133.128:7001
登錄客戶端進行操作:
redis-cli -c -h 192.168.1.110 -p 7000一定要加上-c參數
到這里單機集群配置已經成功了
多機器配置
與單機配置相比較,需要修改的有以下幾點:
- 綁定ip配置為每個機器的ip
- 端口可以使用一樣的,也可以配置為不一樣的
- 安裝的軟件在每個機器上必須安裝
- 啟動集群命令只需要在其中一個機器上執行即可
其他的命令等均一樣
集群搭建好了,但是有一點要注意,對於同一個key只會存在於一個節點機器上,比如set、zset、list這種數據結構。所以最初我想用集群去存儲上億條去重數據等想法是不行了。最終還是要修改去重算法。
python操作Redis集群
python的redis庫是不支持集群操作的,推薦庫:redis-py-cluster,一直在維護。還有一個rediscluster庫,看GitHub上已經很久沒更新了。
安裝pip install redis-py-cluster
from rediscluster import StrictRedisCluster
startup_nodes = [
{"host":"192.168.1.110", "port":7000},
{"host":"192.168.1.110", "port":7001},
{"host":"192.168.1.110", "port":7002},
{"host":"192.168.1.110", "port":7003},
{"host":"192.168.1.110", "port":7004},
{"host":"192.168.1.110", "port":7005}
]
rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
rc.set('name','admin')
rc.set('age',18)
print "name is: ", rc.get('name')
print "age is: ", rc.get('age')
除了連接這里不一樣,其他的操作與redis庫一致,另外在startup_nodes參數中即使寫錯幾個機器host或port也能連接成功,理論上講只要有一個節點正常就可以使用
如果你覺得我的文章還可以,可以關注我的微信公眾號,查看更多實戰文章:Python爬蟲實戰之路
也可以掃描下面二維碼,添加我的微信公眾號

