codis3.2.1集羣搭建與測試

Codis是一套用go語言編寫的,爲了應對高並環境下的redis集羣軟件,原理是對一個redis key操作前,先把這個key通過crc32算法,分配到不同redis的某一個slot,實現併發讀寫功能.而且能通過zookeeper調用redis-sentinel來實現故障切換功能.現在最新版本是3.2.1,依託於redis3.2.9開發出來.

優點:實現高併發讀寫,數據一致性高.

缺點:性能有較大損耗,故障切換無法保證不丟key,無法進行讀寫分離.

 

架構介紹

1.需要用到的軟件有:

codis3.2.1

描述:codis集羣套件,裏面含有redis相關程序,和集羣專用程序,主要功能程序解析:

codis-server:屬於redis-server優化版,基於 redis-3.2.9 分支開發。增加了額外的數據結構,以支持 slot 有關的操作以及數據遷移指令。

codis-proxy:客戶端連接的 Redis 代理服務, 實現了 Redis 協議。 除部分命令不支持以外(例如:keys *,flush ),表現的和原生的 Redis 沒有區別(就像 Twemproxy)。

redis-sentinel:可以實現對Redis的監控、通知、自動故障轉移。如果Master不能工作,則會自動啓動故障轉移進程,將其中的一個Slave提升爲Master,其他的Slave重新設置新的Master服務。Sentinel的配置由 codis-dashboardzookeeper一起控制,不需要手工填寫.

codis-dashboard:集羣管理工具,支持 codis-proxycodis-server 的添加、刪除,以及據遷移等操作。在集羣狀態發生改變時,codis-dashboard 維護集羣下所有 codis-proxy 的狀態的一致性。

codis-fe:集羣web管理界面。

go1.9.1

描述:codis依賴語言包

jdk1.8

描述:zookeeper依賴語言包

zookeeper-3.4.11

描述:用於存放數據配置路由表。zookeeper簡稱zk。在生產環境中,zk部署越多,其可靠性越高。由於zk集羣是以宕機個數過半纔會讓整個集羣宕機,因此,奇數個zk更佳。

 

2. 邏輯架構如下:

訪問層:訪問方式可以是類似keepalived集羣的vip方式,或者是通過java代碼調用jodis控件再連接上zookeeper集羣,然後查找到可用的proxy,進而連接調用不同的codis-proxy地址來實現高可用的LVSHA功能.

 

代理層:中間層由codis-proxyzookeeper處理數據走向和分配,通過crc32算法,key平均分配在不同redis的某一個slot.實現類似raid0的條帶化,在舊版本的codis,slot需要手工分配,codis3.2之後,只要點一個按鈕slot會自動分配,相當方便,但是也可以手動分配,需要另外調用codis-admin命令.

 

數據層:最後codis-proxy把數據存進真實的redis-server主服務器上,由於codis的作者黃東旭相當注重數據一致性,不允許有數據延時造成的數據不一致,所以架構從一開始就沒考慮主從讀寫分離.從服務器僅僅是作爲故障切換的冗餘架構,codis-dashboard監控各服務的狀態,然後通過改寫zookeeper數據和調用redis-sentinel實現故障切換功能.


1.png


3.因爲機器有限,部署的架構如下:

zookeeper集羣:

10.0.2.5:2181

10.0.2.6:2181

10.0.2.7:2181

codis-configcodis-dashboard

10.0.2.6:18087

10.0.2.6:8090

codis-proxy

10.0.2.5:19000

10.0.2.7:19000

codis-server

10.0.2.5:6379(),10.0.2.5:6380()

10.0.2.6:6379(),10.0.2.6:6380()

10.0.2.7:6379(),10.0.2.7:6380()

 

安裝部署

1. 下載程序代碼

1)下載golang語言程序包,

按正常途徑是要×××的,不過國內地址也有人放出來了,因爲codis3.2要求至少是1.71.8以上版本的,那乾脆下最新版吧.

https://studygolang.com/dl/golang/go1.9.1.linux-amd64.tar.gz

 

2)下載java語言程序包,

Java的下載地址一直在變,所以最好自己上去看着來下載

http://download.oracle.com/otn-pub/java/jdk/8u151-b12/e758a0de34e24606bca991d704f6dcbf/jdk-8u151-linux-x64.tar.gz?AuthParam=1513326216_bcf60226458d67751e1d8d1bbe6689b4

 

3)下載zookeeper程序

直接就是程序包,不用編譯了,好方便

http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.11/zookeeper-3.4.11.tar.gz

 

4)下載codis3.2.1

直接就是程序包,不用編譯了,好方便

