Redis 集群 Codis

前置知识

分片

如果没有分片机制,Redis就被局限于单机所支持的内存容量。Redis的分片机制允许数据拆分存放在不同的Redis实例上,每个Redis实例只包含所有键的子集。可以减轻单台Redis的压力,提升Redis扩展能力和计算能力。如果我们只使用一个Redis实例,当Redis宕机将会直接停止服务,所以我们可以采取分片机制,将原本一台Redis实例维护的数据,改为由多个Redis实例共同维护这部分数据。

范围分片

分片需要将不同key映射到不同Redis实例上存储,所以key的映射规则需要制定一个算法,最简单的一个分片方案应该是范围分片。范围分片理解起来很简单,比如我们存储用户基本信息,我们制定一个算法将用户userid从0到1000映射到实例A,userid从1000到2000映射到实例B,以此类推。这个方案很轻松可以使用,但是引发了一个问题:我们需要维护user_id范围和映射实例之间的关系。而正是这个问题导致范围分片虽然简单,但是效率比其他分片方案低效许多,所以Redis中一般不会使用范围分片作为分片方案。

哈希分片

比如我们目前有四个Redis实例,我们需要存储一个key。我们可以通过哈希函数crc32()将key名转换成一个长整型数字,然后对长整型数字对4取余,就可以得到映射的实例。但是这种分配方案一样存在弊端:当我们需要增加或移除Redis实例时,就会造成大量key无法被命中。所以这时候出现了一种哈希分片的高级形式–一致性哈希。

一致性哈希有三大特性:

  • key哈希结果尽可能分配到不同Redis实例。
  • 当实例增加或移除,需要保护已映射的内容不会重新被分配到新实例上。
  • 对key的哈希应尽量避免重复。

但是在Redis中没有使用一致性哈希这个概念,而是引入了哈希槽。在Redis集群中共有16384个哈希槽然后每个key通过哈希函数crc16()将key名转化成一个长整型数字再对16384取余,最终决定这个key存储的哈希槽。而每个Redis实例负责维护一部分哈希槽,所有实例共同维护所有的哈希槽。使用哈希槽最显而易见的特点就是Redis实例的增加或者移除很方便,而不需要暂停所有Redis实例服务。

分片实现

数据分片方式一般有三种:客户端分片、代理分片和服务器分片。

客户端分片

定义:客户端自己计算key需要映射到哪一个Redis实例。
优点:客户端分片最明显的好处在于降低了集群的复杂度,而服务器之间没有任何关联性,数据分片由客户端来负责实现。
缺点:客户端实现分片则客户端需要知道当前集群下不同Redis实例的信息,当新增Redis实例时需要支持动态分片,多数Redis需要重启才能实现该功能。

代理分片

定义:客户端将请求发送到代理,代理通过计算得到需要映射的集群实例信息,然后将客户端的请求转发到对应的集群实例上,然后返回响应给客户端。
优点:降低了客户端的复杂度,客户端不用关心后端Redis实例的状态信息。
缺点:多了一个中间分发环节,所以对性能有些损失。

服务端分片

定义:客户端可以和集群中任意Redis实例通信,当客户端访问某个实例时,服务器进行计算key应该映射到哪个具体的Redis实例中存储,如果映射的实例不是当前实例,则该实例主动引导客户端去对应实例对key进行操作。这其实是一个重定向的过程。这个过程不是从当前Redis实例转发到对应的Redis实例,而是客户端收到服务器通知具体映射的Redis实例重定向到映射的实例中。当前还不能完全适用于生产环境。
优点:支持高可用,任意实例都有主从,主挂了从会自动接管。
缺点:需要客户端语言实现服务器集群协议,但是目前大多数语言都有其客户端实现版本。

预分片

从上面可以清楚地看出,分片机制增加或移除实例是非常麻烦的一件事,所以我们可以考虑一开始就开启32个节点实例,当我们可以新增Redis服务器时,我们可以将一半的节点移动到新的Redis服务器。这样我们只需要在新服务器启动一个空节点,然后移动数据,配置新节点为源节点的从节点,然后更新被移动节点的ip信息,然后向新服务器发送slaveof命令关闭主从配置,最后关闭旧服务器不需要使用的实例并且重新启动客户端。这样我们就可以在几乎不需要停机时间时完成数据的移动。

分片的缺点

  • 分片是由多台Redis实例共同运转,所以如果其中一个Redis实例宕机,则整个分片都将无法使用,所以分片机制无法实现高可用。
  • 如果有不同的key映射到不同的Redis实例,这时候不能对这两个key做交集或者使用事务。
  • 使用分片机制因为涉及多实例,数据处理比较复杂。
  • 分片中对于实例的添加或删除会很复杂,不过可以使用预分片技术进行改善。

