對於Redis集羣方案有好多種,基本經常使用的就是twemproxy,codis、redis cluster這三種解決方案,本人有幸工做中都大量使用過,各有利有弊,下面這篇文章詳解講解一下豌豆尖的Codis 3。因爲業務中還使用有Codis 2,因此對於Codis 2也寫了一篇文章Codis 2集羣搭建。Codis整體來講還算不錯,僅供你們學習和參考。html
Codis是一個分佈式Redis解決方案, 對於上層的應用來講, 鏈接到Codis Proxy和鏈接原生的Redis Server沒有顯著區別 (不支持的命令列表), 上層應用能夠像使用單機的Redis同樣使用, Codis 底層會處理請求的轉發, 不停機的數據遷移等工做, 全部後邊的一切事情, 對於前面的客戶端來講是透明的, 能夠簡單的認爲後邊鏈接的是一個內存無限大的Redis服務。前端
Codis 3.x由如下組件組成:java
• Codis Server:基於 redis-2.8.21 分支開發。增長了額外的數據結構,以支持 slot 有關的操做以及數據遷移指令。具體的修改能夠參考文檔 redis 的修改。node
• Codis Proxy:客戶端鏈接的Redis代理服務, 實現了Redis協議。 除部分命令不支持之外(不支持的命令列表),表現的和原生的Redis沒有區別(就像Twemproxy)。linux
對於同一個業務集羣而言,能夠同時部署多個codis-proxy實例;nginx
不一樣codis-proxy之間由codis-dashboard保證狀態同步。c++
• Codis Dashboard:集羣管理工具,支持codis-proxy、codis-serve的添加、刪除,以及據遷移等操做。在集羣狀態發生改變時,codis-dashboard 維護集羣下全部 codis-proxy的狀態的一致性。git
對於同一個業務集羣而言,同一個時刻 codis-dashboard 只能有 0個或者1個;github
全部對集羣的修改都必須經過 codis-dashboard 完成。golang
• Codis Admin:集羣管理的命令行工具。
可用於控制codis-proxy、codis-dashboard狀態以及訪問外部存儲。
• Codis FE:集羣管理界面。
多個集羣實例共享能夠共享同一個前端展現頁面;
經過配置文件管理後端codis-dashboard列表,配置文件可自動更新。
• Codis HA:爲集羣提供高可用。
依賴codis-dashboard實例,自動抓取集羣各個組件的狀態;
會根據當前集羣狀態自動生成主從切換策略,並在須要時經過codis-dashboard完成主從切換。
• Storage:爲集羣狀態提供外部存儲。
提供Namespace概念,不一樣集羣的會按照不一樣product name進行組織;
目前僅提供了Zookeeper和Etcd兩種實現,可是提供了抽象的interface可自行擴展。
這次試驗服務部署架構方式以下:
10.0.60.152 | zk、fe、dashboard、proxy、codis |
10.0.60.153 | zk、proxy、codis |
10.0.60.154 | zk、proxy、codis |
system:CentOS 7版本這次試驗用到的軟件及版本以下:
Jdk:1.8版本
Zookeeper:3.4版本(http://zookeeper.apache.org/releases.html)
Go:go1.5.2.Linux-amd64.tar.gz版本(https://golang.org/doc/install?download=go1.5.2.linux-amd64.tar.gz)
Codis:3.0.3版本(https://github.com/CodisLabs/codis/archive/3.0.3.zip)
安裝參考文檔:https://github.com/CodisLabs/codis/blob/release3.0/doc/tutorial_zh.md
Zookeeper分佈式服務框架,是Apache Hadoop的一個子項目,它主要是用來解決分佈式應用中常常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集羣管理、分佈式應用配置項的管理等。Codis依賴zookeeper才能協同工做。
首先安裝開發工具及openjdk,zookeeper是由Java語言開發的,因此須要openjdk環境。
$ yum groupinstall "Development tools" "Compatibility libraries" -y $ yum install openssl-devel openssl -y $ yum install java-1.8.0-openjdk-devel java-1.8.0-openjdk -y $ yum install -y gcc make gcc-c++ automake lrzsz openssl-devel zlib-* bzip2-* readline* zlib-* bzip2-* git $ yum install -y nmap unzip wget lsof xz net-tools mercurial
肯定Java運行環境正常
$ java -version openjdk version "1.8.0_101" OpenJDK Runtime Environment (build 1.8.0_101-b13) OpenJDK 64-Bit Server VM (build 25.101-b13, mixed mode)
安裝二進制版本的zookeeper
$ tar xvf zookeeper-3.4.9.tar.gz -C /usr/local/ $ ln -s /usr/localzookeeper-3.4.9/ /usr/local/zookeeper $ cd /usr/local/zookeeper/conf $ cp zoo_sample.cfg zoo.cfg
編譯zookeeper配置文件/usr/local/zookeeper/conf/zoo.cfg
maxClientCnxns=60 tickTime=2000 initLimit=10 syncLimit=5 dataDir=/data/zookeeper/db dataLogDir=/data/zookeeper/log clientPort=2181 # cluster configure server.1=10.0.60.152:2888:3888 server.2=10.0.60.153:2888:3888 server.3=10.0.60.154:2888:3888
$ mkdir /data/zookeeper/{db,log} -p
下面須要生成ID,這裏須要注意,myid對應的zoo.cfg的server.ID,好比第二臺zookeeper主機對應的myid應該是2,以此類推,三個主機分別爲:其中2888表示zookeeper程序監聽端口,3888表示zookeeper選舉通訊端口。
10.0.60.152$ echo 1 > /data/zookeeper/db/myid 10.0.60.153$ echo 2 > /data/zookeeper/db/myid 10.0.60.154$ echo 3 > /data/zookeeper/db/myid
而後輸出環境變量。
$ export PATH=$PATH:/usr/local/zookeeper/bin/ $ source /etc/profile
而後就能夠啓動zookeeper了。
$ zkServer.sh start
查看各個zookeeper節點的狀態(會有一個leader節點,兩個follower節點)。
[root@node1 ~]# zkServer.sh status Mode: follower [root@node2 ~]# zkServer.sh status Mode: leader [root@node3 ~]# zkServer.sh status Mode: follower
客戶端鏈接,能夠查看相關信息。
$ zkCli.sh -server 127.0.0.1:2181
至此,zookeeper已經搞定了。
首先下載go二進制安裝包
https://golang.org/doc/install?download=go1.5.2.linux-amd64.tar.gz
官方界面介紹瞭如何安裝GO運環境,對於GO運行環境來講,有一些特定的GOROOT和GOPATH環境變量須要設置,這是必須的,否則沒法運行go程序。這裏最好安裝go1.5.2版本,否則後面編譯Codis有些小問題。
$ tar xvf go1.5.2.linux-amd64.tar.gz -C /usr/local
解壓完成後,GO就安裝完了,下面設置一個GOPATH目錄,其實就是go程序運行目錄。
$ mkdir /usr/local/codis
而後就能夠設置GO須要的環境變量,路徑看好,千萬別搞錯了。
$ cat /etc/profile.d/go.sh #!/bin/bash # export GOROOT=/usr/local/go export GOPATH=/usr/local/codis/ export PATH=$PATH:$GOROOT/bin
應用一下go.sh
$ chmod a+x /etc/profile.d/go.sh $ source /etc/profile.d/go.sh
查看GO版本
$ go version go version go1.5.2 linux/amd64
Codis的編譯使用了godep,若是沒有安裝的話就會報godep command not found的錯誤,godep是golang的一個包管理工具,相似於Python的pip。
$ mkdir -p $GOPATH/src/github.com/tools $ cd $GOPATH/src/github.com/tools $ go get -u github.com/tools/godep $ cd godep $ go install ./
其中go install ./命令會將godep執行程序生成到$GOPATH/bin下。
$ ll $GOPATH/bin -rwxr-xr-x. 1 root root 10329080 Oct 11 11:00 godep
而後將$GOPATH/bin加到/etc/profile.d/go.sh中,主要是引用godep命令:
$ cat /etc/profile.d/go.sh #!/bin/bash # export GOROOT=/usr/local/go export GOPATH=/usr/local/codis/ export PATH=$PATH:$GOROOT/bin export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
$ source /etc/profile.d/go.sh
查看godep效果
$ which godep /usr/local/codis/bin/godep $ godep version godep v74 (linux/amd64/go1.5.2)
$ cd /root $ wget https://github.com/CodisLabs/codis/archive/3.0.3.zip $ unzip 3.0.3.zip $ mkdir /usr/local/codis/src/github.com/CodisLabs $ cp -fr ./codis-3.0.3/ /usr/local/codis/src/github.com/CodisLabs/codis $ cd /usr/local/codis/src/github.com/CodisLabs/codis $ make
編譯完成後,查看一下Codis產生的文件。
$ ll total 52 drwxr-xr-x. 3 root root 4096 Oct 11 11:08 bin drwxr-xr-x. 7 root root 4096 Oct 11 11:05 cmd drwxr-xr-x. 5 root root 4096 Oct 11 11:05 doc -rw-r--r--. 1 root root 338 Oct 11 11:05 Dockerfile drwxr-xr-x. 5 root root 4096 Oct 11 11:05 extern drwxr-xr-x. 3 root root 4096 Oct 11 11:06 Godeps -rw-r--r--. 1 root root 1352 Oct 11 11:05 Makefile -rw-r--r--. 1 root root 1076 Oct 11 11:05 MIT-LICENSE.txt drwxr-xr-x. 6 root root 4096 Oct 11 11:05 pkg -rw-r--r--. 1 root root 2966 Oct 11 11:05 README.md drwxr-xr-x. 2 root root 4096 Oct 11 11:05 scripts -rwxr-xr-x. 1 root root 418 Oct 11 11:05 version -rw-r--r--. 1 root root 1081 Oct 11 11:05 wandoujia_license.txt
輸出Codis執行文件,添加最後一行PATH變量。在bin文件夾內生成codis-admin、codis-dashboard、codis-fe、codis-ha、codis-proxy、codis-server六個可執行文件。另外, bin/assets文件夾是codis-dashboard http服務須要的前端資源, 須要和codis-dashboard放置在同一文件夾下。
$ cat /etc/profile.d/go.sh #!/bin/bash # export GOROOT=/usr/local/go export GOPATH=/usr/local/codis/ export PATH=$PATH:$GOROOT/bin export PATH=$GOROOT/bin:$GOPATH/bin:$PATH export PATH=$PATH:/usr/local/codis/src/github.com/CodisLabs/codis/bin/
$ source /etc/profile.d/go.sh
至此,Codis安裝完成。但須要注意的是,若是你是用golang 1.5 beta3以上的版本進行編譯,還有可能出現的一個問題是:
GOPATH=godep path godep restore Error: GO15VENDOREXPERIMENT is enabled and the vendor/ directory is not a valid Go workspace. godep: Error restore requires GOPATH but it is empty. make: *** [godep] Error 1
這是由於golang 1.5 beta3以後go添加了GO15VENDOREXPERIMENT這個特性,並在1.6版本就默認開啓,你能夠參照Codis issue715裏面的方案解決。最簡單就是在編譯前
export GO15VENDOREXPERIMENT=0
Codis安裝完成後,就能夠爲Codis建立一些標準的目錄,用來存儲Codis的腳本目錄、配置文件目錄、日誌目錄、PID目錄、Redis配置目錄等。
$ mkdir -p /data/codis/sh $ mkdir -p /data/codis/conf $ mkdir -p /data/codis/log $ mkdir -p /data/codis/run $ mkdir -p /data/codis/redis/bin $ mkdir -p /data/codis/redis/redis-6379 $ mkdir -p /data/codis/redis/redis-6380
複製Codis自帶的redis-2.8.21相關工具到標準目錄中。
$ cd /usr/local/codis/src/github.com/CodisLabs/codis/extern/redis-2.8.21/src/ $ cp ./{redis-benchmark,redis-cli,redis-sentinel,redis-server} /data/codis/redis/bin/
添加環境變量
$ cat /etc/profile.d/go.sh #!/bin/bash # export GOROOT=/usr/local/go export GOPATH=/usr/local/codis/ export PATH=$PATH:$GOROOT/bin export PATH=$GOROOT/bin:$GOPATH/bin:$PATH export PATH=$PATH:/usr/local/codis/src/github.com/CodisLabs/codis/bin/ export PATH=$PATH:/data/codis/redis/bin
$ source /etc/profile.d/go.sh
考慮到性能,主庫關閉aof和rdp,從庫只開啓aof便可。下面這份配置就是生產環境中的配置,具體的含義能夠看本博客的Redis生產環境配置文件詳解章節。
主庫:/data/codis/redis/redis-6379/redis.conf
###基本參數### daemonize yes pidfile /data/codis/run/redis-6379.pid port 6379 tcp-backlog 65535 bind 0.0.0.0 timeout 0 tcp-keepalive 0 loglevel notice logfile "/data/codis/log/redis-6379.log" databases 16 lua-time-limit 5000 maxclients 10000 ###慢日誌參數### slowlog-log-slower-than 10000 slowlog-max-len 128 ###內存參數### maxmemory 3G maxmemory-policy noeviction ###RDB持久化參數### #save 3600 1 #stop-writes-on-bgsave-error yes #rdbcompression yes #rdbchecksum yes #dbfilename dump.rdb ###AOF持久化參數### #no-appendfsync-on-rewrite yes #appendonly yes #appendfilename "appendonly.aof" #appendfsync no #auto-aof-rewrite-min-size 512mb #auto-aof-rewrite-percentage 100 #aof-load-truncated yes #aof-rewrite-incremental-fsync yes ###客戶端Buffer參數### client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 ###其餘參數### hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes latency-monitor-threshold 0 ###安全參數### #requirepass 123456789
從庫:/data/codis/redis/redis-6380/redis.conf
###基本參數### daemonize yes pidfile /data/codis/run/redis-6380.pid port 6380 tcp-backlog 65535 bind 0.0.0.0 timeout 0 tcp-keepalive 0 loglevel notice logfile "/data/codis/log/redis-6380.log" databases 16 lua-time-limit 5000 maxclients 10000 ###慢日誌參數### slowlog-log-slower-than 10000 slowlog-max-len 128 ###內存參數### maxmemory 3G maxmemory-policy noeviction ###RDB持久化參數### #save 3600 1 #stop-writes-on-bgsave-error yes #rdbcompression yes #rdbchecksum yes #dbfilename dump.rdb ###AOF持久化參數### no-appendfsync-on-rewrite yes appendonly yes appendfilename "appendonly.aof" appendfsync no auto-aof-rewrite-min-size 512mb auto-aof-rewrite-percentage 100 aof-load-truncated yes aof-rewrite-incremental-fsync yes ###客戶端Buffer參數### client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 ###其餘參數### hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes latency-monitor-threshold 0 ###安全參數### #requirepass 123456789
可使用codis-server啓動redis了。
$ codis-server /data/codis/redis/redis-6379/redis.conf $ codis-server /data/codis/redis/redis-6380/redis.conf
首先生成默認的配置文件:
$ codis-dashboard --default-config | tee /data/codis/conf/dashboard.toml
修改配置文件參數以下:
# Set Coordinator, only accept "zookeeper" & "etcd" coordinator_name = "zookeeper" coordinator_addr = "10.0.60.152:2181,10.0.60.153:2181,10.0.60.154:2181" # Set Codis Product {Name/Auth}. product_name = "codis-demo" product_auth = "" # Set bind address for admin(rpc), tcp only. admin_addr = "0.0.0.0:18080"
配置文件參數說明:
coordinator_name:外部存儲類型,接受zookeeper/etcd,這裏咱們使用的zookeeper集羣。
coordinator_addr:外部存儲地址。
product_name:集羣名稱,知足正則\w[\w\.\-]*。
product_auth:集羣密碼,默認爲空。
admin_addr:RESTful API端口。
啓動dashboard
$ nohup codis-dashboard --ncpu=2 --config=/data/codis/conf/dashboard.toml --log=/data/codis/log/dashboard.log --log-level=WARN &
參數解釋:
–ncpu=N:最大使用CPU個數。
-c CONF, –config=CONF:指定啓動配置文件。
-l FILE, –log=FILE:設置log輸出文件。
–log-level=LEVEL:設置log輸出等級:INFO,WARN,DEBUG,ERROR,默認INFO,推薦WARN。
PS:dashboard只須要在一個節點啓動便可,啓動時會向zookeeper註冊信息(topom),若是有其餘節點也啓動dashboard時,向zookeeper註冊信息發現裏面有信息時,就會沒法啓動的。另外,若是dashboard異常退出,請看後面的異常處理案例。
八、配置啓動Codis各組件—-啓動codis-proxy(集羣中全部節點)
首先生成默認的配置文件:
$ codis-proxy --default-config | tee /data/codis/conf/proxy.toml
修改配置文件參數以下:
product_name = "codis-demo" product_auth = "" admin_addr = "0.0.0.0:11080" proto_type = "tcp4" proxy_addr = "0.0.0.0:19000" #jodis_addr = "10.0.60.152:2181,10.0.60.153:2181,10.0.60.154:2181" jodis_addr = "" jodis_timeout = 10 backend_ping_period = 5 session_max_timeout = 1800 session_max_bufsize = 131072 session_max_pipeline = 1024 session_keepalive_period = 60
配置文件參數介紹:
product_name:產品名稱, 這個codis集羣的名字, 能夠認爲是命名空間, 不一樣命名空間的codis沒有交集。
product_auth:集羣密碼,默認爲空。Codis 3.x支持AUTH,可是要求全部組件使用的AUTH必須徹底相同。
admin_addr:RESTful API端口。
proto_type:Redis端口類型,接受tcp/tcp4/tcp6/unix/unixpacket。
proxy_addr:Redis端口地址或者路徑。
jodis_addr:Jodis註冊zookeeper地址。
jodis_timeout:Jodis註冊session timeout時間,單位second。
backend_ping_period:與codis-server探活週期,單位second,0表示禁止。
session_max_timeout:與client鏈接最大讀超時,單位second,0表示禁止。
session_max_bufsize:與client鏈接讀寫緩衝區大小,單位byte。
session_max_pipeline:與client鏈接最大的pipeline大小。
session_keepalive_period:與client的tcp keepalive週期,僅tcp有效,0表示禁止。
啓動codis-proxy
$ nohup codis-proxy --ncpu=2 --config=/data/codis/conf/proxy.toml --log=/data/codis/log/proxy.log --log-level=WARN &
-c CONF, –config=CONF:指定啓動配置文件。
–ncpu=N:最大使用CPU個數。
-l FILE, –log=FILE:設置log輸出文件。
–log-level=LEVEL:設置log輸出等級:INFO,WARN,DEBUG,ERROR;默認INFO,推薦WARN。
–ulimit=NLIMIT:檢查ulimit -n的結果,確保運行時最大文件描述很多於NLIMIT。
codis-proxy啓動後,處於waiting狀態,監聽proxy_addr地址,可是不會accept鏈接,添加到集羣並完成集羣狀態的同步,才能改變狀態爲online。添加的方法有如下兩種:
第一種:經過codis-fe添加,經過Add Proxy按鈕,將admin_addr加入到集羣中,以下圖(具體操做要等到後面codis-fe啓動後才能夠):
第二種:經過codis-admin命令行工具添加,方法以下(添加3個proxy):
$ codis-admin --dashboard=10.0.60.152:18080 --create-proxy -x 10.0.60.152:11080 $ codis-admin --dashboard=10.0.60.152:18080 --create-proxy -x 10.0.60.153:11080 $ codis-admin --dashboard=10.0.60.152:18080 --create-proxy -x 10.0.60.154:11080
1)獲取proxy信息,對集羣name以及auth進行驗證,並將其信息寫入到外部存儲中;其中–dashboard須要指定codis-dashboard的管理地址,–create-proxy指定爲和codis-proxy的admin_addr地址,。添加過程當中,codis-dashboard會完成以下一系列動做:
2)同步slots狀態;
3)標記proxy狀態爲online,此後proxy開始accept鏈接並開始提供服務;
PS:在添加codis-proxy的時候須要特別注意,這個地方容易出現各類問題,最好能一次性添加成功,否則就須要刪除zookeeper數據了,而後從新開始。還有一點須要注意的是,測試中發現一旦刪除掉某個proxy後,再次添加就會報錯。
首先生成默認的配置文件,配置文件codis.json能夠手動編輯,也能夠經過codis-admin從外部存儲(這裏是zookeeper)中拉取,以下操做:
$ codis-admin --dashboard-list --zookeeper=127.0.0.1:2181 | tee /data/codis/conf/codis.json
拉去的配置文件信息:
$ cat /data/codis/conf/codis.json [ { "name": "codis-demo", "dashboard": "10.0.60.152:18080" } ]
啓動codis-fe,注意啓動codis-fe的時候,必需要使用codis-fe的全路徑進行啓動,由於codis-fe須要找到前端靜態文件,也就是要找到/usr/local/codis/src/github.com/CodisLabs/codis/bin/assets目錄。
$ nohup `which codis-fe` --ncpu=2 --log=/data/codis/log/fe.log --log-level=WARN --dashboard-list=/data/codis/conf/codis.json \ --listen=0.0.0.0:8080 &
web監控端口是801端口,咱們能夠在瀏覽器打開http://10.0.60.152:8080看看圖形化界面。
首先使用codis-admin工具建立組,按照上面的規劃的,咱們建立2個組便可:
$ codis-admin --dashboard=10.0.60.152:18080 --create-group --gid=1 $ codis-admin --dashboard=10.0.60.152:18080 --create-group --gid=2
而後使用codis-admin工具給組添加Redis主機(2個主機爲一個組):
$ codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=1 --addr=10.0.60.152:6379 $ codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=1 --addr=10.0.60.154:6379
$ codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=2 --addr=10.0.60.153:6380 $ codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=2 --addr=10.0.60.154:6380
把從庫跟主庫同步:
$ codis-admin --dashboard=10.0.60.152:18080 --sync-action --create --addr=10.0.60.154:6379 $ codis-admin --dashboard=10.0.60.152:18080 --sync-action --create --addr=10.0.60.154:6380
若slave須要提高爲master,操做以下:須要注意的是若是當從庫運行一段時間後掛掉了,那麼從新啓動後須要人爲手動地將主從進行同步,執行上面的命令便可,或者圖形界面操做(反之,若是主庫掛了,立刻又好了,這時候從庫會自動從新鏈接上的,不須要人爲干預)。
$ codis-admin --dashboard=10.0.60.152:18080 --promote-server --gid=1 --addr=10.0.60.154:6379
注意的是,當從庫提高爲主庫後,那麼原來的主庫就會掉線,若是想把它做爲如今主庫的從庫,仍是須要人爲干預的,由於這個涉及到數據安全性的問題。
Codis採用Pre-sharding的技術來實現數據的分片, 默認分紅1024個slots (0-1023),對於每一個key來講,經過如下公式肯定所屬的Slot Id : SlotId = crc32(key) %1024。每個slot都會有一個且必須有一個特定的server group id來表示這個slot的數據由哪一個server group來提供。
$ codis-admin --dashboard=10.0.60.152:18080 --slot-action --create-range --beg=0 --end=511 --gid=1 $ codis-admin --dashboard=10.0.60.152:18080 --slot-action --create-range --beg=512 --end=1023 --gid=2
至此,一個簡單的集羣就搭建完成了。可是此時redis雖然可以很好地進行切換了。可是是須要人爲切換,若是想作到自動切換,那麼還須要Codis的另外一個組件codis-ha。
codis-ha --log=/data/codis/log/ha.log --log-level=WARN --interval=3 --dashboard=127.0.0.1:18080 &
注意:Codis HA工具僅僅是Codis集羣HA的一部分,單獨工做能力有限。工做原理:
默認以5s(–interval是調整時間間隔的)爲週期,codis-ha會從codis-dashboard中拉取集羣狀態,並進行主從切換;
codis-ha在如下狀態下會退出:
一、從codis-dashboard獲取集羣狀態失敗時;
二、向codis-dashboard發送主從切換指令失敗時;
codis-ha在如下狀態下不會進行主從切換:
一、存在proxy狀態異常:
由於提高主從須要獲得全部proxy的確認,所以必須確保操做時全部proxy都能正常響應操做指令;
二、網絡緣由形成的master異常:
若存在slave知足slave.master_link_status == up,一般能夠認爲master並無真的退出,而是因爲網絡緣由或者響應延遲形成的master狀態獲取失敗,此時codis-ha不會對該group進行操做;
三、沒有知足條件的slave時:
提高過程會選擇知足slave.master_link_status == down,而且slave.master_link_down_since_seconds最小的進行操做。這就要求被選擇的slave至少在過去一段時間內與master是成功同步狀態,這個時間間隔是2d+5,其中d是codis-ha檢查週期默認5秒。
注意:所以,應用codis-ha時還須要結合對codis-proxy和codis-server的可用性監控,不然codis-ha沒法保證可靠性。
PS:當codis-ha啓動後,你能夠測試關掉redis master,看看redis slave是否立刻會成爲主節點。
最後來看一下配置完成後的web界面是什麼樣子?
在此界面中也能夠進行,組建立、將redis加入到組、刪除redis主機、設置主從同步、將從節點提高爲主節點、初始化slot等等。而且還能夠看見OPS、內存、key等性能狀況。另外能夠在web界面進行slot遷移的操做,具體能夠自行多試驗試驗。
鏈接codis-proxy代理端口便可,而後操做redis命令。
$ redis-cli -h 10.0.60.152 -p 19000 127.0.0.1:19000> set k1 v1 OK
查看zk中codis產品:
$ zkCli.sh -server 127.0.0.1:2181 [zk: 127.0.0.1:2181(CONNECTED) 1] ls /codis3/codis-demo/ proxy slots topom group
查看zk中的dashboard信息:
[zk: 127.0.0.1:2181(CONNECTED) 2] get /codis3/codis-demo/topom { "start_time": "2016-10-13 18:09:21.802793218 +0800 CST", "admin_addr": "10.0.60.152:18080", "product_name": "codis-demo", "pid": 3386, "pwd": "/usr/local/codis/src/github.com/CodisLabs/codis/extern/redis-2.8.21/src", "sys": "Linux" }
查看zk中的slot狀態:
[zk: 127.0.0.1:2181(CONNECTED) 3] ls /codis3/codis-demo/slots
前面initslots初始化的全部Slot都保存在slots路徑下,每一個Slot是一個結點。隨便選取一個Slot結點,用get命令可以查看結點上附着的數據:
[zk: 127.0.0.1:2181(CONNECTED) 4] get /codis3/codis-demo/slots/slot-0334 { "id": 334, "group_id": 1, "action": {} }
查詢zk中的server狀態:
[zk: 127.0.0.1:2181(CONNECTED) 5] get /codis3/codis-demo/group/group-0001 { "id": 1, "servers": [ { "server": "10.0.60.152:6379", "action": {} }, { "server": "10.0.60.154:6379", "action": { "state": "synced" } } ], "promoting": {} }
查詢zk中的proxy狀態:
[zk: 127.0.0.1:2181(CONNECTED) 6] ls /codis3/codis-demo/proxy/proxy- proxy-919ce168362a7286e4081b600a00ca67 proxy-cdcec3cebe703a67688bb0fc3de21f76 proxy-b87c96f0bc6d8e62f196369c66cea7c2
[zk: 127.0.0.1:2181(CONNECTED) 7] get /codis3/codis-demo/proxy/proxy-919ce168362a7286e4081b600a00ca67 { "id": 1, "token": "919ce168362a7286e4081b600a00ca67", "start_time": "2016-10-13 19:55:09.532570818 +0800 CST", "admin_addr": "10.0.60.152:11080", "proto_type": "tcp4", "proxy_addr": "10.0.60.152:19000", "product_name": "codis-demo", "pid": 4532, "pwd": "/usr/local/codis/src/github.com/CodisLabs/codis/extern/redis-2.8.21/src", "sys": "Linux" }
要是想系統重作,刪除此產品便可:rmr /codis3/codis_demo。
使用codis-admin命令行管理工具進行修復。
當codis-dashboard啓動時,會在外部存儲上存放一條數據,用於存儲 dashboard 信息,同時做爲LOCK存在。當codis-dashboard安全退出時,會主動刪除該數據。
當codis-dashboard異常退出時(大多數狀況zookeeper鏈接異常時會異常退出),因爲以前LOCK未安全刪除,重啓每每會失敗。所以codis-admin提供了強制刪除工具:
一、確認codis-dashboard進程已經退出(很重要);
二、而後運行codis-admin刪除LOCK:
codis-admin --remove-lock --product=codis_demo --zookeeper=127.0.0.1:2181
或者刪除topom
[zk: 127.0.0.1:2181(CONNECTED) 13] rmr /codis3/codis-demo/topom
正常關閉codis-dashboard:
codis-admin --dashboard=10.0.60.152:18080 --shutdown
一般codis-proxy都是經過codis-dashboard進行移除,移除過程當中codis-dashboard爲了安全會向codis-proxy發送offline指令,成功後纔會將proxy 信息從外部存儲中移除。若是codis-proxy異常退出,該操做會失敗。此時可使用codis-admin工具進行移除:
一、確認codis-proxy進程已經退出(很重要);
二、運行codis-admin刪除proxy,首先查看proxy狀態:
codis-admin --dashboard=10.0.60.152:18080 --proxy-status
或用
codis-admin --dashboard=10.0.60.152:18080 --list-proxy
根據查看到的信息,強制刪除報錯的codis-proxy。
codis-admin --dashboard=10.0.60.152:18080 --remove-proxy --token=6a2db3c9ac07ba8857d4bc79ca6d191c --force
codis-admin --dashboard=10.0.60.152:18080 --remove-proxy --addr=127.0.0.1:11080 --force
選項–force表示,不管offline操做是否成功,都從外部存儲中將該節點刪除。因此操做前,必定要確認該codis-proxy進程已經退出。
codis-proxy正常關閉
codis-admin --proxy=10.0.60.152:11080 --auth="xxxxx" --shutdown
參考:https://github.com/CodisLabs/jodis/issues/10
安全和透明的數據遷移是Codis提供的一個重要的功能,也是Codis區別於Twemproxy等靜態的分佈式Redis解決方案的地方。
數據遷移的最小單位是key,咱們在codis redis中添加了一些指令,實現基於key的遷移,如SLOTSMGRT等 (命令列表),每次會將特定slot一個隨機的key 發送給另一個codis redis實例,這個命令會確認對方已經接收,同時刪除本地的這個k-v 鍵值,返回這個slot的剩餘key的數量,整個操做是原子的。
遷移的過程對於上層業務來講是安全且透明的,數據不會丟失,上層不會停止服務。
注意,遷移的過程當中打斷是能夠的,可是若是中斷了一個正在遷移某個slot的任務,下次須要先遷移掉正處於遷移狀態的slot,不然沒法繼續 (即遷移程序會檢查同一時刻只能有一個slot處於遷移狀態)。
由於codis-proxy是無狀態的,能夠比較容易的搭多個實例,達到高可用性和橫向擴展。對Java用戶來講,可使用基於Jedis的實現Jodis,來實現proxy層的HA:
對於其餘語言,可使用haproxy代理到後端的多個codis-proxy,達到負載均衡的做用。而haproxy的單點問題可使用keepalive作HA,這樣就能夠實現一個高可用高併發的codis-proxy了。
Codis Dashboard:集羣管理工具,支持codis-proxy、codis-serve的添加、刪除,以及數據遷移等操做。在集羣狀態發生改變時,codis-dashboard 維護集羣下全部codis-proxy的狀態的一致性。
但須要注意的是對於同一個業務集羣而言,同一個時刻codis-dashboard只能有0個或者1個。另外全部對集羣的修改都必須經過codis-dashboard完成。因爲自己的限制,codis-dashboard沒法作到高可用。也就是說若是你集羣中的codis-dashboard掛掉了,那麼你將沒法對集羣作出更改操做,另外你的codis-fe界面也會異常(獲取不到數據),但值得慶幸的是此時你的codis-集羣對外服務不會出現任何問題。你須要作的就是去集羣中的其餘節點開啓codis-dashboard便可,此時會從新去zookeeper中註冊信息,集羣操做不會有任何問題,因此也沒必要太擔憂codis-dashboard掛掉了,只須要作好監控及時報警便可。
另外,此時的codis-fe須要更改一下配置文件,也就是把codis-dashboard的地址更換爲新的codis-dashboard主機便可;而後從新啓動codis-fe,此時整個codis集羣又恢復了最初的完整性,期間不會對客戶端鏈接形成任何影響。
對下層的redis實例來講,當一個group的master掛掉的時候,應該讓管理員清楚,並手動的操做,由於這涉及到了數據一致性等問題(redis的主從同步是最終一致性的)。所以codis不會自動的將某個slave升級成master。關於外部codis-ha工具(具體能夠參考以前的章節),這是一個經過codis-dashboard開放的RESTful API實現自動切換主從的工具。該工具會在檢測到master掛掉的時候主動應用主從切換策略,提高單個slave成爲新的master。
須要注意,codis將其中一個slave升級爲master時,該組內其餘slave實例是不會自動改變狀態的,這些slave仍將試圖從舊的master上同步數據,於是會致使組內新的master和其餘slave之間的數據不一致。所以當出現主從切換時,須要管理員手動建立新的sync action來完成新master與slave之間的數據同步(codis-ha不提供自動操做的工具,由於這樣太不安全了)。
默認狀況下,codis-fe圖形化界面沒有任何安全措施,任何人只要知道地址均可以登陸操做codis集羣。此時你能夠藉助nginx/Apache的訪問控制來進行codis-fe訪問控制。提升codis-fe安全性。
標準多codis實例目錄
# proxy_19000; $ mkdir -p /data/codis/proxy_19000/bash $ mkdir -p /data/codis/proxy_19000/conf $ mkdir -p /data/codis/proxy_19000/log $ mkdir -p /data/codis/proxy_19000/run # proxy_19001; $ mkdir -p /data/codis/proxy_19001/bash $ mkdir -p /data/codis/proxy_19001/conf $ mkdir -p /data/codis/proxy_19001/log $ mkdir -p /data/codis/proxy_19001/run
而後在各自的實例的/data/codis/proxy_19001/bash/目錄下添加如下腳本便可。
一、start_dashboard.sh
#!/bin/bash # nohup codis-dashboard --ncpu=2 --config=../conf/dashboard.toml --log=../log/dashboard.log --log-level=WARN &
二、add_group.sh
#!/bin/bash # # create group; codis-admin --dashboard=10.0.60.152:18080 --create-group --gid=1 codis-admin --dashboard=10.0.60.152:18080 --create-group --gid=2 # add host; codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=1 --addr=10.0.60.152:6379 codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=1 --addr=10.0.60.154:6379 codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=2 --addr=10.0.60.153:6380 codis-admin --dashboard=10.0.60.152:18080 --group-add --gid=2 --addr=10.0.60.154:6380 # configuration maser/slave; codis-admin --dashboard=10.0.60.152:18080 --sync-action --create --addr=10.0.60.154:6379 codis-admin --dashboard=10.0.60.152:18080 --sync-action --create --addr=10.0.60.154:6380
三、start_proxy.sh
#!/bin/bash # nohup codis-proxy --ncpu=2 --config=../conf/proxy.toml --log=../log/proxy.log --log-level=WARN &
四、start_fe.sh
#!/bin/bash # nohup `which codis-fe` --ncpu=2 --log=../log/fe.log --log-level=WARN --dashboard-list=../conf/codis.json --listen=0.0.0.0:8080 &
五、initslot.sh
codis-admin --dashboard=10.0.60.152:18080 --slot-action --create-range --beg=0 --end=511 --gid=1 codis-admin --dashboard=10.0.60.152:18080 --slot-action --create-range --beg=512 --end=1023 --gid=2
注意按照順序依次啓動便可。因爲codis一旦跟zookeeper鏈接出現異常後codis-proxy就會異常退出,因此須要寫一個計劃任務監控腳本當codis_proxy異常退出時就報警而且自動拉起來。
#!/bin/bash IP=10.0.60.152 PORT="19000 190001" TIME=`date +%Y-%m-%d-%H-%M` for port in $PORT;do ps aux | grep -v grep | grep $port | grep codis-proxy &> /dev/null ret=$? if [ $ret -eq 0 ]; then echo "$TIME codis ${IP}:${port} is exist !" >> /data/codis/proxy_${port}/log/codis.log else msg="$TIME codis ${IP}:${port} is down!" /usr/bin/curl http://10.0.8.51:8888/sms/send -d "from=1000&to=15210491149&msg=$msg" echo "$TIME codis ${IP}:${port} is not exist !" >> /data/codis/proxy_${port}/log/codis.log cd /data/codis/proxy_${port}/bash sh start_proxy.sh > /dev/null 2>&1 sleep 2 sh set_proxy_online.sh > /dev/null 2>&1 sleep 2 fi done
完結。
爲了方便你們交流,本人開通了微信公衆號(關注看更多精彩)和QQ羣,QQ羣1(291519319)和QQ羣2(659336691)。喜歡技術的一塊兒來交流吧