Codis 集群

一、codis介绍
codis是一个分布式redis集群解决方案,对于上层的应用来说, 连接到codis-proxy和连接原生的redis-server没有明显的区别。
上层应用可以像使用单机的redis一样使用,codis底层会处理请求的转发,不停机的数据迁移等工作。所有后边的一切事情,对于前面的客户端来说是透明的,可以简单的认为后边连接的是一个内存无限大的redis服务。
codis由四部分组成:
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分支,基于redis2.8.21开发,加入了slot的支持和原子的数据迁移指令。codis上层的codis-proxy和codis-config只能和这个版本的redis交互才能正常运行。
codis依赖zookeeper来存放数据路由表和codis-proxy节点的元信息,codis-config发起的命令都会通过zookeeper同步到各个存活的codis-proxy。
codis支持按照namespace区分不同的产品,拥有不同的product name的产品,各项配置都不会冲突。
codis架构图如下:


二、环境准备
codis集群的搭建,需要zookeeper集群,有关zookeeper集群的搭建,可以参考这篇文章《烂泥:zookeeper集群搭建》。
除了zookeeper集群之外,我们还需要安装go语言环境,因为codis是基于go语言开发的。
2.1 ****安装基础依赖
安装基础依赖,使用如下命令:
yum install -y git gcc make g++ gcc-c++ automake openssl-devel zlib-*
clip_image002

基础依赖安装往后,我们现在开始配置go语言环境。

2.2 go****语言环境搭建**
codis是基于go语言开发的,所以我们要在所有服务器上都配置go语言环境。

GOPATH, GOROOT配置:https://golang.org/doc/install

下载go语言包,如下:
wget https://storage.googleapis.com/golang/go1.6.1.linux-amd64.tar.gz


下载完毕后,解压到/usr/local,如下:
tar -C /usr/local -xf go1.6.1.linux-amd64.tar.gz
clip_image004

把go加入到系统的环境变量,如下:
GOPATH:是go的工作目录
GOROOT:是go的安装目录
vim /etc/profile
export GOROOT=$PATH:/usr/local/go/bin
export GOPATH=/usr/local/go/work
clip_image005

让刚刚加入的环境变量生效,并查看go是否配置成功,如下:
source /etc/profile
env
go version
clip_image006

通过上图,我们可以很明显的看出go语言环境配置成功。

三、安装codis
codis的安装,我们可以通过三种不同的方式进行:通过go下载安装、通过git方式和通过源码方式,下面分别介绍下。

3.1 ****通过go下载安装

官方github地址为:https://github.com/CodisLabs/codis
cd /usr/local/go/work/src/github.com/CodisLabs/codis
官方使用文档地址为:
https://github.com/CodisLabs/codis/blob/master/doc/tutorial_zh.md
按照官方github介绍,codis首选方式是通过go下载安装的。命令如下:
go get -u -d github.com/CodisLabs/codis


注意:由于众所周知的原因,这一步比较慢,需要耐心等待。上一步执行完毕后,我们切换到目录下,进行编译,如下:
make
clip_image008

clip_image009

clip_image010

注意:这一步也比较慢,需要耐心等待。
make编译执行完毕后后,会在bin目录下生成codis-config、codis-proxy、codis-server三个可执行文件以及assets目录。
其中assets是codis-config的dashboard http 服务需要的前端资源,需要和codis-config放置在同一目录下。如下:
ll bin/
clip_image011

编译完毕后,我们现在来测试编译的结果,使用如下命令:
make gotest
clip_image012

通过上图,我们可以看到codis已经安装成功。

3.2 ****通过git方式

上一章节,我们介绍了codis通过go下载安装的方法,这一章节,我们通过git方式进行安装。
首先下载codis最新的git仓库,使用如下命令:
git clone https://github.com/CodisLabs/codis.git


git仓库下载完毕后,我们接下来进行如下的操作。如下:
mkdir -p /usr/local/src/github.com/CodisLabs/
cp -r codis /usr/local/src/github.com/CodisLabs/
cd /usr/local/src/github.com/CodisLabs/codis/
clip_image014

以上操作完毕后,就和通过go下载安装方式一样了。执行make命令进行编译,然后执行make gotest命令进行测试。