codis的分片

Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。

每一个 slot 都会有一个且必须有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。数据的迁移也是以slot为单位的。

在Codis中,Codis会把所有的key分成1024个槽,这1024个槽对应着的就是Redis的集群,这个在Codis中是会在内存中维护着这1024个槽与Redis实例的映射关系。这个槽是可以配置,可以设置成 2048 或者是4096个。看你的Redis的节点数量有多少,偏多的话,可以设置槽多一些。
Codis中key的分配算法,先是把key进行CRC32 后,得到一个32位的数字,然后再hash%1024后得到一个余数,这个值就是这个key对应着的槽,这槽后面对应着的就是redis的实例。

CRC32:CRC本身是“冗余校验码”的意思,CRC32则表示会产生一个32bit(8位十六进制数)的校验值。由于CRC32产生校验值时源数据块的每一个bit(位)都参与了计算,所以数据块中即使只有一位发生了变化,也会得到不同的CRC32值。

Codis之间的槽位同步

Codis把槽位信息同步的工作交给了ZooKeeper来管理,当Codis的Codis Dashbord 改变槽位的信息的时候,其他的Codis节点会监听到ZooKeeper的槽位变化,会及时同步过来。如图:

codis 槽位同步

Codis中的扩容

因为Codis是一个代理中间件,所以这个当需要扩容Redis实例的时候,可以直接增加redis节点。在槽位分配的时候,可以手动指定Codis Dashbord来为新增的节点来分配特定的槽位。
在Codis中实现了自定义的扫描指令SLOTSSCAN,可以扫描指定的slot下的所有的key,将这些key迁移到新的Redis的节点中(话外语:这个是Codis定制化的其中一个好处)。
首先,在迁移的时候,会在原来的Redis节点和新的Redis里都保存着迁移的槽位信息,在迁移的过程中,如果有key打进将要迁移或者正在迁移的旧槽位的时候,这个时候Codis的处理机制是,先是将这个key强制迁移到新的Redis节点中,然后再告诉Codis,下次如果有新的key的打在这个槽位中的话,那么转发到新的节点。

自动均衡策略

面对着上面讲的迁移策略,如果有成千上万个节点新增进来,都需要我们手动去迁移吗?那岂不是得累死啊。当然,Codis也是考虑到了这一点,所以提供了自动均衡策略。自动均衡策略是这样的,Codis 会在机器空闲的时候,观察Redis中的实例对应着的slot数,如果不平衡的话就会自动进行迁移。

Codis简介

Tip: 抄自官方介绍,目前我使用的是Codis3.x的,所以下面全部说的全部指代的是Codis3.x的。

codis 架构图

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有显著区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务。

Codis由以下组件组成:

  • Codis Server:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。具体的修改可以参考文档 redis 的修改
  • Codis Proxy:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外(不支持的命令列表),表现的和原生的 Redis 没有区别(就像 Twemproxy)。
    • 对于同一个业务集群而言,可以同时部署多个 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 列表,配置文件可自动更新。
  • Storage:为集群状态提供外部存储。
    • 提供 Namespace 概念,不同集群的会按照不同 product name 进行组织;
    • 目前仅提供了 Zookeeper、Etcd、Fs 三种实现,但是提供了抽象的 interface 可自行扩展。

来说说我对以上各种名词的理解:

Codis Server,就是经过一定改造的redis-server端,也就是redis的服务端,通过改造,从而增加了redis能支持的更多数据结构,也就是额外的数据类型。

Codis Proxy,客户端连接的 Redis 代理服务, 实现了 Redis 协议。当我们程序想连接到Codis Server的时候怎么连接呢,肯定不是直接连接,因为后端的Codis Server可能是一个业务集群,有很多台Codis Server,那就需要连接到Codis Proxy,然后Codis Proxy会给我们转发到对应的Codis Server上去,这种做法类似一种负载均衡的解决方案。

Codis安装

安装codis需要先安装go环境,官方文档已经好几年没更新了,上面写的是用的go1.7版本。我今天装的是go1.14版本。