https://github.com/CodisLabs/codis/releases/download/3.2.1/codis3.2.1-go1.7.6-linux.tar.gz

 

2. 安裝程序

1) 安裝java

#解壓程序包
tar xf jdk-8u144-linux-x64.tar.gz
#移動到指定目錄
mv jdk1.8.0_144/ /usr/local/
#進入指定目錄,並創建程序軟連接
cd /usr/local/
ln -sf jdk1.8.0_144/ jdk
#創建環境變量文件
echo "export JAVA_HOME=/usr/local/jdk
export JRE_HOME=/usr/local/jdk/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin"> /etc/profile.d/java.sh
#重載環境變量
source /etc/profile
#測試檢查是否安裝完成
java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

安裝完畢

 

2) 安裝golang

#解壓程序包
tar xf go1.9.1.linux-amd64.tar.gz
#移動到指定目錄
mv go /usr/local/
#把程序包裏的命令軟連接到系統默認命令目錄
ln -sf /usr/local/go/bin/* /usr/bin/
#測試檢查是否安裝完成
go version
go version go1.9.1 linux/amd64

安裝完成

 

3) 安裝zookeeper

#解壓程序包
tar xf zookeeper-3.4.11.tar.gz
#移動到指定目錄
mv zookeeper-3.4.11 /usr/local/
#進入指定目錄,並創建程序軟連接
cd /usr/local/
ln -sf zookeeper-3.4.11/ zookeeper

安裝完成,等候配置.

 

4) 安裝codis

#解壓程序包
tar xf codis3.2.1-go1.7.6-linux.tar.gz
#移動到指定目錄
mv codis3.2.1-go1.7.6-linux /usr/local/
#進入指定目錄,並創建程序軟連接
cd /usr/local/
ln -sf codis3.2.1-go1.7.6-linux/ codis

安裝完成,等候配置,因爲我們用的都是二進制程序包,只要依賴包有正常安裝,就不會報錯,直接就能用,所以安裝就很簡單.

 

3. 配置程序

1) 配置zookeeper,3臺一起都是這麼配置

#設置hosts跳轉規則,好像不這麼設置的話,不能順利啓動
echo “10.0.2.5        zookeeper-node1
10.0.2.6        zookeeper-node2
10.0.2.7        zookeeper-node3” >> /etc/hosts
#創建程序目錄
mkdir -p /data/zookeeper
#創建配置文件,文件夾裏有一個模板,有興趣可以看看
vim /usr/local/zookeeper/conf/zoo.cfg
#最大連接數設置(單ip限制). 注:默認60,設成0即無限制. 
maxClientCnxns=500
#一個週期(tick)的時長(單位:毫秒). 
tickTime=28800
#初始化同步階段最多耗費tick個數. 注:可用默認值
initLimit=10
#等待應答的最大間隔tick個數. 注:可用默認值
syncLimit=5
#數據存儲目錄,剛纔創建那個. 注:勿放在/tmp目錄
dataDir=/data/zookeeper/
#通信端口. 注:可用默認值
clientPort=2181
server.1=zookeeper-node1:2888:3888
server.2=zookeeper-node2:2888:3888
server.3=zookeeper-node3:2888:3888

生成ID,這裏需要注意, myid對應的zoo.cfgserver.ID.比如zookeeper-node2對應的myid應該是2,不按規定設置,zookeeper集羣將無法啓動

echo "1"> /data/zookeeper/myid

==============================================

例如:在zookeeper-node3那臺10.0.2.7的服務器,就應該是

echo "3"> /data/zookeeper/myid

====================================================

#zoo.cfg最後三行特別說明

說明:server.A=BCD:其中 A 是一個數字,表示這個是第幾號服務器;B 是這個服務器的 ip 地址;C 表示的是這個服務器與集羣中的 Leader 服務器交換信息的端口;D 表示的是萬一集羣中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。

#最後啓動,因爲zookeeper的server是有順序的,最好是按順序啓動,先啓動server.1再啓動server2,最後啓動server.3這樣
/usr/local/zookeeper/bin/zkServer.sh start
#查看狀態,會有follower和leader的區別,他們自己會選誰是leader
/usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower

配置並啓動完畢.

 

2) 配置codis-server,3臺一起都是這麼配置

注意:codis-server就是redis-server程序,屬於codis優化版本,配合codis集羣使用.

所以就是配置個redis的主從結構,實際生產環境不要搭在一起

#創建redis數據目錄,配置文件目錄,日誌目錄
mkdir -p /data/redis/data/config/
mkdir -p /data/redis/data/logs/
#創建主庫的配置文件,暫時只配置這些,其他先默認
vim /data/redis/data/config/redis_6379.conf
#允許後臺運行
daemonize yes
#設置端口,最好是非默認端口
port 6379
#綁定登錄IP,安全考慮,最好是內網
bind *
#命名並指定當前redis的PID路徑,用以區分多個redis
pidfile "/data/redis/data/config/redis_6379.pid"
#命名並指定當前redis日誌文件路徑
logfile "/data/redis/data/logs/redis_6379.log"
#指定RDB文件名,用以備份數據到硬盤並區分不同redis,當使用內存超過可用內存的45%時觸發快照功能
dbfilename "dump_6379.rdb"
#指定當前redis的根目錄,用來存放RDB/AOF文件
dir "/data/redis/data"
#當前redis的認證密鑰,redis運行速度非常快,這個密碼要足夠強大,
#所有codis-proxy集羣相關的redis-server認證密碼必須全部一致
requirepass "123"
#當前redis的最大容量限制,建議設置爲可用內存的45%內,最高能設置爲系統可用內存的95%,
#可用config set maxmemory 去在線修改,但重啓失效,需要使用config rewrite命令去刷新配置文件
#注意,使用codis集羣,必須配置容量大小限制,不然無法啓動
maxmemory 100000kb
#LRU的策略,有四種,看情況選擇
maxmemory-policy allkeys-lru
#如果做故障切換,不論主從節點都要填寫密碼且要保持一致
masterauth "123"
 
#創建從庫的配置文件,暫時只配置這些,其他先默認
vim /data/redis/data/config/redis_6380.conf
#允許後臺運行
daemonize yes
#設置端口,最好是非默認端口
port 6380
#綁定登錄IP,安全考慮,最好是內網
bind *
#命名並指定當前redis的PID路徑,用以區分多個redis
pidfile "/data/redis/data/config/redis_6380.pid"
#命名並指定當前redis日誌文件路徑
logfile "/data/redis/data/logs/redis_6380.log"
#指定RDB文件名,用以備份數據到硬盤並區分不同redis,當使用內存超過可用內存的45%時觸發快照功能
dbfilename "dump_6380.rdb"
#指定當前redis的根目錄,用來存放RDB/AOF文件
dir "/data/redis/data"
#當前redis的認證密鑰,redis運行速度非常快,這個密碼要足夠強大
#所有codis-proxy集羣相關的redis-server認證密碼必須全部一致
requirepass "123"
#當前redis的最大容量限制,建議設置爲可用內存的45%內,最高能設置爲系統可用內存的95%,
#可用config set maxmemory 去在線修改,但重啓失效,需要使用config rewrite命令去刷新配置文件
#注意,使用codis集羣,必須配置容量大小限制,不然無法啓動
maxmemory 100000kb
#LRU的策略,有四種,看情況選擇
maxmemory-policy allkeys-lru
#如果做故障切換,不論主從節點都要填寫密碼且要保持一致
masterauth "123"
#配置主節點信息
slaveof 10.0.2.5 6379

除了端口號不同帶來的文件名不同.實際上從庫配置只是多了最後一行,指定了主庫地址

#然後就可以啓動了,我一開始就說過codis-server就是redis-server
/usr/local/codis/codis-server /data/redis/data/config/redis_6379.conf
/usr/local/codis/codis-server /data/redis/data/config/redis_6380.conf
#驗證一下
ss -ntplu |grep codis-server
tcp    LISTEN     0      128       *:6379                  *:*                   users:(("codis-server",pid=2192,fd=4))
tcp    LISTEN     0      128       *:6380                  *:*                   users:(("codis-server",pid=2197,fd=4))

啓動方式和redis-server一樣,指定配置文件就可以啓動.這就配置並啓動成功了.

 

3) 配置redis-sentinel,3臺一起都是這麼配置

正確來說,redis-sentinel是要配置主從架構才能生效,但是在codis集羣中並不一樣,因爲他的配置由zookeeper來維護,所以,這裏codis使用的redis-sentinel只需要配置一些基本配置就可以了.

#我們把配置放到redis數據目錄的配置文件目錄
vim /data/redis/data/config/sentinel.conf
bind 0.0.0.0
protected-mode no
port 26379
dir "/data/redis/data"
pidfile "/data/redis/data/config/sentinel_26379.pid"
logfile "/data/redis/data/logs/sentinel_26379.log"
daemonize yes
#然後就可以啓動了
/usr/local/codis/redis-sentinel /data/redis/data/config/sentinel.conf
#驗證一下
/usr/local/codis/redis-cli -p 26379 -c info Sentinel
# Sentinel
sentinel_masters:3
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=codis-test1-3,status=ok,address=10.0.2.7:6380,slaves=1,sentinels=3
master1:name=codis-test1-1,status=ok,address=10.0.2.5:6379,slaves=1,sentinels=3
master2:name=codis-test1-2,status=ok,address=10.0.2.6:6379,slaves=1,sentinels=3

配置並啓動成功.

注意:沒有配置好codis-dashboard會沒最後那幾行,因爲還不受zookeeper控制,所以是正常的,配置好之後纔會自動加載進來.

 

4) 配置codis-proxy,這次只有兩臺要配置,當然你也可以配三臺

這個是codis集羣的核心,實際上他也沒配主從架構,配置也是從zookeeper拿來用的,所以,直接來看配置吧

#配置很多,我們先生成一下默認的配置文件
/usr/local/codis/codis-proxy --default-config | tee ./proxy.conf
#然後我們把配置放到redis數據目錄的配置文件目錄,再更改關鍵位置,其他默認即可
vim /data/redis/data/config/proxy.conf
#項目名稱,會登記在zookeeper裏,如果你想一套zookeeper管理多套codis,就必須區分好
product_name = "codis-test1"
# 設置登錄dashboard的密碼(與真實redis中requirepass一致)
product_auth = "123"
#客戶端(redis-cli)的登錄密碼(與真實redis中requirepass不一致),是登錄codis的密碼
session_auth = "123456"
#管理的端口,0.0.0.0即對所有ip開放,基於安全考慮,可以限制內網
admin_addr = "0.0.0.0:11080"
#用那種方式通信,假如你的網絡支持tcp6的話就可以設別的
proto_type = "tcp4"
#客戶端(redis-cli)訪問代理的端口,0.0.0.0即對所有ip開放
proxy_addr = "0.0.0.0:19000"
#外部配置存儲類型,我們用的就是zookeeper,當然也是還有其他可以支持,這裏不展開說
jodis_name = "zookeeper"
#配置zookeeper的連接地址,這裏是三臺就填三臺
jodis_addr = "10.0.2.5:2181,10.0.2.6:2181,10.0.2.7:2181"
#zookeeper的密碼,假如有的話
jodis_auth = ""
#codis代理的最大連接數,默認是1000,併發大要調大
proxy_max_clients = 100000
#假如併發太大,你可能需要調這個pipeline參數,大多數情況默認10000就夠了
session_max_pipeline = 100000
#併發大也可以改以下參數
backend_max_pipeline = 204800
session_recv_bufsize = "256kb"
session_recv_timeout = "0s"
#然後就可以啓動了,
/usr/local/codis/codis-proxy --ncpu=1 --config=/data/redis/data/config/proxy.conf --log=/data/redis/data/logs/proxy.log &
#驗證一下
ss -ntplu |grep codis-proxy
tcp    LISTEN     0      128       *:19000                 *:*                   users:(("codis-proxy",pid=2075,fd=4))
tcp    LISTEN     0      128      :::11080                :::*                   users:(("codis-proxy",pid=2075,fd=6))

--ncpu    指定使用多少個cpu,我的是虛擬機,所以就1了,如果你是多核,那就填多個

--config    指定配置文件,就是剛纔的配置文件

--log    指定輸出日誌文件

配置並啓動成功,但是暫時還用不了,因爲還需要配置codis-dashboard才能最終完成.

 

5) 配置codis-dashboard,只需要配置一臺機上

這個屬於管理配置codis集羣信息的工具,配置完之後的配置信息會自動加載到zookeeper集羣,即使這個服務掛了,配置都還在zookeeper,所以不用考慮高可用,單點就足夠了,大不了重新啓動一下也不是特別麻煩,配置界面由codis-fe來實現.因爲限制於zookeeper的命名空間,通常是和proxy一套配置.

#我們也可以用程序來生成一下默認配置文件
/usr/local/codis/codis-dashboard --default-config | tee ./dashboard.conf
#然後我們把配置放到redis數據目錄的配置文件目錄,再更改關鍵位置,其他默認即可
vim /data/redis/data/config/dashboard.conf
#外部配置存儲類型,我們用的就是zookeeper,當然也是還有其他可以支持,這裏不展開說
coordinator_name = "zookeeper"
#配置zookeeper的連接地址,這裏是三臺就填三臺
coordinator_addr = "10.0.2.5:2181,10.0.2.6:2181,10.0.2.7:2181"
#項目名稱,會登記在zookeeper裏,如果你想一套zookeeper管理多套codis,就必須區分好
product_name = "codis-test1"
#所有redis的登錄密碼(與真實redis中requirepass一致),因爲要登錄進去修改數據
product_auth = "123"
#codis-dashboard的通信端口,0.0.0.0表示對所有開放,最好使用內網地址
admin_addr = "0.0.0.0:18080"
#如果想要在codis集羣在故障切換功能上執行一些腳本,可以配置以下兩個配置
sentinel_notification_script = ""
sentinel_client_reconfig_script = ""
#然後就可以啓動了,
/usr/local/codis/codis-dashboard --ncpu=1 --config=/data/redis/data/config/dashboard.conf --log=/data/redis/data/logs/codis_dashboard.log --log-level=WARN &
#驗證一下
ss -ntplu |grep codis-dashboard
tcp    LISTEN     0      128      :::18080                :::*                   users:(("codis-dashboard",pid=2021,fd=5))

--ncpu    指定使用多少個cpu

--config    指定配置文件

--log    指定輸出日誌文件

--log-level    指定日誌等級,有INFO,WARN,DEBUG,ERROR

安裝完成,就差最後一步就可以開始配置.

由於codis-dashboard本身是不需要密碼登錄的,所以這將會非常危險,強烈建議使用內網地址,而作者表示將會在下個版本考慮增加codis-dashboard的認證密碼.

 

6) 配置codis-fe,只需要配置一臺機上

這個是屬於web界面操作codis-dashboard配置的工具,web代碼文件在codis安裝文件夾的目錄下,具體是:/usr/local/codis/assets/這個目錄.可多臺dashboard共用.

這個工具本身不需要配置文件就能啓動,只需要指定codis-dashboardip和端口就可以了,但是我爲了方便管理,還是生成一個配置文件的好.

#生成一下配置文件,其實也就是codis-dashboard的ip和端口
/usr/local/codis/codis-admin --dashboard-list --zookeeper=10.0.2.6:2181 >codis.json
#然後我們把配置放到redis數據目錄的配置文件目錄,看一下
cat /data/redis/data/config/codis.json 
[
    {
        "name": "codis-test1",
        "dashboard": "10.0.2.6:18080"
    }
]
#然後就可以啓動了,
/usr/local/codis/codis-fe --ncpu=1 --log=/data/redis/data/logs/fe.log --log-level=WARN --dashboard-list=/data/redis/data/config/codis.json --listen=0.0.0.0:8090 &

--ncpu    指定使用多少個cpu

--log    指定輸出日誌文件

--log-level    指定日誌等級,有INFO,WARN,DEBUG,ERROR

--dashboard-list    指定dashboard的地址和項目名稱,這裏因爲生成了文件,所以就指定成文件了

--listen    指定codis-fe的web登錄端口,也就是我們通過8090來訪問這個管理端了,0.0.0.0即對來訪IP無限制,其實最好是限制內網

驗證一下

圖片2.png

全套安裝完成,成功啓動.開始下一步.

 

使用舉例

因爲有了web界面,基本上就都是界面操作了,非常方便,配置會直接加載到zookeeper裏面去.

首先,我們先添加codis-proxy地址和端口

圖片3.png


按順序:

第一步,先添加codis-proxy的地址和管理端口,上面設置的是11080.

第二步,點擊左方的橙色按鈕,然後就添加完畢.

第三步,看到下方出現該有的codis-proxy地址就算完成了,然後看到右方的SYNC字樣的顏色是綠色,則代表配置正常.

如果要刪除記錄,點擊最右方的紅色按鈕即可.

 

然後,我們添加真實redis-server(也是codis-server)地址和端口

企業微信截圖_20180104161941.png


按順序:

第一步,先創建一個組,準備把相關的一組主從放進去

第二步,點擊按鈕生成這個分組

第三步,添加真實redis-server地址,並選定一個分組,例如剛纔創建的分組1

第四步,點擊按鈕生成配置

第五步,可以看到配置已經登記好,注意sync狀態.

第六步,點擊重新平衡所有slots數據塊(任何添加和刪除新舊節點都需要點擊這個)

在舊版本中slots需要手動配置,但是3.2版本之後就改成自動分配了,所以已經不需要配置,點擊一下就可以了.當然你也可以手動去分配.

 

最後配置sentinel的地址和端口

圖片5.png


按順序:

第一步,添加真實的sentinel地址和端口

第二步,點擊按鈕添加

第三步,查看狀態,這裏有點不一樣,他會自動添加當前主從組架構由多少臺,控制切換

也正如我之前說的,他們自動去改配置文件,可以去看看sentinel的配置文件證實一下,這裏不展開來說了

 

都配置好了,就可以使用了,連接其中一個codis-proxy測一下,注意區分好登錄的地址和端口,還有密碼

/usr/local/codis/redis-cli -h 10.0.2.5 -p 19000 -a 123456
10.0.2.5:19000> info
# Server
redis_version:3.2.9
redis_git_sha1:f8bc4e32
redis_git_dirty:0
redis_build_id:2bdb8aa56be3fbc2
redis_mode:standalone
os:Linux 4.10.0-19-generic x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.4
process_id:2032
run_id:98e2364d837990dfb47be050901ef9e36ea113fa
tcp_port:6379
uptime_in_seconds:16312
uptime_in_days:0
hz:10
lru_clock:3634855
executable:/usr/local/codis/codis-server
config_file:/data/redis/data/config/redis_6379.conf
 
# Clients
connected_clients:71
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
 
# Memory
used_memory:61878808
used_memory_human:59.01M
used_memory_rss:76623872
used_memory_rss_human:73.07M
used_memory_peak:63148384
used_memory_peak_human:60.22M
total_system_memory:1529741312
total_system_memory_human:1.42G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:102400000
maxmemory_human:97.66M
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.24
mem_allocator:jemalloc-4.0.3
.
.
.

可以使用了.

 

壓力測試

1.性能測試

先用自帶的redis-benchmark來壓測性能,模擬500個併發和100萬個請求.注意區分好登錄的地址和端口,還有密碼

先壓測codis-proxy的性能

/usr/local/codis/redis-benchmark -h 10.0.2.5 -p 19000 -a 123456 -c 500 -n 1000000 -q

再壓測單節點的性能

/usr/local/codis/redis-benchmark -h 10.0.2.5 -p 6379 -a 123 -c 500 -n 1000000 -q

redis-benchmark參數解析:

-h    ip地址

-p    redis端口

-a    認證密碼

-c    設定多少個併發連接

-n    總共多少個請求

-q    顯示模式:簡要模式

然後看圖

圖片6.png


可以看到,有些操作相差不大,有些相差甚遠,性能損耗明顯,不過作爲集羣應用,主要應對的是高併發環境,性能損耗是可以接受的,何況對於redis這種內存型高速應用來說,性能損耗基本沒什麼太大感知.

 

2.數據分佈測試

然後是讀寫分佈測試:

我寫了個腳本來測試:

cat t-redis.sh
#!/bin/bash
hos="10.0.2.7"
pot="19000"
pawd="123456"
cli="/usr/local/codis/redis-cli"
keyset="keytest2"
valueset="jlasdnfnsdfsdf;sdfhlkjahsdjlkfadfjkasdbbcjhdgasfyuefkbadjkhflk"
dbname=2
a=0
for i in `seq 1 300000`
do
        $cli -h $hos -p $pot -a $pawd -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null
        #echo $a
        let a++
done

腳本很簡單,就是不斷向codis集羣寫垃圾數據而已,執行腳本.

bash t-redis.sh

然後結果可以看web界面,因爲你連接codis-proxyinfo來看,其實是不準確的,那個顯示的只是單臺的數據.

圖片7.png


可以看到,每一個組都分佈得比較均勻,把壓力都分到三臺redis-server主服務器去了.

 

3.故障切換測試

然後來看故障切換,繼續執行那個腳本

bash t-redis.sh

進入其中一臺codis-server,例如10.0.2.5,此時狀態是正常的.

圖片8.png

開始模擬操作

#查找主庫進程
ss -ntplu |grep codis-server 
tcp    LISTEN     0      128       *:6379                  *:*                   users:(("codis-server",pid=2032,fd=4))
tcp    LISTEN     0      128       *:6380                  *:*                   users:(("codis-server",pid=2037,fd=4))
#殺掉主庫進程
kill 2032

此時從庫接管了主庫的進程,sentinels有提示信息.

圖片9.png


可能有人發現組1sync按鈕變成了紅色,也就是說主從失效,點一下就變回正常.

現在等待數據寫完,我先把舊的主進程6379端口從新起來

/usr/local/codis/codis-server /data/redis/data/config/redis_6379.conf

然後看看:

圖片10.png

看狀態是恢復正常了,但是有計算機的同學可以算一下,我的腳本執行的總共是30萬個key,但是現在少了幾千個.


---1:

上面丟key的問題是由於redis-sentinel故障切換期間,整個codis集羣並不會關閉對此故障redis-server的連接,所以codis-proxy依然會發送數據給當前故障的redis-server,而顯然此時的redis-server是無法存儲數據的,這就造成了丟key現象了.如果整個主從掛了,就會丟掉所有發送到此redis-serverkey,除非手工剔除故障節點.

雖然codis還自帶有一種故障切換程序codis-ha,他屬於一個守護進程,會連接codis-dashboard查看各節點狀態,

#執行一下命令啓動codis-ha,端口是codis-dashboard的端口
/usr/local/codis/codis-ha --dashboard=10.0.2.6:18080 --log=/data/redis/data/logs/ha.log --log-level=WARN &

--dashboard    指定dashboard的地址和端口

--log    指定日誌文件

--log-level    指定日誌等級,有INFO,WARN,DEBUG,ERROR

但是這個軟件也是有缺陷,他會自動連接上dashboard檢測各主從結構的健康信息,檢測間隔很快(默認3秒,可修改參數--interval),檢測到故障後,會將故障主庫或者從庫強制下線並刪除在dashboard登記的信息.

雖然切換速度非常快,只會有很少的丟key現象(3秒還是會丟一些),但是後面會把故障舊主庫強制下線,需要手動修改配置並重新啓動redis-server(codis-server),還要再在codis-fe界面添加配置才行.

 1.png

顯然這是做不到全自動管理,有點麻煩了,而且也會讓redis-sentinel變得沒有意義了,所以只能兩個方式選其一.

雖然看上去丟key現象是少了,但是依然還是有丟key的情況,只能說是50步笑100步,而且該組內其他 slave 實例是不會自動改變狀態的,這些 slave 仍將試圖從舊的 master 上同步數據,因而會導致組內新的 master 和其他 slave 之間的數據不一致。因此當出現主從切換時,需要管理員手動創建新的 sync action 來完成新 master 與 slave 之間的數據同步,這樣反而增加了手動操作的工作量,各位對於codis-ha和redis-sentinel的集羣的選擇還是需要多考慮一些實際情況.

所以,說到底就是codis的故障切換沒有做好,如果對丟key可以容忍的,就開redis-sentinel就足夠了,對於數據一致性要求高的,就開codis-ha加腳本來實現比較好,各取所需.


實時添加刪除節點
codis的另一個賣點就是可以在線添加/刪除redis-server(codis-server)節點,做到實時擴容和更換問題節點,對於單點redis而言優勢明顯,不用重啓服務就能有更大的空間,也可以在線切換掉有問題的節點.不過要注意,可以實時擴容和故障切換,並不代表沒有性能損耗,真的要做也是要注意線上壓力,避免性能壓力導致的服務不可用.

實現的原理是因爲codis集羣把各個redis-server節點都用規則分成了多個slots數據塊(總共1024個).需要擴容只要把新的節點添加完成後,在把這些slots信息從新分配就可以達到擴容效果,需要故障切換則把問題redis-server節點slots遷移走,然後就可以把這個節點下架了,對於線上環境可以說是幾乎沒感知,試驗過程中也沒發現有丟key現象,就是性能有所下降,但是我測試的環境下性能下降還能接受,大概只有10%-30%的性能損耗.

開始試驗,首先我們假設添加兩個新的redis-server節點,都直接是主庫,沒有從庫環境(因爲這次不需要測故障切換):

10.0.2.5:16379

10.0.2.6:16379


1.添加一個節點,等於是擴容,這還是比較簡單

1.png

第一步,和之前差不多,先創建一個新組,點擊按鈕確認添加

第二步,把新地址添加到新的組,點擊按鈕確認添加

第三步,確認新的地址已成功添加進去

第四步,點擊按鈕,從新分配所有slots數據塊

這裏唯一問題就是最後一步,重新分配會耗費一定資源,codis會自動平衡數據塊的分佈,所以會有數據遷移過程,但是據我測試的結果來看,並不很嚴重,大概在20%左右.

根據它自帶的監控來看的話,

2.png

可以看到之前正常情況的qps接近1500,剛點重新平衡下降比較嚴重一些,後面就大概有20%的性能損耗那樣子,最後遷移完畢就恢復正常了.當然這是數據量少的情況,如果數據量多,這個遷移時間就恐怕不是那麼簡單了.


2.切換一個節點,並下架

正常下架只需要點擊這個按鈕

3.png

但是因爲裏面還有數據,是不允許直接下架的

4.png

所以我們要先遷移數據,如下所示:

5.png

第一步,確認一個需要遷移的組的數據塊的編號,例如這裏499-512的塊是數據組4的,我現在要遷移組4,就選定這個

第二步,把剛纔獲取到的信息填進去,就是把500這個編號的數據塊從組4遷移到組5,點擊按鈕執行

然後你就會看到,

6.png

顯然組4的信息消失了,codis把組4的數據塊都遷移到了組5去了,

這個時候,這個redis-server節點就可以刪除了

7.png

至於還需不需要重新填補,這個問題則需要自身考慮.如果不需要填補,最好再點一下重新平衡slots比較好.

8.png

可以看到,又重新平衡了.


故障處理

1.codis-dashboard無法啓動,並提示:

[ERROR] store: acquire lock of codis-test1 failed
[error]: zk: node
already exists

由於是測試環境,我經常強制關機,導致codis-dashboard沒有正常關閉.直接造成zookeeper裏面的狀態沒有更新,最終新啓動的codis-dashboard不能註冊進zookeeper,一直提示已存在而被強制關閉.

修復方法也不難,就是刪除這個lock的狀態鍵值就可以了

#輸入項目名和zookeeper地址
/usr/local/codis/codis-admin --remove-lock --product=codis-test1 --zookeeper=10.0.2.6:2181

然後,codis-dashboard又可以正常啓動了.

codis-admin是可以全權控制codis集羣的工具,所有添加/刪除/修改的工作都可以用他來實現,參數很多,這裏只是舉例了一個方法,詳細可以參照codis-admin --help


2.codis-proxy異常退出導致無法刪除

通常codis-proxy都是通過codis-dashboard進行移除,移除過程中codis-dashboard爲了安全會向codis-proxy發送offline指令,成功後纔會將proxy信息從外部存儲(zookeeper)中移除。如果codis-proxy異常退出,該操作會失敗。此時需要手動刪除zookeeper信息。

#先登入zookeeper進行操作
/usr/local/zookeeper/bin/zkCli.sh -server
#確認有問題的codis-proxy地址對應在zookeeper上的信息
[zk: localhost:2181(CONNECTED) 6] get  /codis3/codis-zyyhj1/proxy/proxy-80722e128c6e8fc3d0da44983343a843
{
    "id": 1,
    "token": "80722e128c6e8fc3d0da44983343a843",
    "start_time": "2018-06-16 23:30:57.44436209 +0800 CST",
    "admin_addr": "10.21.1.140:11080",
    "proto_type": "tcp4",
    "proxy_addr": "10.21.1.140:19000",
    "jodis_path": "/jodis/codis-zyyhj1/proxy-80722e128c6e8fc3d0da44983343a843",
    "product_name": "codis-zyyhj1",
    "pid": 26493,
    "pwd": "/root",
    "sys": "Linux localhost.localdomain 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux",
    "hostname": "localhost.localdomain",
    "datacenter": ""
}
cZxid = 0x100001c7b
ctime = Fri Jun 15 21:02:22 CST 2018
mZxid = 0x1000038ae
mtime = Sat Jun 16 23:30:57 CST 2018
pZxid = 0x100001c7b
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 576
numChildren = 0
#確認完畢,刪除
[zk: localhost:2181(CONNECTED) 7] rmr /codis3/codis-zyyhj1/proxy/proxy-80722e128c6e8fc3d0da44983343a843
#刪除完畢,還需要重載一下dashboard,不然信息也是不會更新的
/usr/local/codis/codis-admin  --dashboard=10.21.1.124:18081 --reload

然後,刪不掉的proxy端就不見了,完成.


備註:

codis不支持命令列表:

Command TypeCommand Name
KeysKEYS

MIGRATE

MOVE

OBJECT

RANDOMKEY

RENAME

RENAMENX

SCAN


StringsBITOP

MSETNX


ListsBLPOP

BRPOP

BRPOPLPUSH


Pub/SubPSUBSCRIBE

PUBLISH

PUNSUBSCRIBE

SUBSCRIBE

UNSUBSCRIBE


TransactionsDISCARD

EXEC

MULTI

UNWATCH

WATCH


ScriptingSCRIPT


ServerBGREWRITEAOF

BGSAVE

CLIENT

CONFIG

DBSIZE

DEBUG

FLUSHALL

FLUSHDB

LASTSAVE

MONITOR

RESTORE

SAVE

SHUTDOWN

SLAVEOF

SLOWLOG

SYNC

TIME


Codis SlotSLOTSCHECK

SLOTSDEL

SLOTSINFO

SLOTSMGRTONE

SLOTSMGRTSLOT

SLOTSMGRTTAGONE

SLOTSMGRTTAGSLOT

 以下屬於半支持命令, Codis不支持跨節點操作,因此您必須使用散列標籤將可能顯示在一個請求中的所有密鑰放入同一個插槽中,然後您可以使用這些命令。 Codis不檢查密鑰是否有相同的標籤,所以如果你不使用標籤,你的程序會得到錯誤的迴應。

Command TypeCommand Name
ListsRPOPLPUSH
SetsSDIFF

SINTER

SINTERSTORE

SMOVE

SUNION

SUNIONSTORE
Sorted SetsZINTERSTORE

ZUNIONSTORE
HyperLogLogPFMERGE
ScriptingEVAL

EVALSHA




 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章