Codis 2介绍
对于Redis集群方案有好多种,基本常用的就是twemproxy,codis、redis cluster这三种解决方案,本人有幸工作中都大量使用过,各有利有弊,下面这篇文章详解讲解一下豌豆尖的Codis 2,主要是之前有部分业务使用Codis 2,所以这里也说一下。如果你是新业务那么建议直接使用Codis 3,我也写有Codis 3集群搭建。Codis总体来说还算不错,仅供大家学习和参考。
Codis是一个分布式Redis解决方案,对于上层的应用来说,连接到Codis Proxy和连接原生的Redis Server没有明显的区别 (不支持的命令列表),上层应用可以像使用单机的Redis一样使用,Codis底层会处理请求的转发,不停机的数据迁移等工作,所有后边的一切事情,对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的Redis服务。
Codis 2.x由四部分组成:
- Codis Proxy (codis-proxy)
- Codis Dashboard (codis-config)
- Codis Redis (codis-server)
- ZooKeeper/Etcd
codis-proxy : 是客户端连接的Redis代理服务,codis-proxy本身实现了Redis协议,表现得和一个原生的Redis没什么区别(就像Twemproxy),对于一个业务来说,可以部署多个codis-proxy,codis-proxy本身是没状态的。
codis-config :是Codis的管理工具,支持包括,添加/删除Redis节点,添加/删除Proxy节点,发起数据迁移等操作,codis-config本身还自带了一个http server,会启动一个dashboard,用户可以直接在浏览器上观察Codis集群的状态。
codis-server:是Codis项目维护的一个Redis分支,基于2.8.13开发,加入了slot的支持和原子的数据迁移指令,Codis上层的codis-proxy和codis-config只能和这个版本的Redis交互才能正常运行。
ZooKeeper :用来存放数据路由表和codis-proxy节点的元信息,codis-config发起的命令都会通过ZooKeeper同步到各个存活的codis-proxy。
PS: Codis支持按照Namespace区分不同的产品,拥有不同的product name 的产品,各项配置都不会冲突。
安装配置Codis 2集群
此次试验服务部署架构方式如下:
1 2 3 4 5 6 |
10.0.60.152 zookeeper codis-proxy codis-dashboard redis(master) redis(slave) |
此次试验用到的软件及版本如下:
system:CentOS 6/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:2.0版本(https://github.com/CodisLabs/codis/archive/3.0.3.zip)
安装参考文档:https://github.com/CodisLabs/codis/blob/release2.0/doc/tutorial_zh.md
1、安装配置zookeeper
Zookeeper分布式服务框架,是Apache Hadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。Codis依赖zookeeper才能协同工作。
首先安装开发工具及openjdk,zookeeper是由Java语言开发的,所以需要openjdk环境。
1 2 3 |
$ yum groupinstall "Development tools" "Compatibility libraries" -y $ yum install openssl-devel openssl git -y $ yum install java-1.8.0-openjdk-devel java-1.8.0-openjdk -y |
确定Java运行环境正常
1 2 3 4 |
$ 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
1 2 3 4 |
$ 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
1 2 3 4 5 6 7 8 9 10 11 |
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 |
1 |
$ mkdir /data/zookeeper/{db,log} -p |
然后输出环境变量。
1 2 3 4 |
$ cat /etc/ #!/bin/bash # export PATH=$PATH:/usr/local/zookeeper/bin/ |
1 |
$ source /etc/profile.d/zk.sh |
然后就可以启动zookeeper了。
1 |
$ zkServer.sh start |
查看各个zookeeper节点的状态(只有一个节点,所以是standalone,如果是集群那么会有一个leader节点,两个follower节点)。
1 2 |
$ zkServer.sh status Mode: standalone |
客户端连接,可以查看相关信息。
1 |
$ zkCli.sh -server 127.0.0.1:2181 |
至此,zookeeper已经搞定了。
2、go安装(codis是go语言写的,所以这些机器需要安装go环境)
首先下载go二进制安装包
https://golang.org/doc/install?download=go1.5.2.linux-amd64.tar.gz
官方界面介绍了如何安装GO运环境,对于GO运行环境来说,有一些特定的GOROOT和GOPATH环境变量需要设置,这是必须的,不然无法运行go程序。这里最好安装go1.5.2版本,不然后面编译Codis有些小问题。
1 |
$ tar xvf go1.5.2.linux-amd64.tar.gz -C /usr/local |
解压完成后,GO就安装完了,下面设置一个GOPATH目录,其实就是go程序运行目录。
1 |
$ mkdir /usr/local/codis |
然后就可以设置GO需要的环境变量,路径看好,千万别搞错了。
1 2 3 4 5 6 |
$ 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
1 2 |
$ chmod a+x /etc/profile.d/go.sh $ source /etc/profile.d/go.sh |
查看GO版本
1 2 |
$ go version go version go1.5.2 linux/amd64 |
3、下载并编译安装codis 2
这里我们主要是要安装Codis 2,需要注意的是Codis安装目录必须是固定的格式,不然会有问题。下面命令的大概意思就是先创建固定目录,然后进入到此目录后就去下载codis 2的安装包,最后进行编译和测试。
1 2 3 4 5 |
$ mkdir $GOPATH/src/github.com/CodisLabs/ $ cd $GOPATH/src/github.com/CodisLabs/ $ git clone https://github.com/CodisLabs/codis.git -b release2.0 $ make $ make gotest |
执行全部指令后,会在bin文件夹内生成codis-config、codis-proxy、codis-server三个可执行文件。另外, bin/assets文件夹是codis-config的dashboard http服务需要的前端资源, 需要和codis-config放置在同一文件夹下)
1 2 3 4 5 6 |
$ ll bin/ total 38812 drwxr-xr-x. 4 root root 4096 Oct 14 16:26 assets -rwxr-xr-x. 1 root root 16826104 Oct 14 16:26 codis-config -rwxr-xr-x. 1 root root 16596648 Oct 14 16:26 codis-proxy -rwxr-xr-x. 1 root root 6312973 Oct 14 16:27 codis-server |
输出Codis执行文件,添加最后一行PATH变量。
1 2 3 4 5 6 7 8 |
$ 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/ |
1 |
$ source /etc/profile.d/go.sh |
至此,Codis安装完成。但需要注意的是,如果你是用golang 1.5 beta3以上的版本进行编译,还有可能出现的一个问题是:
1 2 3 4 |
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里面的方案解决。最简单就是在编译前
1 |
export GO15VENDOREXPERIMENT=0 |
5、为Codis创建标准目录
Codis安装完成后,就可以为Codis创建一些标准的目录,用来存储Codis的脚本目录、配置文件目录、日志目录、PID目录、Redis配置目录等。
1 2 3 4 5 6 7 8 9 |
$ 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 $ mkdir -p /data/codis/redis/redis-6381 $ mkdir -p /data/codis/redis/redis-6382 |
复制Codis自带的redis-2.8.21相关工具到标准目录中。
1 2 |
$ 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/ |
添加环境变量
1 2 3 4 5 6 7 8 9 |
$ 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 |
1 |
$ source /etc/profile.d/go.sh |
以上工作都完成之后,下面就可以启动并配置Codis了,大致顺序如下:
1)启动redis实例;
2)启动codis-dashboard;
3)把redis实例添加到codis组中;
4)初始化slot;
5)启动codis-proxy;
6)online codis-proxy;
这只是一个参考,有些顺序不是必须的,但启动dashboard前,必须启动zookeeper服务,这是必须的,后面有很多操作,都可以在web页面完成,例如添加/删除组,添加/删除redis实例等。
6、配置启动Codis各组件—-启动Redis
考虑到性能,主库关闭aof和rdp,从库只开启aof即可。下面这份配置就是生产环境中的配置,具体的含义可以看本博客的Redis生产环境配置文件详解章节。
主库:/data/codis/redis/redis-6379/redis.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
###基本参数### 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
###基本参数### 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 |
可以使用同样配置文件再启动一组redis主从,端口可以需要修改为6381、6382即可。
可以使用codis-server启动redis了。
1 2 3 4 |
$ codis-server /data/codis/redis/redis-6379/redis.conf $ codis-server /data/codis/redis/redis-6380/redis.conf $ codis-server /data/codis/redis/redis-6381/redis.conf $ codis-server /data/codis/redis/redis-6382/redis.conf |
7、配置启动Codis各组件—-启动dashboard(启动集群中某一个节点)
下面就要使用到codis的第一个程序codis-config,它能够完成codis集群的大部分操作,如dashboard启动、redis管理、slot管理等。codis 3中这个程序已经消失了,先看一下codis-config怎么使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ codis-config --help options: -c #配置文件地址; -L #日志输出文件地址; --log-level=<loglevel> #输出日志级别(debug < info (default) < warn < error < fatal); commands: server #redis服务器组管理; slot #slot管理; dashboard #启动dashboard服务; action #事件管理(目前只有删除历史事件的日志); proxy #proxy管理; |
首先标准化codis-dashboard配置文件目录:
1 |
$ cp /usr/local/codis/src/github.com/CodisLabs/codis/config.ini /data/codis/conf/config.ini |
修改配置文件参数如下:
1 2 3 4 5 6 7 8 9 10 11 |
coordinator=zookeeper zk=10.0.60.144:2181 product=test dashboard_addr=10.0.60.144:18087 password= backend_ping_period=5 session_max_timeout=1800 session_max_bufsize=131072 session_max_pipeline=1024 zk_session_timeout=30000 proxy_id=proxy_1 |
参数解释:
zk:指定zookeeper的地址,如果是zookeeper集群,多个地址之间使用逗号分隔。
product:指定产品名称,这个codis集群的名字,可以认为是命名空间,不同命名空间的codis没有交集。
dashboard_addr:dashboard服务的地址,CLI的所有命令都依赖于dashboard的RESTful API,所以必须启动。
password:集群节点之间的认证密码,默认为空。
backend_ping_period
session_max_timeout:会话最大超时时间。
session_max_bufsize:会话最大缓冲大小。
session_max_pipeline
zk_session_timeout:zookeeper的连接会话超时时间。
proxy_id:指定proxy的名称,proxy会读取, 用于标记proxy的名字, 针对多个proxy的情况, 可以使用不同的config.ini, 只需要更改proxy_id 即可。
启动codis-dashboard
1 |
$ nohup `which codis-config` -c /data/codis/conf/config.ini -L /data/codis/log/dashboard.log dashboard --addr=:18087 --http-log=/data/codis/log/requests.log & |
这里需要注意一下,启动codis-dashboard必须使用全路径,因为需要找前端资源,不然web界面是无法访问的。
8、添加Redis Server Group(codis-config操作)
添加Redis Server Group , 每一个Server Group作为一个Redis服务器组存在,只允许有一个master, 可以有多个slave,group id仅支持大于等于1的整数。下面我们添加两组Redis主从。
1 2 |
$ codis-config -c /data/codis/conf/config.ini server add 1 10.0.60.144:6379 master $ codis-config -c /data/codis/conf/config.ini server add 1 10.0.60.144:6380 slave |
1 2 |
$ codis-config -c /data/codis/conf/config.ini server add 2 10.0.60.144:6381 master $ codis-config -c /data/codis/conf/config.ini server add 2 10.0.60.144:6382 slave |
9、初始化slot(codis-config操作)
设置server group服务的slot范围Codis采用Pre-sharding的技术来实现数据的分片,默认分成1024个slots (0-1023),对于每个key来说,通过以下公式确定所属的Slot Id : SlotId = crc32(key) % 1024每一个slot都会有一个特定的server group id来表示这个slot的数据由哪个server group来提供。(codis-config上操作)
1 2 3 |
$ codis-config -c /data/codis/conf/config.ini slot init -f $ codis-config -c /data/codis/conf/config.ini slot range-set 0 511 1 online $ codis-config -c /data/codis/conf/config.ini slot range-set 512 1023 1 online |
注意编号设置不能超过1023,,不然会报错。另外,如果你有2个组,那么设置编号应该为[0, 511]的slot由server group 1提供服务,编号[512, 1023]的slot由server group 2提供服务。
10、启动codis-proxy(codis-proxy操作)
1 |
$ nohup codis-proxy -c /data/codis/conf/config.ini -L /data/codis/log/proxy.log --cpu=4 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 & |
参数解释:
-c:配置文件地址。
-L:日志输出文件地址。
–log-level=<loglevel>:输出日志级别 (debug < info (default) < warn < error < fatal)。
–cpu=<cpu_num>:proxy占用的cpu核数,默认1,最好设置为机器的物理cpu数的一半到2/3左右。
–addr=<proxy_listen_addr>:proxy的redis server监听的地址,格式<ip or hostname>:<port>,如: localhost:9000,:9001。
–http-addr=<debug_http_server_addr>:proxy的调试信息启动的http server,可以访问http://debug_http_server_addr/debug/vars。
至此,整个集群就搭建成功了,在生产环境中一般最少会启动两个codis-proxy,也很简单,在另外一个节点中把config.ini配置文件中的proxy_id参数修改成唯一值,然后启动codis-proxy即可。如下演示(本机启动codis-proxy,端口为19001):
1 |
$ cp /data/codis/conf/config.ini /data/codis/conf/config-2.ini |
修改config-2.ini配置文件参数如下:
1 2 3 4 5 6 7 8 9 10 11 |
coordinator=zookeeper zk=10.0.60.144:2181 product=test dashboard_addr=10.0.60.144:18087 password= backend_ping_period=5 session_max_timeout=1800 session_max_bufsize=131072 session_max_pipeline=1024 zk_session_timeout=30000 proxy_id=proxy_2 |
在配置文件中最需要注意两点:
第一点:就是dashboard_addr地址,这个是填写dashboard的地址,在一个codis集群中只能开启一个dashboard,所以这个地址只是集群中的某一个地址(开启dashboard服务器的地址)。我这里只是为了演示效果所以把两个proxy都放在同一台机器上,生产中这两个节点必然是在不同的机器上,一般第二个codis节点配置不需要开启dashboard,也不需要做添加Redis Server Group和初始化slot,只需要启动codis-proxy即可,而config.ini配置文件一般跟第一个开启codis的config.ini相同。
第二点:就是proxy_id在一个集群中,每个节点的proxy_id都必须不一样。
启动proxy_2的codis-proxy,端口修改为了19001。
1 |
$ nohup codis-proxy -c /data/codis/conf/config-2.ini -L /data/codis/log/proxy.log --cpu=4 --addr=0.0.0.0:19001 --http-addr=0.0.0.0:11001 & |
11、测试codis
通过代理端口19000插入数据,然后到redis主节点取出数据即可。
1 2 3 4 5 6 7 8 9 10 11 |
$ redis-cli -p 19000 127.0.0.1:19000> set k1 v2 OK $ redis-cli -p 6379 127.0.0.1:6379> get k1 "v2" $ redis-cli -p 6380 127.0.0.1:6380> get k1 "v2" |
13、访问web界面
现在可以通过:http://10.0.60.144:18087/admin/访问web界面了,集群效果如下图:
在web界面可以进行proxy添加,组创建,主从切换,数据迁移等工作。
Zookeeper相关操作
查看zk中codis产品:
1 2 3 |
$ zkCli.sh -server 127.0.0.1:2181 [zk: 127.0.0.1:2181(CONNECTED) 1] ls /zk/codis/db_test [proxy, slots, servers, LOCK, migrate_tasks, actions, fence, dashboard, ActionResponse] |
查看zk中的dashboard信息:
1 2 |
[zk: 127.0.0.1:2181(CONNECTED) 2] get /zk/codis/db_test/dashboard {"addr": "10.0.60.144:18087", "pid": 37528} |
查看zk中的slot状态:
1 |
[zk: 127.0.0.1:2181(CONNECTED) 3] ls /zk/codis/db_test/slots |
前面initslots初始化的所有Slot都保存在slots路径下,每个Slot是一个结点。随便选取一个Slot结点,用get命令能够查看结点上附着的数据:
1 2 |
[zk: 127.0.0.1:2181(CONNECTED) 4] get /zk/codis/db_test/slots/slot_990 {"product_name":"test","id":990,"group_id":1,"state":{"status":"online","migrate_status":{"from":-1,"to":-1},"last_op_ts":"0"}} |
查询zk中的server状态:
1 2 |
[zk: 127.0.0.1:2181(CONNECTED) 6] ls /zk/codis/db_test/servers [group_1, group_2] |
1 2 3 4 |
[zk: 127.0.0.1:2181(CONNECTED) 7] get /zk/codis/db_test/servers/group_1/10.0.60.144:6379 {"type":"master","group_id":1,"addr":"10.0.60.144:6379"} [zk: 127.0.0.1:2181(CONNECTED) 7] get /zk/codis/db_test/servers/group_1/10.0.60.144:6379 {"type":"slave","group_id":1,"addr":"10.0.60.144:6380"} |
查询zk中的proxy状态:
1 2 3 |
[zk: 127.0.0.1:2181(CONNECTED) 11] get /zk/codis/db_test/proxy/proxy_1 {"id":"proxy_1","addr":"codis:19000","last_event":"","last_event_ts":0,"state":"online","description":"", "debug_var_addr":"codis:11000","pid":37615,"start_at":"2016-10-17 10:59:28.734899131 +0800 CST"} |
如果要是想整个codis系统重做,删除此产品即可:rmr /zk/codis/db_test。
Codis常见问题修复
使用codis-admin命令行管理工具进行修复。
1)codis-dashboard异常退出的修复
当codis-dashboard启动时,会在外部存储上存放一条数据,用于存储 dashboard 信息,同时作为LOCK存在。当codis-dashboard安全退出时,会主动删除该数据。
当codis-dashboard异常退出时(大多数情况zookeeper连接异常时会异常退出),由于之前LOCK未安全删除,重启往往会失败。因此需要手动删除zookeeper信息。
1、确认codis-dashboard进程已经退出(很重要);
2、手动删除zookeeper信息;
1 |
[zk: 127.0.0.1:2181(CONNECTED) 1] rmr /zk/codis/db_test/dashboard |
2)codis-proxy异常退出的修复
通常codis-proxy都是通过codis-dashboard进行移除,移除过程中codis-dashboard为了安全会向codis-proxy发送offline指令,成功后才会将proxy信息从外部存储(zookeeper)中移除。如果codis-proxy异常退出,该操作会失败。此时需要手动删除zookeeper信息。
1、确认codis-proxy进程已经退出(很重要);
2、删除zookeeper信息;
1 |
[zk: 127.0.0.1:2181(CONNECTED) 1] rmr /zk/codis/db_test/proxy |
3)jodis连接proxy显示Proxy list is empty问题处理
参考:https://github.com/CodisLabs/jodis/issues/10
codis-proxy高可用问题?
因为codis-proxy是无状态的,可以比较容易的搭多个实例,达到高可用性和横向扩展。对Java用户来说,可以使用基于Jedis的实现Jodis,来实现proxy层的HA:
- 它会通过监控zookeeper上的注册信息来实时获得当前可用的proxy列表,既可以保证高可用性;
- 也可以通过轮流请求所有的proxy实现负载均衡。
对于其他语言,可以使用haproxy代理到后端的多个codis-proxy,达到负载均衡的作用。而haproxy的单点问题可以使用keepalive做HA,这样就可以实现一个高可用高并发的codis-proxy了。
Redis高可用问题?
对下层的redis实例来说,当一个group的master挂掉的时候,应该让管理员清楚,并手动的操作,因为这涉及到了数据一致性等问题(redis的主从同步是最终一致性的)。因此codis不会自动的将某个slave升级成master。关于外部codis-ha工具(https://github.com/ngaut/codis-ha,测试发现已经不不在支持新Codis 2.0版本,新版Codis 2.0有些目录变了,但Codis 3.0已经集成了codis-ha),这是一个通过codis-dashboard开放的RESTful API实现自动切换主从的工具。该工具会在检测到master挂掉的时候主动应用主从切换策略,提升单个slave成为新的master。
需要注意,codis将其中一个slave升级为master时,该组内其他slave实例是不会自动改变状态的,这些slave仍将试图从旧的master上同步数据,因而会导致组内新的master和其他slave之间的数据不一致。因此当出现主从切换时,需要管理员手动创建新的sync action来完成新master与slave之间的数据同步(codis-ha不提供自动操作的工具,因为这样太不安全了)。
数据迁移
安全和透明的数据迁移是Codis提供的一个重要的功能,也是Codis区别于Twemproxy等静态的分布式Redis解决方案的地方。
数据迁移的最小单位是key,我们在codis redis中添加了一些指令,实现基于key的迁移,如SLOTSMGRT等 (命令列表),每次会将特定slot一个随机的key 发送给另外一个codis redis实例,这个命令会确认对方已经接收,同时删除本地的这个k-v 键值,返回这个slot的剩余key的数量,整个操作是原子的。
在codis-config管理工具中,每次迁移任务的最小单位是slot。
如: 将slot id为[0-511]的slot的数据,迁移到server group 2上,–delay参数表示每迁移一个key后sleep的毫秒数,默认是0,用于限速。
1 |
$ codis-config slot migrate 0 511 2 --delay=10 |
迁移的过程对于上层业务来说是安全且透明的,数据不会丢失,上层不会中止服务。
注意,迁移的过程中打断是可以的,但是如果中断了一个正在迁移某个slot的任务,下次需要先迁移掉正处于迁移状态的slot,否则无法继续 (即迁移程序会检查同一时刻只能有一个slot处于迁移状态)。
Auto Rebalance
Codis支持动态的根据实例内存,自动对slot进行迁移,以均衡数据分布。
1 |
$ codis-config slot rebalance |
要求:
所有的codis-server都必须设置了maxmemory参数。
所有的slots都应该处于online状态,即没有迁移任务正在执行。
所有server group都必须有Master。
Codis相关脚本
标准多codis实例目录
1 2 3 4 5 6 7 8 9 10 11 |
# 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/目录下添加以下脚本即可。
1、start_dashboard.sh
1 2 3 |
#!/bin/bash # nohup `which codis-config` -c ../conf/config.ini -L ../log/dashboard.log dashboard --addr=:18087 --http-log=/data/codis/proxy_19000/log/requests.log & |
2、add_group.sh
1 2 3 4 5 6 7 8 9 |
#!/bin/sh # echo "add group 1 with a master(10.0.60.144:6379), Notice: use in produciton" `which codis-config` -c ../conf/config.ini -L ../log/config.log server add 1 10.0.60.144:6379 master `which codis-config` -c ../conf/config.ini -L ../log/config.log server add 1 10.0.60.144:6380 slave echo "add group 2 with a master(10.0.60.144:6381), Notice: use in produciton" `which codis-config` -c ../conf/config.ini -L ../log/config.log server add 2 10.0.60.144:6381 master `which codis-config` -c ../conf/config.ini -L ../log/config.log server add 2 10.0.60.144:6382 slave |
3、initslot.sh
1 2 3 4 5 6 7 8 |
#!/bin/bash # echo "slots initializing..." codis-config -c ../conf/config.ini slot init -f echo "set slot ranges to server groups..." codis-config -c ../conf/config.ini slot range-set 0 511 1 online codis-config -c ../conf/config.ini slot range-set 512 1023 1 online |
4、start_proxy.sh
1 2 3 4 |
#!/bin/bash # echo "start new proxy..." nohup `which codis-proxy` -c ../conf/config.ini -L ../log/proxy.log --cpu=4 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 & |
5 、set_proxy_online.sh
1 2 3 |
#!/bin/bash # `which codis-config` -c ../conf/config.ini proxy online proxy_1 |
注意按照顺序依次启动即可。由于codis一旦跟zookeeper连接出现异常后codis-proxy就会异常退出,所以需要写一个计划任务监控脚本当codis_proxy异常退出时就报警并且自动拉起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#!/bin/bash IP=10.0.60.144 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 |
完结。