wget http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz tar -zx[v]f zookeeper-3.4.6.tar.gz -C /work/servers cd /work/servers/zookeeper-3.4.6 mkdir data && mkdir logs??修改zoo.cfg几个关键属性:?
一、codis安装前准备工作
1、参考链接
Codis:https://github.com/CodisLabs/codis/blob/master/doc/tutorial_zh.md
? ? ? ? ? ? http://0xffff.me/blog/2014/11/11/codis-de-she-ji-yu-shi-xian-1/
Codis-port:https://github.com/CodisLabs/redis-port
FAQ:https://github.com/CodisLabs/codis/blob/master/doc/FAQ_zh.md
Zookeeper:https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
?
2、准备几个目录备用
/work/soft ? ? ? ?- 软件下载目录
/work/servers ?- 软件安装目录
? ?go ?- go安装目录【GOROOT】
? ?zookeeper-3.4.6 - zookeeper安装目录【ZOOKEEPER_HOME】
/work/gospace - 本机所有go项目(包括项目依赖的第三方库)的所在目录(包括codis和codis-port)【GOPATH】
/work/codis ?- codis和codis-port源码下载目录
? ? logs - codis启动的相关日志目录(dashboard.log/proxy.log/slot.log/request.log/redis-port.log)
? ? rdb ?- redis的RDB文件路径
/work/codis_bin - 一个软链接到codis/bin
/work/codis_port_bin - 一个软链接到codis_port/bin
/etc/codis ? - codis启动的一系列配置文件(redis_xxx.conf/zoo.cfg/codis的config.ini)
?
3、环境介绍
使用一台虚拟机搭建一个codis伪集群,zookeeper没有使用集群[配置很简单,自己操作]。?
①1个redis-server - 使用它的redis.conf配置文件以及使用它模拟从redis导数据到codis集群 ②1个zookeeper - 中间件 ③6个端口不同实例相同的codis-server - 见[三、codis运行] ④2个codis-proxy - 只不过配置文件不同 ⑤192.168.56.101 - 宿主机能够访问的IP(虚拟机的网络连接,网卡1:NAT,网卡2:host-only;家庭电脑尽量使用桥接,并且静态地址)?redis-server和codis-server的不同:codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.21 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行。?
?
4、go/zookeeper/jdk/redis安装和环境变量配置(codis是go语言开发)
(1)进入/work/soft目录,cd /work/soft
(2)下载并解压go安装包:??
wget https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz tar -zx[v]f go1.6.linux-amd64.tar.gz -C /work/servers?(3)下载并安装zookeeper安装包:
wget http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz tar -zx[v]f zookeeper-3.4.6.tar.gz -C /work/servers cd /work/servers/zookeeper-3.4.6 mkdir data && mkdir logs??修改zoo.cfg几个关键属性:?
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/work/servers/zookeeper-3.4.6/data dataLogDir=/work/servers/zookeeper-3.4.6/logs clientPort=2181
?最后把配置文件放到/etc/codis中,
cp /work/servers/zookeeper-3.4.6/conf/zoo.cfg /etc/codis/zoo.cfg
(4)jdk安装略...?
(5)redis安装略...
(6)准备codis-server(6个redis服务)的启动文件:
?修改redis.conf,主要修改这几点:?
daemonize yes pidfile /var/run/redis_6379.pid port 6379 dbfilename dump_6379.rdb dir /work/codis/rdb
?然后执行下面命令:??
cp redis.conf /etc/codis/redis_6378.conf && sed -i ‘s/6379/6378/g‘ /etc/codis/redis_6378.conf cp redis.conf /etc/codis/redis_6478.conf && sed -i ‘s/6379/6478/g‘ /etc/codis/redis_6478.conf cp redis.conf /etc/codis/redis_6379.conf cp redis.conf /etc/codis/redis_6479.conf && sed -i ‘s/6379/6479/g‘ /etc/codis/redis_6479.conf cp redis.conf /etc/codis/redis_6380.conf && sed -i ‘s/6379/6380/g‘ /etc/codis/redis_6380.conf cp redis.conf /etc/codis/redis_6480.conf && sed -i ‘s/6379/6480/g‘ /etc/codis/redis_6480.conf
?(7)配置环境变量,执行命令:vim /etc/profile,在最后一行添加:?
export GOROOT=/work/servers/go export GOPATH=/work/gospace export ZOOKEEPER_HOME=/work/servers/zookeeper-3.4.6 export JAVA_HOME=你的jdk根路径 export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar export PATH=$GOROOT/bin:$GOPATH/bin:$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin:$PATH
?配置ok,刷新环境变量; ?.或者source ?/etc/profile。
?
(8)测试三个必须软件是否正常安装:
jdk - 执行java命令
zookeeper?
? ?- 启动命令:zkServer.sh start /etc/codis/zoo.cfg
? ?- 停止敏力:zkServer.sh stop /etc/codis/zoo.cfg
? ?- 查看状态:zkServer.sh status /etc/codis/zoo.cfg
go - 编写个小程序(摘自go官网)?
package main import "fmt" func main() { fmt.Println("Hello, 世界") }
?执行命令:go run hello.go。
?
?
二、codis安装与配置
1、安装codis前,需要先装下git:?
yum install -y git
?2、下载codis源码(下载目录自动到GOPATH=/work/gospace中):??
go get -u -d github.com/CodisLabs/codis
?3、切换到/work/gospace/src/github.com/CodisLabs/codis,编译测试:??
make && make gotest
?4、执行成功了上面的命令,会在bin文件夹中生成三个可执行文件:codis-config、codis-proxy、codis-server,常用命令查询:?
./codis-config -c /etc/codis/config.ini proxy -h ./codis-config -c /etc/codis/config.ini action -h ./codis-config -c /etc/codis/config.ini slot -h ./codis-config -c /etc/codis/config.ini server -h ./codis-config -c /etc/codis/config.ini dashboard -h
?5、在/work目录建立软链接方便进入bin目录:?
ln -s /work/gospace/src/github.com/CodisLabs/codis/bin codis_bin
?6、编辑config.ini文件,主要修改2点:?
zk=192.168.56.101:2181(如果是zookeeper集群,用逗号隔开继续添加) dashboard_addr=192.168.56.101:18087 【下面可选修改】 [product=test 其实就是个Namespace区分项目,改完后在zookeeper中的路径会稍微不同,如:/zk/codis/db_product名字] [proxy_id=proxy1 改完在启动proxy的时候,注意proxy_id的名字]
?ip地址改为客户端能访问到的,最好别搞成127.0.0.1;然后copy到/etc/codis/目录。
?
?
三、codis的运行
【说明】:
(1)首先创建2个group(group-1,group-2),分配redis端口号:6378(master-group1)、6478(slave-group1)、6379(master-group2)、6479(slave-group2),槽位分配group1:0-511,group2:512-1023;
(2)然后再创建1个group(group-3),分配redis端口号6380(master-group3)、6480(slave-group3),重新分配槽位:group1:0-340,group2:341-680,group3:681-1023;?
(3)以下所有的bash文件都是在codis_bin目录中;
(4)首次启动codis,必须按照下面1-6的顺序依次启动命令。
1、首先启动zookeeper[如果安装时候已启动,自动忽略]:
论zookeeper重要性:Codis依赖ZooKeeper来存放数据路由表和codis-proxy节点的元信息,codis-config发起的命令都会通过ZooKeeper同步到各个存活的codis-proxy。?
zkServer.sh start /etc/codis/zoo.cfg
?2、启动dashboard,方便起见写到bash文件[下同]:??
#!/bin/bash nohup ./codis-config -c /etc/codis/config.ini -L /work/codis/logs/dashboard.log dashboard --addr=192.168.56.101:18087 --http-log=/work/codis/logs/request.log > /dev/null 2>&1 &
--addr的ip地址不能写成127.0.0.1 否则访问页面打不开。
执行:ps -ef | grep codis 能看到:?
root 1536 1 0 16:38 ? 00:00:42 ./codis-config -c /etc/codis/config.ini -L /work/codis/logs/dashboard.log dashboard --addr=192.168.56.101:18087 --http-log=/work/codis/logs/request.log root 1970 1122 0 18:33 pts/0 00:00:00 grep codis
?3、启动redis:?
#!/bin/bash echo ‘redis starting‘ ./codis-server /etc/codis/redis_6378.conf ./codis-server /etc/codis/redis_6478.conf ./codis-server /etc/codis/redis_6379.conf ./codis-server /etc/codis/redis_6479.conf ./codis-server /etc/codis/redis_6380.conf ./codis-server /etc/codis/redis_6480.conf echo ‘done‘
?4、初始化group:?
#!/bin/bash echo ‘groups initializing...‘ ./codis-config -c /etc/codis/config.ini server add 1 localhost:6378 master ./codis-config -c /etc/codis/config.ini server add 1 localhost:6478 slave ./codis-config -c /etc/codis/config.ini server add 2 localhost:6379 master ./codis-config -c /etc/codis/config.ini server add 2 localhost:6479 slave echo ‘done‘
5、初始化slot:?
#!/bin/bash echo ‘slots starting...‘ ./codis-config -c /etc/codis/config.ini action remove-fence ./codis-config -c /etc/codis/config.ini slot init -f ./codis-config -c /etc/codis/config.ini slot range-set 0 511 1 online ./codis-config -c /etc/codis/config.ini slot range-set 512 1023 2 online echo ‘done‘
6、启动proxy:?
#!/bin/bash echo ‘shutdown codis-proxy‘ ./codis-config -c /etc/codis/config.ini proxy offline proxy_1 sleep 2 echo ‘codis-proxy starting‘ nohup ./codis-proxy -c /etc/codis/config.ini --log-level=info -L /work/codis/logs/proxy.log --cpu=3 --addr=192.168.56.101:19000 --http-addr=192.168.56.101:11000 &>/dev/null & [下面命令非必须(执行也不报错),官方文档有点问题:它指出启动后的proxy是offline状态,但是实验发现是online状态的,所以无需执行下面设置为online的命令] sleep 2 echo ‘setting codis-proxy online‘ ./codis-config -c /etc/codis/config.ini proxy online proxy_1 echo ‘done‘
?
?
全部启动正常后,打开chrome,访问:http://192.168.56.101:18087/admin/,可以看到如下界面(此时你看不到group3):
?
?
?
?
四、codis的模拟各种场景测试
1、用java程序写测试程序:
JedisResourcePool jedisPool = RoundRobinJedisPool.create().curatorClient("192.168.56.101:2181", 30000).zkProxyDir("/zk/codis/db_test/proxy").build(); Jedis jedis = jedisPool.getResource(); while(++i < 10000){ jedis.setnx("num:"+i, i+""); }
2、多线程测试程序:?
public static String randomstr(){ Random rnd = new Random(); return ""+rnd.nextInt(Integer.MAX_VALUE); } public static void init_data(JedisResourcePool jedisPool){ for(int i = 0; i < 100; i++){ new myThread(jedisPool).start(); } } static class myThread extends Thread{ private JedisResourcePool jedisPool; public myThread(JedisResourcePool jedisPool){ this.jedisPool = jedisPool; } public void run() { for(int i=0;i<1000;i++){ String randomstr = randomstr(); Jedis jedis = jedisPool.getResource(); jedis.setnx(randomstr, randomstr); System.out.println(Thread.currentThread().getName()+"=======>>>>"+randomstr); try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(e.getMessage() + "=======>>>>" + randomstr); e.printStackTrace(); } finally{ jedis.close(); } } } }
?3、程序检测key值定位到哪个slot:?
CRC32 crc32 = new CRC32(); crc32.update("num:1".getBytes()); System.out.println(crc32.getValue() % 1024);
??
4、把6479-redis(slave)从group1中remove掉,然后向6379-redis(master)插入数据,看是否继续同步数据到6479-redis(slave):?
./codis-config -c /etc/codis/config.ini server remove 2 localhost:6479
??
5、保持程序2在正常运行状态,同时添加group3,重新分配迁移slot,查看是否抛异常.
依次执行下面命令:?
./codis-config -c /etc/codis/config.ini server add 3 localhost:6380 master ./codis-config -c /etc/codis/config.ini server add 3 localhost:6480 slave ./codis-config -c /etc/codis/config.ini slot migrate 0 340 1 --delay=5 ./codis-config -c /etc/codis/config.ini slot migrate 341 680 2 --delay=5 ./codis-config -c /etc/codis/config.ini slot migrate 681 1023 3 --delay=5
?6、再启动一个proxy(proxy_2):
??【说明】:
==================================================
①config.ini中使用相同的zookeeper,dashboard_addr,product, 不同的proxy_id;
②start_proxy_2.sh中设置不同的addr,http-addr端口号,以及log日志文件名
==================================================
?复制一份config.ini重命名为config_2.ini
cd /etc/codis cp config.ini config_2.ini && sed -i ‘s/proxy_1/proxy_2/g‘ config_2.ini
?启动proxy_2:??
#!/bin/bash echo ‘shutdown codis-proxy-2‘ ./codis-config -c /etc/codis/config_2.ini proxy offline proxy_2 sleep 2 echo ‘codis-proxy-2 starting‘ nohup ./codis-proxy -c /etc/codis/config_2.ini --log-level=info -L /work/codis/logs/proxy_2.log --cpu=3 --addr=192.168.56.101:19001 --http-addr=192.168.56.101:11001 &>/dev/null & sleep 2 echo ‘setting codis-proxy-2 online‘ ./codis-config -c /etc/codis/config_2.ini proxy online proxy_2 echo ‘done‘
启动成功后,保持程序2在正常运行状态,测试几点:?
①使用页面端mark offline按钮停掉其中一个proxy;
②然后再启动停掉的proxy;
③分别使用kill或者kill -9杀死某个proxy的进程
?
7、虚拟机退出后,再次开启,只需要启动zookeeper、dashboard、redis、proxy即可,测试以下几点:
①观察slave/master的redis是否还是slave/master;
②调用程序插入数据是否正常;
③主从同步是否正常。
?
五、测试总结
1、同一个组中,remove掉某个slave,插入到master的数据,还能同步到该slave中、
?
2、挂掉整个系统,重新启动dashboard,控制页面虽然能看到master和slave的redis状态,实际上slave不再是slave,而是master,需要进行重新add-slave操作。
?
3、dashboard启动不来,报错如下:?
dashboard.go:234: [PANIC] create zk node failed [error]: dashboard already exists: {"addr": "192.168.56.101:18087", "pid": 1242}
?
解决方案:delete /zk/codis/db_test/dashboard
?
4、删除一个已分配slot的group,或者redis-master时,报错:?
[error]: http status code 500, cannot remove master, use promote first
?
解决方案:已分配slot的group是删除不了的,只能转移slot数据。删除redis-master也必然不行,一个group必须有个master。可以先指定一个slave升级为master,然后可以删除该master。
?
5、kill -9强制关闭proxy,codis无法区分是否正常下线或者session过期。然后再操作分配slot时候,出现错误。
解决办法:
./codis-config -c /etc/codis/config.ini action remove-fence 或者 进入zookeeper手动删除/zk/codis/db_test/fence
?
6、slot的迁移,程序运行对迁移状态不影响,可以在dashboard看到迁移动态。
?迁移原理:http://0xffff.me/blog/2014/11/11/codis-de-she-ji-yu-shi-xian-part-2
[ Codis 不适合少量key,value特别大的应用(这种不用分布式了,直接用单个redis就可以), 更适合海量 Key, value比较小(<= 1 MB) 的应用]
?
六、使用codis-port把项目中redis数据迁移到codis集群
1、修改安装redis-server的redis.conf的端口号为6580:
?
sed -i ‘s/6379/6580/g‘ redis.conf
?
2、启动安装的redis实例:? ?
redis-server ../conf/redis.conf
?
3、写个程序往6580-redis插入10w条数据:
?
Jedis jedis = new Jedis("192.168.56.101", 6580); for(int i=20000;i<100000;i++){ jedis.set("i:"+i, ""+i); }
4、下载安装、编译redis-port:
cd /work go get -u -d github.com/CodisLabs/codis-port cd /work/gospace/src/github.com/CodisLabs/codis-port && make ln -s /work/gospace/src/github.com/CodisLabs/redis-port/bin codis_port_bin
?5、redis数据导入到codis集群:
cd /work/codis_port_bin
?执行命令:
#!/bin/bash nohup ./redis-port sync --ncpu=3 --from=127.0.0.1:6580 --target=192.168.56.101:19000 > /work/codis/logs/redis-port.log 2>&1 & sleep 3 tail -f /work/codis/logs/redis-port.log
?
?
原文:http://aokunsang.iteye.com/blog/2287044