安装go1.14

  1. 下载go

    1
    $ wget -c https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local
  2. 新建go工作文件夹

    1
    $ mkdir -vp /opt/{src/,pkg/,bin/}
  3. 设置环境变量

    在~/.bashrc中添加对应的环境变量。

    1
    2
    3
    export GOPATH=/opt/go
    export GOROOT=/usr/local/go
    export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

    然后刷新环境变量

    1
    $ source ~/.bashrc
  4. 查看go的env

    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
    $ go env
    GO111MODULE="off"
    GOARCH="amd64"
    GOBIN=""
    GOCACHE="/root/.cache/go-build"
    GOENV="/root/.config/go/env"
    GOEXE=""
    GOFLAGS=""
    GOHOSTARCH="amd64"
    GOHOSTOS="linux"
    GOINSECURE=""
    GONOPROXY=""
    GONOSUMDB=""
    GOOS="linux"
    GOPATH="/opt/go"
    GOPRIVATE=""
    GOPROXY="https://goproxy.cn,direct"
    GOROOT="/usr/local/go"
    GOSUMDB="sum.golang.org"
    GOTMPDIR=""
    GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
    GCCGO="gccgo"
    AR="ar"
    CC="gcc"
    CXX="g++"
    CGO_ENABLED="1"
    GOMOD=""
    CGO_CFLAGS="-g -O2"
    CGO_CPPFLAGS=""
    CGO_CXXFLAGS="-g -O2"
    CGO_FFLAGS="-g -O2"
    CGO_LDFLAGS="-g -O2"
    PKG_CONFIG="pkg-config"
    GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build187617497=/tmp/go-build -gno-record-gcc-switches"

Tip:一定要将GO111MODULE设置为off,不然codis会编译不通过。

设置方式为:go env -w GO111MODULE="off"

安装zookeeper

  1. zookeeper的下载

    进入官方下载地址选择要下载的版本。点我下载

  2. 解压下载的压缩包

    1
    $ tar -zxvf apache-zookeeper-3.6.0-bin.tar.gz -C /opt && mv /opt/apache-zookeeper-3.6.0-3.6.0-bin /opt/zookeeper
  3. 创建数据存放目录并修改配置文件

    1
    2
    $ mkdir /opt/zookeeper/data 
    $ cd /opt/zookeeper/conf && cp zoo_sample.cfg zoo.cfg

    修改配置文件zoo.cnf中的dataDir为/opt/zookeeper/data/

  4. 启动zookeeper

    1
    2
    $ cd /opt/zookeeper/bin
    $ ./zkServer.sh start

编译安装codis

  1. 下载codis源码

    1
    2
    $ mkdir -p $GOPATH/src/github.com/CodisLabs
    $ cd $_ && git clone https://github.com/CodisLabs/codis.git -b release3.2
  2. 编译codis源码

    Tip:一定要将GO111MODULE设置为off,不然会编译不过。

    因为源码目录下有个vendor目录,已经包含了所需的所有pkg

    1
    2
    3
    4
    5
    6
    7
    8
    $ cd $GOPATH/src/github.com/CodisLabs/codis
    $ make
    make -j -C extern/redis-3.2.8/
    ... ...
    go build -i -o bin/codis-dashboard ./cmd/dashboard
    go build -i -o bin/codis-proxy ./cmd/proxy
    go build -i -o bin/codis-admin ./cmd/admin
    go build -i -o bin/codis-fe ./cmd/fe
  3. 查看编译之后的命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ ls bin/
    total 95724
    drwxr-xr-x 3 root root 4096 May 2 21:50 ./
    drwxr-xr-x 18 root root 4096 May 3 12:06 ../
    drwxr-xr-x 4 root root 4096 May 2 21:42 assets/
    -rwxr-xr-x 1 root root 15785824 May 2 21:42 codis-admin*
    -rwxr-xr-x 1 root root 16705984 May 2 21:41 codis-dashboard*
    -rw-r--r-- 1 root root 4 May 2 21:43 codis-dashboard.pid
    -rwxr-xr-x 1 root root 15091792 May 2 21:42 codis-fe*
    -rwxr-xr-x 1 root root 15090216 May 2 21:42 codis-ha*
    -rwxr-xr-x 1 root root 17703112 May 2 21:42 codis-proxy*
    -rw-r--r-- 1 root root 4 May 2 21:50 codis-proxy.pid
    -rwxr-xr-x 1 root root 5928296 May 2 21:41 codis-server*
    -rwxr-xr-x 1 root root 2773360 May 2 21:41 redis-benchmark*
    -rwxr-xr-x 1 root root 2969544 May 2 21:41 redis-cli*
    -rwxr-xr-x 1 root root 5928296 May 2 21:41 redis-sentinel*
    -rw-r--r-- 1 root root 169 May 2 21:41 version

    可以看出是编译成功了。

Codis启动

codis 有多种启动方式,下面介绍每一种启动方式。

快速启动

Tip: 我没有按照这种方式启动过,该段参考官网文档,这种启动方式只是作为演示或者测试用。

查看日志的时候,记得日志文件名字,文件名字中的日期是你启动当天的日期。

源码中 admin 文件夹提供了一系列脚本以便快速启动、停止各个组件,提高运维效率。

