对于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)。喜欢技术的一块儿来交流吧