3.3 ****通过下载源码

下面我们来介绍下,通过源码方式的安装。下载codis源码文件,如下:
wget https://github.com/CodisLabs/codis/archive/3.0.3.tar.gz


解压源码包,如下:
tar -xf 3.0.3.tar.gz
cd codis-3.0.3/
clip_image016

然后进行编译,使用make命令,如下:
clip_image017

clip_image018

clip_image019

clip_image020

这一步很慢,需要下载各种依赖,然后是make gotest。
基本和go下载安装方式一样,不过需要说明下,我通过源码方式一直没有安装成功。报如下错误:
clip_image021

所以以上三种安装的方法,建议使用第一、二种,尽管有点慢。
四、配置codis集群
codis安装完毕后,我们现在来配置codis集群。在正式配置集群之前,先创建相关的目录,然后复制相关文件到新的目录下。使用如下命令:
cd /usr/local/go/work/src/github.com/CodisLabs/codis
mkdir -p /usr/local/codis/{log,redis_conf}
cp -rf bin/ /usr/local/codis/
cp config.ini /usr/local/codis/
cp extern/redis-test/conf/6379.conf /usr/local/codis/redis_conf/20189.conf
cp extern/redis-test/conf/6380.conf /usr/local/codis/redis_conf/20190.conf
clip_image022

4.1 ****编辑codis配置文件

上述操作完毕后,我们来修改codis的配置文件config.ini,在此我们只需要修改相关的选项即可。如下:
vim /usr/local/codis/config.ini
coordinator=zookeeper
zk=192.168.1.9:2181,192.168.1.124:2181,192.168.1.231:2181
product=test
dashboard_addr=192.168.1.9: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_9
该配置文件中,我们需要注意三个参数:zk、dashboard_addr、proxy_id。
其中zk是表示zookeeper集群的服务器IP地址,dashboard_addr表示codis web管理的IP地址及端口,proxy_id表示codis的id,注意每台codis服务器该值要唯一


另外两台服务器的codis配置文件,内容如下:
clip_image024

clip_image025

到此codis配置文件修改完毕。

4.2 ****编辑redis配置文件

codis配置文件修改完毕后,我们现在来修改redis配置文件。
每台codis服务器上,我们要启动两个redis实例(也可以启动多个redis实例),所以我们要配置两个redis。如下:
vim /usr/local/codis/redis_conf/20189.conf
daemonize no
pidfile /var/run/redis20189.pid
port 20189
tcp-backlog 511
timeout 0
tcp-keepalive 0
loglevel notice
logfile /var/log/redis/20189.log
databases 16
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump20189.rdb
dir /usr/local/codis/
slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100
appendonly no
appendfilename “appendonly.aof”
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events “”
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
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes


配置第二个redis实例,如下:
yes|cp /usr/local/codis/redis_conf/20189.conf /usr/local/codis/redis_conf/20190.conf
sed -i ‘s/20189/20190/g’ /usr/local/codis/redis_conf/20190.conf
mkdir -p /var/log/redis/
clip_image027

每台codis服务器上redis配置完毕后,我们来启动redis实例,如下:
/usr/local/codis/bin/codis-server /usr/local/codis/redis_conf/20189.conf &
/usr/local/codis/bin/codis-server /usr/local/codis/redis_conf/20190.conf &
ps -ef |grep codis-server
clip_image028

注意:我们每台codis服务器上的redis实例都需要启动。

4.3 ****启动codis dashboard

redis实例全部启动后,我们现在来启动codis的dashboard。
注意,我们一定要在192.168.1.9这台codis服务器上启动该命令,这是因为我们在4.1章节codis配置文件中配置的dashboard地址就是192.168.1.9。
使用如下命令启动dashboard:
nohup /usr/local/codis/bin/codis-config -c config.ini dashboard &
netstat -tunlp


codis dashboard访问端口是18087,如下:
http://codis.ilanni.com:18087/admin/
clip_image030

通过上图,我们可以很明显的看出codis dashboard已经正常启动。

4.4 ****创建redis server分组

codis dashboard已经正常启动后,我们现在来创添加redis server分组。如下:


clip_image032