1
2
3
4
5
6
7
8
9
10
$ pwd
/opt/go/src/github.com/CodisLabs/codis
$ ll admin
total 24
drwxr-xr-x 2 root root 4096 May 2 22:39 ./
drwxr-xr-x 18 root root 4096 May 3 12:06 ../
-rwxr-xr-x 1 root root 2282 May 2 21:14 codis-dashboard-admin.sh*
-rwxr-xr-x 1 root root 1796 May 2 21:14 codis-fe-admin.sh*
-rwxr-xr-x 1 root root 2102 May 2 21:14 codis-proxy-admin.sh*
-rwxr-xr-x 1 root root 1722 May 2 21:14 codis-server-admin.sh*
  1. 启动codis-dashboard

    使用 codis-dashboard-admin.sh 脚本启动 dashboard,并查看 dashboard 日志确认启动是否有异常。

    1
    $ ./admin/codis-dashboard-admin.sh start

    然后查看启动日志:

    1
    2
    3
    4
    $  tail -100 ./log/codis-dashboard.log.2017-04-08
    2017/04/08 15:16:57 fsclient.go:197: [INFO] fsclient - create /codis3/codis-demo/topom OK
    2017/04/08 15:16:57 main.go:140: [WARN] [0xc42025f7a0] dashboard is working ...
    2017/04/08 15:16:57 topom.go:424: [WARN] admin start service on [::]:18080

    快速启动集群元数据存储使用 filesystem,默认数据路径保存在 /tmp/codis,若启动失败,请检查当前用户是否对该路径拥有读写权限。

  2. 启动codis-proxy

    使用 codis-proxy-admin.sh 脚本启动 codis-proxy,并查看 proxy 日志确认启动是否有异常。

    1
    $ ./admin/codis-proxy-admin.sh start

    然后查看启动日志:

    1
    2
    3
    4
    $ tail -100 ./log/codis-proxy.log.2017-04-08
    2017/04/08 15:39:37 proxy.go:293: [WARN] [0xc4200df760] set sentinels = []
    2017/04/08 15:39:37 main.go:320: [WARN] rpc online proxy seems OK
    2017/04/08 15:39:38 main.go:210: [WARN] [0xc4200df760] proxy is working ...
  3. 启动codis-server

    使用 codis-server-admin.sh 脚本启动 codis-server,并查看 redis 日志确认启动是否有异常。

    1
    $ ./admin/codis-server-admin.sh start

    然后查看启动日志:

    1
    2
    3
    $ tail -100 /tmp/redis_6379.log 
    5706:M 08 Apr 16:04:11.748 * DB loaded from disk: 0.000 seconds
    5706:M 08 Apr 16:04:11.748 * The server is now ready to accept connections on port 6379

    Tip: redis.conf 配置中 pidfile、logfile 默认保存在 /tmp 目录,若启动失败,请检查当前用户是否有该目录的读写权限。

  4. 启动codis-fe

    使用 codis-fe-admin.sh 脚本启动 codis-fe,并查看 fe 日志确认启动是否有异常。

    1
    $ ./admin/codis-fe-admin.sh start

    然后查看启动日志:

    1
    2
    3
    4
    5
    $ tail -100 ./log/codis-fe.log.2022-05-03
    2017/04/08 16:12:13 main.go:100: [WARN] set ncpu = 1
    2017/04/08 16:12:13 main.go:103: [WARN] set listen = 0.0.0.0:9090
    2017/04/08 16:12:13 main.go:115: [WARN] set assets = /home/codis/go/src/github.com/CodisLabs/codis/admin/../bin/assets
    2017/04/08 16:12:13 main.go:153: [WARN] set --filesystem = /tmp/codis

通过ansible 快速部署集群

使用 ansible 可快速在单机、多机部署多套 codis 集群。 ansible 文件夹包含了部署 codis 集群的 playbook,根据自己部署环境修改 groups_var/all 文件里参数,修改 hosts 文件添加部署的环境 IP 即可。 ansible 安装也及其简单,各部署机器无需安装任何额外的 agent,彼此之间通过 ssh 通信。

1
2
3
4
5
$ git clone https://github.com/ansible/ansible.git -b stable-2.3
$ cd ./ansible
$ source ./hacking/env-setup
$ cd $codis_dir/ansible
$ ansible-playbook -i hosts site.yml

Tip:这种方式可以大规模在多台主机中部署 codis 集群。

相关的ansible文档可以参考https://ansible-tran.readthedocs.io/en/latest/docs/intro.html

通过命令行启动

Tip: 请按照顺序逐步完成操作。生产环境建议修改dashboard coordinator_name配置,使用 zookeeperetctd作为外部存储。

