您好,登錄后才能下訂單哦!
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-dashboard和zookeeper一起控制,不需要手工填寫.
codis-dashboard:集群管理工具,支持 codis-proxy、codis-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地址來實現高可用的LVS和HA功能.
代理層:中間層由codis-proxy和zookeeper處理數據走向和分配,通過crc32算法,把key平均分配在不同redis的某一個slot中.實現類似raid0的條帶化,在舊版本的codis中,slot需要手工分配,在codis3.2之后,只要點一個按鈕slot會自動分配,相當方便,但是也可以手動分配,需要另外調用codis-admin命令.
數據層:最后codis-proxy把數據存進真實的redis-server主服務器上,由于codis的作者黃東旭相當注重數據一致性,不允許有數據延時造成的數據不一致,所以架構從一開始就沒考慮主從讀寫分離.從服務器僅僅是作為故障切換的冗余架構,由codis-dashboard監控各服務的狀態,然后通過改寫zookeeper數據和調用redis-sentinel實現故障切換功能.
3.因為機器有限,部署的架構如下:
zookeeper集群:
10.0.2.5:2181
10.0.2.6:2181
10.0.2.7:2181
codis-config和codis-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.7或1.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.cfg的server.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=B:C:D:其中 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-dashboard的ip和端口就可以了,但是我為了方便管理,還是生成一個配置文件的好.
#生成一下配置文件,其實也就是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無限制,其實最好是限制內網
驗證一下
全套安裝完成,成功啟動.開始下一步.
使用舉例
因為有了web界面,基本上就都是界面操作了,非常方便,配置會直接加載到zookeeper里面去.
首先,我們先添加codis-proxy地址和端口
按順序:
第一步,先添加codis-proxy的地址和管理端口,上面設置的是11080.
第二步,點擊左方的橙色按鈕,然后就添加完畢.
第三步,看到下方出現該有的codis-proxy地址就算完成了,然后看到右方的SYNC字樣的顏色是綠色,則代表配置正常.
如果要刪除記錄,點擊最右方的紅色按鈕即可.
然后,我們添加真實redis-server(也是codis-server)地址和端口
按順序:
第一步,先創建一個組,準備把相關的一組主從放進去
第二步,點擊按鈕生成這個分組
第三步,添加真實redis-server地址,并選定一個分組,例如剛才創建的分組1
第四步,點擊按鈕生成配置
第五步,可以看到配置已經登記好,注意sync狀態.
第六步,點擊重新平衡所有slots數據塊(任何添加和刪除新舊節點都需要點擊這個)
在舊版本中slots需要手動配置,但是3.2版本之后就改成自動分配了,所以已經不需要配置,點擊一下就可以了.當然你也可以手動去分配.
最后配置sentinel的地址和端口
按順序:
第一步,添加真實的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 顯示模式:簡要模式
然后看圖
可以看到,有些操作相差不大,有些相差甚遠,性能損耗明顯,不過作為集群應用,主要應對的是高并發環境,性能損耗是可以接受的,何況對于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-proxy用info來看,其實是不準確的,那個顯示的只是單臺的數據.
可以看到,每一個組都分布得比較均勻,把壓力都分到三臺redis-server主服務器去了.
3.故障切換測試
然后來看故障切換,繼續執行那個腳本
bash t-redis.sh
進入其中一臺codis-server,例如10.0.2.5,此時狀態是正常的.
開始模擬操作
#查找主庫進程 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有提示信息.
可能有人發現組1的sync按鈕變成了紅色,也就是說主從失效,點一下就變回正常.
現在等待數據寫完,我先把舊的主進程6379端口從新起來
/usr/local/codis/codis-server /data/redis/data/config/redis_6379.conf
然后看看:
看狀態是恢復正常了,但是有計算機的同學可以算一下,我的腳本執行的總共是30萬個key,但是現在少了幾千個.
坑---1:
上面丟key的問題是由于redis-sentinel故障切換期間,整個codis集群并不會關閉對此故障redis-server的連接,所以codis-proxy依然會發送數據給當前故障的redis-server,而顯然此時的redis-server是無法存儲數據的,這就造成了丟key現象了.如果整個主從掛了,就會丟掉所有發送到此redis-server的key了,除非手工剔除故障節點.
雖然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界面添加配置才行.
顯然這是做不到全自動管理,有點麻煩了,而且也會讓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.添加一個節點,等于是擴容,這還是比較簡單
第一步,和之前差不多,先創建一個新組,點擊按鈕確認添加
第二步,把新地址添加到新的組,點擊按鈕確認添加
第三步,確認新的地址已成功添加進去
第四步,點擊按鈕,從新分配所有slots數據塊
這里唯一問題就是最后一步,重新分配會耗費一定資源,codis會自動平衡數據塊的分布,所以會有數據遷移過程,但是據我測試的結果來看,并不很嚴重,大概在20%左右.
根據它自帶的監控來看的話,
可以看到之前正常情況的qps接近1500,剛點重新平衡下降比較嚴重一些,后面就大概有20%的性能損耗那樣子,最后遷移完畢就恢復正常了.當然這是數據量少的情況,如果數據量多,這個遷移時間就恐怕不是那么簡單了.
2.切換一個節點,并下架
正常下架只需要點擊這個按鈕
但是因為里面還有數據,是不允許直接下架的
所以我們要先遷移數據,如下所示:
第一步,確認一個需要遷移的組的數據塊的編號,例如這里499-512的塊是數據組4的,我現在要遷移組4,就選定這個
第二步,把剛才獲取到的信息填進去,就是把500這個編號的數據塊從組4遷移到組5,點擊按鈕執行
然后你就會看到,
顯然組4的信息消失了,codis把組4的數據塊都遷移到了組5去了,
這個時候,這個redis-server節點就可以刪除了
至于還需不需要重新填補,這個問題則需要自身考慮.如果不需要填補,最好再點一下重新平衡slots比較好.
可以看到,又重新平衡了.
故障處理
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 Type | Command Name |
---|---|
Keys | KEYS |
MIGRATE | |
MOVE | |
OBJECT | |
RANDOMKEY | |
RENAME | |
RENAMENX | |
SCAN | |
Strings | BITOP |
MSETNX | |
Lists | BLPOP |
BRPOP | |
BRPOPLPUSH | |
Pub/Sub | PSUBSCRIBE |
PUBLISH | |
PUNSUBSCRIBE | |
SUBSCRIBE | |
UNSUBSCRIBE | |
Transactions | DISCARD |
EXEC | |
MULTI | |
UNWATCH | |
WATCH | |
Scripting | SCRIPT |
Server | BGREWRITEAOF |
BGSAVE | |
CLIENT | |
CONFIG | |
DBSIZE | |
DEBUG | |
FLUSHALL | |
FLUSHDB | |
LASTSAVE | |
MONITOR | |
RESTORE | |
SAVE | |
SHUTDOWN | |
SLAVEOF | |
SLOWLOG | |
SYNC | |
TIME | |
Codis Slot | SLOTSCHECK |
SLOTSDEL | |
SLOTSINFO | |
SLOTSMGRTONE | |
SLOTSMGRTSLOT | |
SLOTSMGRTTAGONE | |
SLOTSMGRTTAGSLOT |
以下屬于半支持命令, Codis不支持跨節點操作,因此您必須使用散列標簽將可能顯示在一個請求中的所有密鑰放入同一個插槽中,然后您可以使用這些命令。 Codis不檢查密鑰是否有相同的標簽,所以如果你不使用標簽,你的程序會得到錯誤的回應。
Command Type | Command Name |
---|---|
Lists | RPOPLPUSH |
Sets | SDIFF |
SINTER | |
SINTERSTORE | |
SMOVE | |
SUNION | |
SUNIONSTORE | |
Sorted Sets | ZINTERSTORE |
ZUNIONSTORE | |
HyperLogLog | PFMERGE |
Scripting | EVAL |
EVALSHA |
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。