clip_image033

clip_image034

这样我们第一个redis server分组就创建完毕了,可以使用同样的方法创建第二、三个分组。如下:
clip_image035

这样三组redis server分组就创建完毕了。
当然我们也可以通过命令进行创建,如下:
/usr/local/codis/bin/codis-config server add-group 1
/usr/local/codis/bin/codis-config server add-group 2
/usr/local/codis/bin/codis-config server add-group 3
/usr/local/codis/bin/codis-config server list
clip_image036

注意:上述命令在三台codis服务器上任意一台上执行。
到此codis的redis server分组添加完毕。

4.5 ****添加redis实例

redis server分组添加完毕后,我们现在来为每一个分组添加redis实例。先为group_1添加redis实例,如下:


clip_image038

这个里面可以填写任何一个codis服务器上的redis实例(哪怕不是codis服务器的redis实例),在此我们填写的是192.168.1.9这台服务器上的redis实例。
clip_image039

可以看到group_1组的第一个redis实例,被自动配置为master类型。
现在我们来添加第二个redis实例,如下:
clip_image040

clip_image041

通过上图,我们可以很明显的看到第二个添加的redis实例被默认配置为slave类型。
注意:redis官方的支持的集群也是master-slave主从式的集群。
group_2组和group_3组的redis实例添加和上面的操作一样,如下:
clip_image042

这样三组redis实例就全部添加完毕。
当然我们也可以通过命令进行添加,如下:
/usr/local/codis/bin/codis-config server add 1 192.168.1.9:20189 master
/usr/local/codis/bin/codis-config server add 1 192.168.1.9:20190 slave
/usr/local/codis/bin/codis-config server add 2 192.168.1.124:20189 master
/usr/local/codis/bin/codis-config server add 2 192.168.1.124:20190 slave
/usr/local/codis/bin/codis-config server add 3 192.168.1.231:20189 master
/usr/local/codis/bin/codis-config server add 3 192.168.1.231:20190 slave
注意:上述命令中的数字,表示的是哪一个分组,master/slave表示的是所属类型。
clip_image043

我们也可以通过命令查看,各个redis server组的信息,如下:
/usr/local/codis/bin/codis-config server list
clip_image044

注意:每组添加的第一个redis实例不能被删除,因为codis默认把该redis实例设置为master。
到此redis server分组的redis实例添加完毕。

4.6 ****分配slot范围

codis采用pre-sharding的技术来实现数据的分片,默认分成1024个slot(0-1023)。对于每个key来说,可以通过以下公式确定所属的slot id:slotid=crc32(key)%1024。
每一个slot都会有一个且必须有一个特定的server group id来表示这个slot的数据由哪个server group来提供。
在分配slot之前,我们需要初始化slot。
在codis服务器任意一台上执行bin/codis-config slot init命令,该命令会在zookeeper上创建slot相关信息。如下:
cd /usr/local/codis
/usr/local/codis/bin/codis-config -c config.ini slot init


slot初始化完毕后,我们现在来分配slot范围。如下:
clip_image046

clip_image047

上图中的New Group Id是自定义的。
clip_image048

通过上图,我们可以看到第一组slot分配成功。
现在来查看slot分配信息,如下:
clip_image049

clip_image050

通过上图,我们可以很明显的看出组1分配的slot是0-334,335以后还没有分配。现在来分配剩下的slot,如下:
clip_image051

clip_image052

这样slot已经全部分配完毕。
当然我们也可以通过命令进行分配,如下:
/usr/local/codis/bin/codis-config slot range-set 0 334 1 online
/usr/local/codis/bin/codis-config slot range-set 335 669 2 online
/usr/local/codis/bin/codis-config slot range-set 670 1023 3 online
clip_image053

查看slot信息,如下:
/usr/local/codis/bin/codis-config slot info 1
/usr/local/codis/bin/codis-config slot info 2
/usr/local/codis/bin/codis-config slot info 3
clip_image054

4.7 ****启动codis-proxy