Codis 3.x 支持 AUTH,但是要求所有组件使用的 AUTH 必须完全相同。

另外,该启动命令是在源码目录下的**./bin目录下,不再是./admin**目录下。

Codis Dashboard

Tip: 各启动命令中的参数目录需要替换成正确的路径,可以是绝对路径或者是相对路径。

  1. 启动命令

    1
    2
    $ nohup ./bin/codis-dashboard --ncpu=4 --config=dashboard.toml \
    --log=dashboard.log --log-level=WARN &

    默认配置文件 dashboard.toml 可由 codis-dashboard 生成。具体生成方式参考下一条。

  2. 详细说明

    启动参数说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ ./bin/codis-dashboard -h
    Usage:
    codis-dashboard [--ncpu=N] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR]
    codis-dashboard --default-config
    codis-dashboard --version

    Options:
    --ncpu=N 最大使用 CPU 个数
    -c CONF, --config=CONF 指定启动配置文件
    -l FILE, --log=FILE 设置 log 输出文件
    --log-level=LEVEL 设置 log 输出等级:INFO,WARN,DEBUG,ERROR;默认INFO,推荐WARN

    参数 --host-admin 请参见与 Docker 有关章节。

    生成默认配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ ./bin/codis-dashboard --default-config | tee dashboard.toml
    ##################################################
    # #
    # Codis-Dashboard #
    # #
    ##################################################

    # 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"
    product_auth = ""

    # Set bind address for admin(rpc), tcp only.
    admin_addr = "0.0.0.0:18080"
    参数 说明
    coordinator_name 外部存储类型,接受 zookeeper/etcd
    coordinator_addr 外部存储地址
    product_name 集群名称,满足正则 \w[\w\.\-]*
    product_auth 集群密码,默认为空
    admin_addr RESTful API 端口

Codis Proxy

  1. 启动命令

    1
    2
    nohup ./bin/codis-proxy --ncpu=4 --config=proxy.toml \
    --log=proxy.log --log-level=WARN &

    默认配置文件 proxy.toml 可由 codis-proxy 生成。具体生成方式参考下方说明。

    codis-proxy 启动后,处于 waiting 状态,监听 proxy_addr 地址,但是不会 accept 连接,添加到集群并完成集群状态的同步,才能改变状态为 online。添加的方法有以下两种:

    • 通过 codis-fe 添加:通过 Add Proxy 按钮,将 admin_addr 加入到集群中;
    • 通过 codis-admin 命令行工具添加,方法如下:
    1
    $ ./bin/codis-admin --dashboard=127.0.0.1:18080 --create-proxy -x 127.0.0.1:11080

    其中 127.0.0.1:18080 以及 127.0.0.1:11080 分别为 dashboard 和 proxy 的 admin_addr 地址;

    添加过程中,dashboard 会完成如下一系列动作:

    • 获取 proxy 信息,对集群 name 以及 auth 进行验证,并将其信息写入到外部存储中;
    • 同步 slots 状态;
    • 标记 proxy 状态为 online,此后 proxy 开始 accept 连接并开始提供服务;
  2. 详细说明

    启动参数说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $ ./bin/codis-proxy -h
    Usage:
    codis-proxy [--ncpu=N] [--config=CONF] [--log=FILE] [--log-level=LEVEL] [--host-admin=ADDR] [--host-proxy=ADDR] [--ulimit=NLIMIT]
    codis-proxy --default-config
    codis-proxy --version

    Options:
    --ncpu=N 最大使用 CPU 个数
    -c CONF, --config=CONF 指定启动配置文件
    -l FILE, --log=FILE 设置 log 输出文件
    --log-level=LEVEL 设置 log 输出等级:INFO,WARN,DEBUG,ERROR;默认INFO,推荐WARN
    --ulimit=NLIMIT 检查 ulimit -n 的结果,确保运行时最大文件描述不少于 NLIMIT

    参数 --host-proxy 以及 --host-admin 请参见与 Docker 有关章节。

    生成默认配置文件

    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
    $ ./bin/codis-proxy --default-config | tee proxy.toml
    ##################################################
    # #
    # Codis-Proxy #
    # #
    ##################################################

    # Set Codis Product {Name/Auth}.
    product_name = "codis-demo"
    product_auth = ""

    # Set bind address for admin(rpc), tcp only.
    admin_addr = "0.0.0.0:11080"

    # 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"

    # Set jodis address & session timeout.
    jodis_addr = ""
    jodis_timeout = 10
    jodis_compatible = false

    # Proxy will ping-pong backend redis periodly to keep-alive
    backend_ping_period = 5

    # If there is no request from client for a long time, the connection will be droped. Set 0 to disable.
    session_max_timeout = 1800

    # Buffer size for each client connection.
    session_max_bufsize = 131072

    # Number of buffered requests for each client connection.
    # Make sure this is higher than the max number of requests for each pipeline request, or your client may be blocked.
    session_max_pipeline = 1024

    # Set period between keep alives. Set 0 to disable.
    session_keepalive_period = 60
    参数 说明
    product_name 集群名称,参考 dashboard 参数说明
    product_auth 集群密码,默认为空
    admin_addr RESTful API 端口
    proto_type Redis 端口类型,接受 tcp/tcp4/tcp6/unix/unixpacket
    proxy_addr Redis 端口地址或者路径
    jodis_addr Jodis 注册 zookeeper 地址
    jodis_timeout Jodis 注册 session timeout 时间,单位 second
    jodis_compatible Jodis 注册 zookeeper 的路径
    backend_ping_period 与 codis-server 探活周期,单位 second,0 表示禁止
    session_max_timeout 与 client 连接最大读超时,单位 second,0 表示禁止
    session_max_bufsize 与 client 连接读写缓冲区大小,单位 byte
    session_max_pipeline 与 client 连接最大的 pipeline 大小
    session_keepalive_period 与 client 的 tcp keepalive 周期,仅 tcp 有效,0 表示禁止

    Tip: Codis3 会将 jodis 节点注册在 /jodis/{PRODUCT_NAME} 下,这点与 Codis2 不太兼容,所以为了兼容性,可以考虑将 jodis_compatible 设置成 true

