先看下什么是codis吧.codis是由豌豆荚开发的一个分布式 Redis 服务, 用户可以看成是一个无限内存的 Redis 服务, 有动态扩/缩容的能力. 对偏存储型的业务更实用, 如果你需要 SUBPUB 之类的指令, Codis 是不支持的. 时刻记住 Codis 是一个分布式存储的项目. 对于海量的 key, value不太大( <= 1M ), 随着业务扩展缓存也要随之扩展的业务场景有特效.
这是codis大致架构
codis-proxy:可以看做redis ,他是redis的代理,与应用透明,支持redis协议.
对于同一个业务集群而言,可以同时部署多个codis-proxy实例;不同codis-proxy之间由codis-dashboard保证状态同步。
Codis Dashboard:
集群管理工具,支持codis-proxy,codis-server的添加,删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard维护集群下所有codis-proxy的状态的一致性。
对于同一个业务集群而言,同一个时刻codis-dashboard只能有0个或者1个;所有对集群的修改都必须通过codis-dashboard完成。
Codis Admin:集群管理的命令行工具。
可用于控制codis-proxy,codis-dashboard状态以及访问外部存储。
Codis FE:集群管理界面。
多个集群实例共享可以共享同一个前端展示页面;通过配置文件管理后端codis-dashboard列表,配置文件可自动更新。
存储:为集群状态提供外部存储
提供命名空间概念,不同集群的会按照不同产品名称进行组织;目前仅提供了Zookeeper,Etcd,Fs三种实现,但是提供了抽象的界面可自行扩展。
codis引入了组的概念,可以平滑扩容/缩荣,对应用无感知.运维投入成本少.而且测试发现效率确实高于Twemproxy.
而且提供了 redis-port 的命令行工具,可以静态分析 RDB 文件,包括解析以及恢复 RDB 数据到 redis,从 redis 上 dump RDB 文件以及从 redis 和 codis 之间动态同步数据
并且codis支持多线程操作,可以充分利用多核cpu
想了解更多请关注官方github https://github.com/CodisLabs/codis
下面我们来搭建一下环境,
1,安装go环境
下载go语言安装包 https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz
解压配置环境变量 export GOROOT=/usr/local/go export PATH=$PATH:$GOROOT/bin:
运行go version验证是否配置成功
2,下载codis安装包 git clone https://github.com/CodisLabs/codis.git -b release3.2
3,编译安装 make
但是怎么都编译不过去,报错如下:
仔细观察报错内容,恍然大悟,原来开是默认文件夹的问题.go语言编译的时候默认codis路径是$GOPATH/src/github.com/CodisLabs/codis/pkg 于是把解压好的codis源码复制到$GOPATH/src/github.com/CodisLabs/目录下
再次编译直接通过
4,安装zookeeper此处就不说了
5,简单的配置一下codis的配置文件
vi codis/config/dashboard.toml文件
# Set Coordinator, only accept "zookeeper" & "etcd"
coordinator_name = "zookeeper"
coordinator_addr = "127.0.0.1:2181"
# Set Codis Product {Name/Auth}.
product_name = "codis-demo” #区分不同的集群,注册到zookeeper也是用这个区分
product_auth = ""
# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:18080” #用于dashboard与codas-proxy,codis-server进行tcp通信
vi codis/config/proxy.toml
# Set Codis Product {Name/Auth}.
product_name = "codis-demo” #同codis-dashboard中配置
product_auth = ""
# Set bind address for admin(rpc), tcp only.
admin_addr = "0.0.0.0:11080” #用于和codis-dashboard进行tcp通信同步信息
# Set bind address for proxy, proto_type can be "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
proto_type = "tcp4"
proxy_addr = "0.0.0.0:19000” #用于redis客户端连接,支持redis协议,端口唯一
# Set jodis address & session timeout.
jodis_name = “zookeeper” #用于jodis从zookeeper获取集群proxy信息,目前只支持zookeeper,etcd
jodis_addr = "127.0.0.1:2181”
jodis_timeout = 10
jodis_compatible = false
vi codis/config/redis.conf 正常配置即可,
vi codis/config/sentinel.conf 配置哨兵
6,依次启动各个组件
./bin/codis-fe --ncpu=4 --log=./log/fe.log --log-level=WARN --zookeeper=127.0.0.1:2181 --listen=192.168.68.128:9090 &
./bin/codis-dashboard --ncpu=4 --config=./config/dashboard.toml --log=./log/dashboard.log --log-level=WARN &
./bin/codis-proxy --ncpu=4 --config=./config/p.toml --log=./log/p.log --log-level=WARN &
./bin/codis-server ../config/redis.conf
./bin/codis-server ../config/sentinel.conf
--ncpu参数可以指定cpu数量
7,增加proxy节点
./bin/codis-admin --dashboard=127.0.0.1:18080 --create-proxy -x 127.0.0.1:11080
相当于在页面那上执行的add proxy操作,增加proxy是动态的,对应用无影响.客户端jodis是从zookeeper中拿的proxy地址进行负载均衡
8,增加组group
./bin/codis-admin --dashboard=127.0.0.1:18080 --create-group --gid=1
把相应的redis节点加到组中
./bin/codis-admin --dashboard=127.0.0.1:18080 --group-add --gid=1 -- addr=127.0.0.1:6379
将从节点增加到组中
./bin/codis-admin --dashboard=127.0.0.1:18080 --sync-action --create --addr=127.0.0.1:6380
9.给group分配solt槽位
./bin/codis-admin --dashboard=127.0.0.1:18080 --rebalance --confirm
10.关联哨兵集群
./bin/codis-admin --dashboard=127.0.0.1:18080 --sentinel-add --addr=127.0.0.1:26379
然后执行sync操作:(同fe页面”SYNC"按钮)
./bin/codis-admin --dashboard=127.0.0.1:18080 --sentinel-resync
11.官方为我们提供的java api
引入依赖
<dependency>
<groupId>com.wandoulabs.jodis</groupId>
<artifactId>jodis</artifactId>
<version>0.2.1</version>
</dependency>
java代码
public class Test {
public static void main(String[] args) {
RoundRobinJedisPool build = RoundRobinJedisPool.create()
.curatorClient("192.168.68.128", 2181).zkProxyDir("/jodis/codis-demo")
.build();
long l = System.currentTimeMillis();
for(int i=0;i<10000;i++){
Jedis resource = build.getResource();
String set = resource.set(String.valueOf(i), "测试");
System.out.println(set);
}
long l1 = System.currentTimeMillis();
System.out.println(l1-l);
}
打开源码,代码量很少,就这几个类
怎么实现动态扩容/缩容 代理层codis-proxy的呢,我们打开源码发现是基于zookeeper的高级api curator实现的通过 watcher机制实现动态添加节点
this.watcher.getListenable().addListener(new PathChildrenCacheListener() {
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
StringBuilder sb = (new StringBuilder("zookeeper event received: type=")).append(event.getType());
if (event.getData() != null) {
ChildData data = event.getData();
sb.append(", path=").append(data.getPath()).append(", stat=").append(data.getStat());
}
RoundRobinJedisPool.LOG.info(sb.toString());
if (RoundRobinJedisPool.RESET_TYPES.contains(event.getType())) {
RoundRobinJedisPool.this.resetPools();
}
}
});
相对于redis cluster的优劣?
redis cluster基于smart client和无中心的设计,client必须按key的哈希将请求直接发送到对应的节点。这意味着:使用官方cluster必须要等对应语言的redis driver对cluster支持的开发和不断成熟;client不能直接像单机一样使用pipeline来提高效率,想同时执行多个请求来提速必须在client端自行实现异步逻辑。 而codis因其有中心节点、基于proxy的设计,对client来说可以像对单机redis一样去操作proxy(除了一些命令不支持),还可以继续使用pipeline并且如果后台redis有多个的话速度会显著快于单redis的pipeline。
个人能力有限,目前只了解这么多了,目前正在对次中间件做考察,后期将用于生产环境