以上全部配置完毕后,我们来启动codis-proxy,使用如下命令:
nohup /usr/local/codis/bin/codis-proxy
-c /usr/local/codis/config.ini
--log-level=error
-L /usr/local/codis/log/proxy.log
--cpu=2
--addr=192.168.1.9:19000
--http-addr=192.168.1.9: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启动后,我们可以在dashboard上进行查看,如下:
clip_image056

到此codis集群就搭建完毕。

五、连接codis集群
codis集群搭建完毕后,现在我们来连接codis集群。要连接codis集群,我们只需要连接codis-proxy即可。即连接4.7章节中的codis-proxy服务器地址,然后加19000端口。使用redis-cli命令连接,如下:
redis-cli -h 192.168.1.9 -p 19000
info


通过上图,我们可以很明显的看到连接codis集群是ok的。
我们现在对codis集群做一些压力测试,同时在dashboard上观察键值对的情况。如下:
redis-benchmark -h 192.168.1.9 -p 19000 -c 10000 -d 100 -t set -n 100000 -r 100000
上述命令的意思是,使用redis-benchmark压力测试命令连接codis集群,同时并发10000个(-c),测试set操作(-t),每个测试数据集是100字节(-d),请求数是100000(-n),使用使用随机数插入数值(-r)。
clip_image058

通过上图,可以很明显的看到codis集群的性能还是很不错的呢。
而我们laravel框架中redis的配置直接填写codis-proxy的连接地址即可。如下:
clip_image059

六、其他
在codis搭建和使用过程中,我们还是会碰到一些其他问题的,下面就稍微提下。

6.1 ****报zk节点不存在错误

如果要kill的dashboard的话,强烈建议通过kill -15 pid来关闭。
如果是直接使用kill -9进行kill的话,可能会报zk节点不存在错误的话。
这样的话,我们需要通过连接zookeeper集群,删除相关节点,然后再进行操作。删除节点操作,操作如下:
cd /usr/local/zookeeper/
./bin/zkCli.sh -server 127.0.0.1:2181
ls /zk/codis/db_test
rmr /zk/codis/db_test


clip_image061

6.2 ****与阿里云slb集成

在这里我们大致介绍下,codis在与阿里云的slb(负载均衡)进行集成的线上生产环境的案例。
目前我们连接codis集群是通过单个codis-proxy来进行的,如果这个节点挂了,就会出现了单点故障的危险。
所以我们这边在codis集群每台服务器上,都启动一个codis-proxy。然后前端使用slb进行统一接入,slb后端就有三台codis-proxy服务器。
codis集群的搭建和前面是一样的,只是在此我们的codis所在ecs(服务器)只有内网IP(省钱),而且slb我们是要的也是内网(省钱)。如下:


clip_image063

这样的话,客户端连接slb的地址就是连接codis整个集群了,同时也避免了单点故障的问题。

  公司的redis有时background save db不成功,通过log发现下面的告警,很可能由它引起的:

[13223] 17 Mar 13:18:02.207 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
于是通过搜索,也有人跟我遇到同样的问题,基本可以确定是由它引起的。
**内核参数overcommit_memory **
它是 内存分配策略
可选值:0、1、2。0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2, 表示内核允许分配超过所有物理内存和交换空间总和的内存
****什么是Overcommit和OOM****
Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做Overcommit。当linux发现内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。
当oom-killer发生时,linux会选择杀死哪些进程?选择进程的函数是oom_badness函数(在mm/oom_kill.c中),该函数会计算每个进程的点数(0~1000)。点数越高,这个进程越有可能被杀死。每个进程的点数跟oom_score_adj有关,而且oom_score_adj可以被设置(-1000最低,1000最高)。
解决方法:
/etc/sysctl.conf

vm.overcommit_memory=1 或者sysctl vm.overcommit_memory=1
或者
echo 1 > /proc/sys/vm/overcommit_memory
内核参数说明如下:
overcommit_memory文件指定了内核针对内存分配的策略,其值可以是0、1、2。
0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。 1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2, 表示内核允许分配超过所有物理内存和交换空间总和的内存

redis数据同步

git clone https://github.com/CodisLabs/redis-port
cd redis-port
make
./bin/redis-port sync --from 10.168.22.140:6379 --filterdb=3 --target 10.251.241.246:19000

转自: http://www.ilanni.com/?p=11524#五、连接codis集群

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容