Codis Server

其实就是一个 redis server 端,从新命名了而已。

  1. 启动命令

    1
    $ nohup ./bin/codis-server > codis-server.log 2>&1 &

    启动 ./bin/codis-server,与启动普通 redis 的方法一致。

  2. 详细说明

    启动参数说明:

    Tip: 可以看出,命令都没有变,但是还得需要用codis-server去启动,因为系统中没有redis-server命令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ ./bin/codis-server -h
    Usage: ./redis-server [/path/to/redis.conf] [options] 根据配置文件去启动
    ./redis-server - (read config from stdin) 根据标准输入来启动
    ./redis-server -v or --version 版本号
    ./redis-server -h or --help 帮助信息
    ./redis-server --test-memory <megabytes> 看看有多少内存

    Examples:
    ./redis-server (run the server with default conf)
    ./redis-server /etc/redis/6379.conf
    ./redis-server --port 7777
    ./redis-server --port 7777 --slaveof 127.0.0.1 8888
    ./redis-server /etc/myredis.conf --loglevel verbose

    Sentinel mode:
    ./redis-server /etc/sentinel.conf --sentinel

    默认的配置文件在源码目录config/redis.conf中。具体配置的各项配置可以查看文档:菜鸟redis文档

    简单的启动就是./bin/codis-server --port=6379

Codis Fe

可选组件。

  1. 启动命令

    1
    2
    $ nohup ./bin/codis-fe --ncpu=4 --log=fe.log --log-level=WARN \
    --zookeeper=127.0.0.1:2181 --listen=127.0.0.1:8080 &
  2. 详细说明

    启动参数说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ ./bin/codis-fe -h
    Usage:
    codis-fe [--ncpu=N] [--log=FILE] [--log-level=LEVEL] [--assets-dir=PATH] (--dashboard-list=FILE|--zookeeper=ADDR|--etcd=ADDR|--filesystem=ROOT) --listen=ADDR
    codis-fe --version

    Options:
    --ncpu=N 最大使用 CPU 个数
    -d LIST, --dashboard-list=LIST 配置文件,能够自动刷新
    -l FILE, --log=FILE 设置 log 输出文件
    --log-level=LEVEL 设置 log 输出等级:INFO,WARN,DEBUG,ERROR;默认INFO,推荐WARN
    --listen=ADDR HTTP 服务端口

    配置文件 codis.json 可以手动编辑,也可以通过 codis-admin 从外部存储中拉取,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ ./bin/codis-admin --dashboard-list --zookeeper=127.0.0.1:2181 | tee codis.json
    [
    {
    "name": "codis-demo",
    "dashboard": "127.0.0.1:18080"
    },
    {
    "name": "codis-demo2",
    "dashboard": "127.0.0.1:28080"
    }
    ]

Codis Admin

