简介
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别(不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作,所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务
Codis架构
逻辑架构
访问层:访问方式可以是类似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实现故障切换功能
codis由四部分组成
codis-proxy | 实现redis协议,由于本身是无状态的,因此可以部署很多个节点 |
---|---|
codis-config | 是codis的管理工具,包括添加/删除redis节点添加/删除proxy节点,发起数据迁移等操作,自带httpserver,支持管理后台方式管理配置 |
codis-server | 是codis维护的redis分支,基于2.8.21分支,加入了slot的支持和原子的数据迁移指令; codis-proxy和codis-config只能和这个版本的redis交互才能正常运行 |
zookeeper | 用于codis集群元数据的存储,维护codis集群节点 |
组件介绍
- Codis Proxy:对外提供Redis服务,除了一些不支持的命令外(不支持的命令列表),表现的和原生的Redis没有区别。由于它是无状态的,所以我们可以部署多个节点,从而保证了可用性。
- Codis Dashboard:集群管理工具,支持Codis Proxy的添加删除以及数据迁移等操作。对于一个Codis集群,Dashboard最多部署一个。
- Codis Admin:集群管理的命令行工具。
- Codis FE:集群管理界面,多个Codis集群可以共用一个Codis FE,通过配置文件管理后端的codis-dashboard。
- Storage:为集群提供外部存储,目前支持ZooKeeper、Etcd、Fs三种。
- Codis Server:基于3.2.8分支开发,增加额外的数据结构,用来支持slot有关的操作及数据迁移指令。
codis分片原理
现在我们已经知道了Codis会将指定key的Redis命令转发给下层的Redis。那么Codis如何知道某个key在哪个Redis上呢。
Codis采用Pre-sharding的技术来实现数据分片,默认分为1024个slot(0-1023)。Codis在接收到命令时,先对key进行crc32运算,然后再对1024取余,得到的结果就是对应的slot。然后就可以将命令转发给slot对应的Redis实例进行处理了。
安装配置
1.安装go运行环境:
Mac系统可以参考这个,其他系统可以参考这个教程
$ go version
go version go1.13.1 darwin/amd64
2.下载Codis源码
需要下载到指定目录:$GOPATH/src/github.com/CodisLabs
$ mkdir -p $GOPATH/src/github.com/CodisLabs
$ cd $GOPATH/src/github.com/CodisLabs
$ git clone https://github.com/CodisLabs/codis.git -b release3.2
3.编译源码
进入源码的codis目录,直接执行make命令即可。编译完成后,bin目录下的结构应该是这样的
$ ll bin
total 192448
drwxr-xr-x 8 jokki staff 256B 11 13 17:17 assets
-rwxr-xr-x 1 jokki staff 17M 11 13 17:17 codis-admin
-rwxr-xr-x 1 jokki staff 18M 11 13 17:16 codis-dashboard
-rw-r--r-- 1 jokki staff 5B 11 21 17:17 codis-dashboard.pid
-rwxr-xr-x 1 jokki staff 16M 11 13 17:17 codis-fe
-rw-r--r-- 1 jokki staff 5B 11 21 17:17 codis-fe.pid
-rwxr-xr-x 1 jokki staff 15M 11 13 17:17 codis-ha
-rwxr-xr-x 1 jokki staff 19M 11 13 17:16 codis-proxy
-rw-r--r-- 1 jokki staff 5B 11 21 17:16 codis-proxy.pid
-rwxr-xr-x 1 jokki staff 1.1M 11 13 17:16 codis-server
-rwxr-xr-x 1 jokki staff 98K 11 13 17:16 redis-benchmark
-rwxr-xr-x 1 jokki staff 161K 11 13 17:16 redis-cli
-rwxr-xr-x 1 jokki staff 1.1M 11 13 17:16 redis-sentinel
-rw-r--r-- 1 jokki staff 170B 11 13 17:16 version
安装zookeeper
1.下载zookeeper
进入/usr/local目录(也可以安装在其他目录,这里我安装在根目录里面)
从地址下载apache-zookeeper-3.5.9-bin.tar.gz
2.解压文件并重命名
sudo tar -zxvf apache-zookeeper-3.5.9-bin.tar.gz
sudo mv apache-zookeeper-3.5.9-bin/ zookeeper
3.在zookeeper 目录下新建两个文件夹 data 和 log,用于存储zookeeper的数据和日志
sudo mkdir data
sudo mkdir log
4.将conf目录下的zoo_sample.cfg文件更名为zoo.cfg,简单修改配置文件,自定义设置数据文件目录和日志文件目录
sudo mv zoo_sample.cfg zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/Users/xxx/zookeeper/data
dataLogDir=/Users/xxx/zookeeper/log
# the port at which the clients will connect
clientPort=2181
#server.1=codis-1:2888:3888
#server.2=codis-2:2888:3888
#server.2=codis-3:2888:3888
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
"zoo.cfg" 29L, 975C
5.设置myid
设置myid在我们配置的dataDir指定的目录下面,创建一个myid文件,里面内容为一个数字,用来标识当前主机,conf/zoo.cfg文件配置的srver.X中的X为什么数字,则myid文件就输入这个数字,由于我只有一台zk,所以配置文件里可以不配置server.X,但还是要配置myid的,echo一个数字1进去即可。如果有多台zk,则分别在zk服务器上echo对应的数字进对应的myid文件
echo "1" > /Users/xxx/zookeeper/data/myid
5.启动zookeeper服务,zookeeper/bin目录下启动
$ ./zkServer.sh start
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /Users/xxxx/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
注:停止服务命令 ./zkServer.sh stop
$ ./zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /Users/xxxx/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: standalone
启动后会在那个目录下产生一个启动的日志zookeeper.out,查看这个日志可以查看是否正常启动了。由于单个zookeeper,所以这里指示Mode: standalone,如果有多个zk节点,就只有一个Mode: leader的状态,别的都是Mode: follower状态。
由于我现在是做一个机器做zk,所以这里几乎不用修改
$ cd /usr/local/codis
$ cat config.ini
zk=localhost:2181 //zookeeper的地址, 如果是zookeeper集群,可以这么写: zk=hostname1:2181,hostname2:2181,hostname3:2181,hostname4:2181,hostname5:2181,如果是etcd,则写成http://hostname1:port,http://hostname2:port,http://hostname3:port
product=test //产品名称, 这个codis集群的名字, 可以认为是命名空间, 不同命名空间的codis没有交集
proxy_id=proxy_1 //proxy会读取, 用于标记proxy的名字, 针对多个proxy的情况, 可以使用不同的config.ini, 只需要更改 proxy_id 即可
net_timeout=5 //检测状态时间间隔
dashboard_addr=localhost:9090 //dashboard 服务的地址,CLI 的所有命令都依赖于 dashboard 的 RESTful API,所以必须启动
coordinator=zookeeper //如果用etcd,则将zookeeper替换为etcd
[root@codis-1 bin]#
配置说明
1.文件名可以任意,不是非得改为zoo.cfg
2.tickTime: zookeeper中使用的基本时间单位, 毫秒
3.dataDir: 内存数据快照的保存目录;如果没有自定义Log也使用该目录
4.clientPort: 监听Cli连接的端口号
到这里为止,我们的准备工作已经完成了。接下来我们启动测试集群。
启动顺序
1.zkServer.sh start 启动zookeeper服务
2.codis-dashboard-admin.sh start 启动 dashboard
3.codis-proxy-admin.sh start 启动proxy
4.codis-server-admin.sh start 启动server
5.codis-fe-admin.sh start 启动fe
打开web访问集群管理页面(fe地址:127.0.0.1:9090)设置集群
测试集群
1.启动codis-dashboard
进入admin目录,执行codis-dashboard-admin.sh脚本
$ ./codis-dashboard-admin.sh start
/Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/admin/../config/dashboard.toml
starting codis-dashboard ...
查看日志,观察是否启动成功
$ tail -100 ../log/codis-dashboard.log.2021-07-21
2021/07/21 17:24:32 topom.go:429: [WARN] admin start service on [::]:18080
2021/07/21 17:24:32 main.go:155: [WARN] option --pidfile = /Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/bin/codis-dashboard.pid
2021/07/21 17:24:32 fsclient.go:195: [INFO] fsclient - create /codis3/codis-demo/topom OK
2021/07/21 17:24:32 topom_sentinel.go:169: [WARN] rewatch sentinels = []
2021/07/21 17:24:32 main.go:179: [WARN] [0xc000178b40] dashboard is working ...
2.启动codis-proxy
执行codis-proxy-admin.sh脚本
$ ./codis-proxy-admin.sh start
/Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/admin/../config/proxy.toml
starting codis-proxy ...
查看是否启动成功
$ tail -100 ../log/codis-proxy.log.2021-07-21
2021/07/21 17:27:08 proxy_api.go:44: [WARN] [0xc0000f0840] API call /api/proxy/start/24c38f7765db81f837f0acbc2af8124a from 192.168.8.189:51250 []
2021/07/21 17:27:08 proxy_api.go:44: [WARN] [0xc0000f0840] API call /api/proxy/sentinels/24c38f7765db81f837f0acbc2af8124a from 192.168.8.189:51250 []
2021/07/21 17:27:08 proxy.go:293: [WARN] [0xc0000f0840] set sentinels = []
2021/07/21 17:27:08 main.go:343: [WARN] rpc online proxy seems OK
2021/07/21 17:27:09 main.go:233: [WARN] [0xc0000f0840] proxy is working ...
3.启动codis-server
执行codis-server-admin.sh脚本
$ ./codis-server-admin.sh start
/Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/admin/../config/redis.conf
starting codis-server ...
查看是否启动成功
$ tail -100 /tmp/redis_6379.log
1807:M 21 Jul 17:28:42.526 * Increased maximum number of open files to 10032 (it was originally set to 256).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.11 (de1ad026/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 1807
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
1807:M 21 Jul 17:28:42.534 # Server started, Redis version 3.2.11
1807:M 21 Jul 17:28:42.534 * The server is now ready to accept connections on port 6379
注:如果执行报错,请先确认使用的用户是否有/tmp/redis_6379.log文件的读写权限。
4.启动codis-fe
执行codis-fe-admin.sh脚本
$ ./codis-fe-admin.sh start
starting codis-fe ...
查看是否启动成功
$ tail -100 ../log/codis-fe.log.2021-07-21
2021/07/21 17:34:31 main.go:101: [WARN] set ncpu = 4
2021/07/21 17:34:31 main.go:104: [WARN] set listen = 0.0.0.0:9090
2021/07/21 17:34:31 main.go:120: [WARN] set assets = /Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/bin/assets
2021/07/21 17:34:31 main.go:162: [WARN] set --filesystem = /tmp/codis
2021/07/21 17:34:31 main.go:216: [WARN] option --pidfile = /Applications/MAMP/htdocs/GO/src/github.com/CodisLabs/codis/bin/codis-fe.pid
全部启动成功之后,就可以访问http://127.0.0.1:9090,开始设置集群了。
在 Proxy 栏可看到我们已经启动的 Proxy,但是 Group 栏为空,因为我们启动的 codis-server 并未加入到集群
添加NEW GROUP,NEW GROUP 行输入 1,再点击 NEW GROUP 即可添加 Codis Server,Add Server 行输入我们刚刚启动的 codis-server 地址,添加到我们刚新建的 Group,然后再点击 Add Server 按钮即可
新增的集群 slot 状态是 offline,因此我们需要对它进行初始化(将 1024 个 slot 分配到各个 group),而初始化最快的方法可通过 fe 提供的 rebalance all slots 按钮来做,如下图所示,点击此按钮,我们即快速完成了一个集群的搭建;当然,也可以手动分配slot,比如,我们将group-1的10个slot分配给group-2,只需要点击Migrate Some按钮即可
到这里codis集群的搭建已经完毕
参考资料
https://github.com/wandoulabs/codis
https://blog.csdn.net/nawenqiang/article/details/84990508
https://zhuanlan.zhihu.com/p/69114539