Tip: 使用 codis-admin 是十分危险的。

  1. codis-dashboard 异常退出的修复

    当 codis-dashboard 启动时,会在外部存储上存放一条数据,用于存储 dashboard 信息,同时作为 LOCK 存在。当 codis-dashboard 安全退出时,会主动删除该数据。当 codis-dashboard 异常退出时,由于之前 LOCK 未安全删除,重启往往会失败。因此 codis-admin 提供了强制删除工具:

    • 确认 codis-dashboard 进程已经退出(很重要);

    • 运行 codis-admin 删除 LOCK:

      1
      $ ./bin/codis-admin --remove-lock --product=codis-demo --zookeeper=127.0.0.1:2181
  2. codis-proxy 异常退出修复

    通常 codis-proxy 都是通过 codis-dashboard 进行移除,移除过程中 codis-dashboard 为了安全会向 codis-proxy 发送 offline 指令,成功后才会将 proxy 信息从外部存储中移除。如果 codis-proxy 异常退出,该操作会失败。此时可以使用 codis-admin 工具进行移除:

    • 确认 codis-proxy 进程已经退出(很重要);

    • 运行 codis-admin 删除 proxy:

      1
      $ ./bin/codis-admin --dashboard=127.0.0.1:18080 --remove-proxy --addr=127.0.0.1:11080 --force

    选项 --force 表示,无论 offline 操作是否成功,都从外部存储中将该节点删除。所以操作前,一定要确认该 codis-proxy 进程已经退出。

Docker 部署

Codis 3.x 起,开始正式支持 Docker 部署。这就需要 codis-dashboard 以及 codis-proxy 能够外部的 listen 地址暴露出来并保存在外部存储中。

  • codis-proxy 增加了 --host-admin 以及 --host-proxy 参数;
  • codis-dashboard 增加了 --host-admin 参数;

以 codis-proxy 的 Docker 为例:

1
2
$ docker run --name "Codis-Proxy" -d -p 29000:19000 -p 21080:11080 codis-image \
codis-proxy -c proxy.toml --host-admin 100.0.1.100:29000 --host-proxy 100.0.1.100:21080

codis-proxy 在启动后,会使用 --host-admin--host-proxy 参数所指定的实际地址替换 Docker 内监听的地址,向 codis-dashboard 注册。这样,例如使用 Jodis 的过程中,客户端就能够通过 100.0.1.100:29000 来访问 proxy 实例。

codis-dashboard 也是相同的道理,会使用 --host-admin 地址向外部存储注册,这样 codis-fe 也能通过该地址正确的对 codis-dashboard 进行操作。

具体样例可以参考 scripts/docker.sh

Codis实战

当我们按照上面命令启动了一个 codis 默认集群的时候,我们就可以打开 codis-fe 页面。默认地址为 127.0.0.1:8088。

Tip: 如果是部署在云主机上,需要打开防火墙端口,并将127.0.0.1更改为你的外网ip。

image-20220503141228742

可以看到上面已经有一个 codis-demo 业务集群了。

新增一个业务集群

新增一个 hello-world 的业务集群。

Tip: 以下操作都在源码目录下完成。请自己提前装好zookeeper,以下都会依赖zookeeper。

codis-dashboard

  1. 生成一个配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $ ./bin/codis-dashboard --default-config | tee ./config/dashboard_2.toml
    ##################################################
    # #
    # Codis-Dashboard #
    # #
    ##################################################

    # 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"
    product_auth = ""

    # Set bind address for admin(rpc), tcp only.
    admin_addr = "0.0.0.0:18080"

    修改配置文件中的 product_namehello-world,如果需要的话,也可以设置product_auth,然后更改admin_addr=”0.0.0.0:18081”

  2. 启动 codis-dashboard

    1
    $ nohup ./bin/codis-dashboard --ncpu=1 --config=./config/dashboard_2.toml --log=./log/dashboard_2.log --log-level=WARN &
  3. 查看 codis-fe 面板

    image-20220503182611019

    发现已经添加上了。因为我们是将集群信息注册到zookeeper中的。

    查看zookeeper中的信息:

    1
    2
    3
    4
    ls /
    [admin, brokers, cluster, codis3, config, consumers, controller, controller_epoch, feature, isr_change_notification, latest_producer_id_block, log_dir_event_notification, zookeeper]
    ls /codis3
    [codis-demo, hello-world]

    可以看到有两个节点信息。如果是 etcd 或者 fs 也是同样的道理。

codis-proxy

  1. 生成一个配置文件

    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
    $ ./bin/codis-proxy --default-config | tee proxy_2.toml
    ##################################################
    # #
    # Codis-Proxy #
    # #
    ##################################################

    # Set Codis Product {Name/Auth}.
    product_name = "codis-demo"
    product_auth = ""

    # Set bind address for admin(rpc), tcp only.
    admin_addr = "0.0.0.0:11080"

    # 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"

    # Set jodis address & session timeout.
    jodis_addr = ""
    jodis_timeout = 10
    jodis_compatible = false

    # Proxy will ping-pong backend redis periodly to keep-alive
    backend_ping_period = 5

    # If there is no request from client for a long time, the connection will be droped. Set 0 to disable.
    session_max_timeout = 1800

    # Buffer size for each client connection.
    session_max_bufsize = 131072

    # Number of buffered requests for each client connection.
    # Make sure this is higher than the max number of requests for each pipeline request, or your client may be blocked.
    session_max_pipeline = 1024

    # Set period between keep alives. Set 0 to disable.
    session_keepalive_period = 60

    修改其中的 product_name 为 hello-world,admin_addr 为 0.0.0.0:11081,proxy_addr 为 0.0.0.0:19001,然后启动:

    1
    $ nohup ./bin/codis-proxy --ncpu=1 --config=./config/proxy_2.toml --log=proxy_2.log --log-level=WARN &

codis-fe

  1. 在 hello-world 集群的 proxy 添加 codis-proxy,填写的地址是你设置的 admin_addr,也就是0.0.0.0:11081,点击New Proxy就ok了。

    添加 codis-proxy

  2. 添加 group

    添加 NEW GROUPNEW GROUP 行输入 1,再点击 NEW GROUP 即可 添加 Codis Server,Add Server 行输入我们刚刚启动的 codis-server 地址,添加到我们刚新建的 Group,然后再点击 Add Server 按钮即可,

    添加 group

  3. 初始化 slot

    新增的集群 slot 状态是 offline,因此我们需要对它进行初始化(将 1024 个 slot 分配到各个 group),而初始化最快的方法可通过 fe 提供的 rebalance all slots 按钮来做,如下图所示,点击此按钮,我们即快速完成了一个集群的搭建。

    初始化 slot

    点击 Rebalance All Slots,将所有的 slot全部分配给 group就ok了。

至此,该 redis 集群就是一个可用的状态。但是这只是一个简单的单机redis,我们来多添加几个 codis-server 。

codis-server

我们使用如下命令实例化多个 redis ,也就是 codis-server:

1
2
3
4
5
6
7
8
$ nohup ./bin/codis-server --port 6378 > ./log/codis-server_6378.log 2>&1 &
$ nohup ./bin/codis-server --port 6377 > ./log/codis-server_6377.log 2>&1 &
$ nohup ./bin/codis-server --port 6376 > ./log/codis-server_6376.log 2>&1 &
$ ps -aux | grep codis-server | grep -v grep
root 5525 0.0 0.1 49976 7032 ? Sl 12:02 0:22 ./bin/codis-server *:6378
root 6207 0.0 0.1 47928 6716 ? Sl 12:05 0:20 ./bin/codis-server *:6377
root 17478 0.0 0.1 52024 7312 ? Sl May02 1:04 ./bin/codis-server *:6379
root 20183 0.0 0.1 47928 6260 pts/0 Sl 22:24 0:00 ./bin/codis-server *:6376

可以看见我们启动了很多,然后我们将其加入到 group 中去。

codis group

6376、6377、6378的master都是6379。

我们来验证一下,我们在master上,也就是6379上添加一条数据,看能不能同步到其他salve上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ./bin/redis-cli -p 6379
127.0.0.1:6379> set codis-test 123
OK
127.0.0.1:6379> get codis-test
"123"
127.0.0.1:6379>

$ ./bin/redis-cli -p 6378
127.0.0.1:6378> get codis-test
"123"

$ ./bin/redis-cli -p 6377
127.0.0.1:6377> get codis-test
"123"

$ ./bin/redis-cli -p 6376
127.0.0.1:6376> get codis-test
"123"

可以看到,是全部同步到了。

codis官方说,使用codis-proxy和使用原生的redis没什么区别,那么我们就用用 codis-proxy 来读取数据试试。我们给 hello-world 设置的codis-proxy 的 proxy_addr是0.0.0.0:19001,就用redis-cli连接19001端口查询数据试试。

1
2
3
$ ./bin/redis-cli -p 19001
127.0.0.1:19001> get codis-test
"123"

也是能读取到数据的。

我们在给当前业务集群添加一个 codis-proxy 试试。这次添加的 proxy_addr 端口为 19002,admin_addr端口为11082。如下:

codis proxy

然后我们测试一下通过新的proxy是否可以获取到数据:

1
2
3
$ ./bin/redis-cli -p 19002
127.0.0.1:19002> get codis-test
"123"

Perfect!

最后,展示一下我们公司在生产环境的图:

codis

参考


Redis 集群 Codis
https://randzz.cn/a9e3e0dfb263/redis-集群-codis/
作者
Ezreal Rao
发布于
2022年5月3日
许可协议