Redis集群化方案


Redis使用中遇到的瓶颈

我们日常在对于redis的使用中,经常会遇到一些问题
1、高可用问题,如何保证redis的持续高可用性。
2、容量问题,单实例redis内存无法无限扩充,达到32G后就进入了64位世界,性能下降。
3、并发性能问题,redis号称单实例10万并发,但也是有尽头的。

Redis集群化的优势  

1、高可用,高并发,高性能

Redis集群化的挑战

1、低概率的漏key风险,redis集群从节点的备份为异步备份(为保持高性能)
2、涉及多个key的操作通常是不被支持的。
举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。
3、涉及多个key的redis事务不能使用。
4、不能保证集群内的数据均衡。
分区的粒度是key,如果某个key的值是巨大的set、list,无法进行拆分。
5、增加或删除容量也比较复杂。
redis集群需要支持在运行时增加、删除节点的透明数据平衡的能力。

Redis集群的几种实现方式

1、客户端分片(不打算采用) 特性:

  • 优点
    • 简单,性能高。
  • 缺点
    • 业务逻辑与数据存储逻辑耦合
    • 可运维性差
    • 多业务各自使用redis,集群资源难以管理
    • 不支持动态增删节点

2、基于代理的分片 客户端发送请求到一个代理,代理解析客户端的数据,将请求转发至正确的节点,然后将结果回复给客户端。

开源方案:codis

特性:

  • 透明接入
    • 业务程序不用关心后端Redis实例,切换成本低。
  • Proxy 的逻辑和存储的逻辑是隔离的。
  • 代理层多了一次转发,性能有所损耗。

3、路由查询 将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。 开源方案 Redis-cluster

Redis集群化方案

经过筛选,将codis和redis-cluster列入CRM项目redis集群化的待选方案,望领导商讨决议。 Codis VS Redis

对比参数 Codis Redis-cluster
Redis版本 基于2.8分支开发 >= 3.0
部署 较复杂。 简单
运维 Dashboard,运维方便。 运维人员手动通过命令操作。
监控 可在Dashboard里监控当前redis-server节点情况,较为便捷。 需配合其他监控应用实现(RedisLive、RedisClusterManager、等……(未调研,使用前应调研评估)
组织架构 Proxy-Based, 类中心化架构,集群管理层与存储层解耦。 P2P模型,gossip协议负责集群内部通信。去中心化
伸缩性 支持动态伸缩。 支持动态伸缩
主节点失效处理 自动选主。 自动选主。
数据迁移 简单。支持透明迁移。 需要运维人员手动操作。支持透明迁移。
升级 基于redis 2.8分支开发,后续升级不能保证;Redis-server必须是此版本的codis,无法使用新版本redis的增强特性。 Redis官方推出,后续升级可保证。
可靠性 经过线上服务验证,可靠性较高。 新推出,坑会比较多。遇到bug之后需要等官网升级。

本对比基于2016.09,参考时请考虑其时效性

一、Redis-Cluster

1.1、redis cluster的现状   目前redis支持的cluster特性:   1):节点自动发现   2):slave->master 选举,集群容错   3):Hot resharding:在线分片   4):进群管理:cluster xxx   5):基于配置(nodes-port.conf)的集群管理   6):ASK 转向/MOVED 转向机制. 1.2、redis cluster 架构   1)redis-cluster架构图

  架构细节:   (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.   (2)节点的fail是通过集群中超过半数的节点检测失效时才生效.   (3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可   (4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

2) redis-cluster选举:容错

  (1)领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.   (2):什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误   a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.   b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态.

二、redis cluster安装

1、准备服务器,并在每台服务器安装好redis。(具体使用多少台机器应升级请教)

2、创建redis节点 假设2台服务器,分别为:192.168.1.237,192.168.1.238.每分服务器有3个节点。 我先在192.168.1.237创建3个节点:

  cd /usr/local/
  mkdir redis_cluster  //创建集群目录
  mkdir 7000 7001 7002  //分别代表三个节点    其对应端口 7000 7001 7002
 //创建7000节点,拷贝到7000目录
 cp /usr/local/redis-3.2.1/redis.conf  ./redis_cluster/7000/   
 //拷贝到7001目录
 cp /usr/local/redis-3.2.1/redis.conf  ./redis_cluster/7001/   
 //拷贝到7002目录
 cp /usr/local/redis-3.2.1/redis.conf  ./redis_cluster/7002/

分别对7001,7002、7003文件夹中的3个文件修改对应的配置

daemonize    yes                          //redis后台运行
pidfile  /var/run/redis_7000.pid          //pidfile文件对应7000,7002,7003
port  7000                                //端口7000,7002,7003
cluster-enabled  yes                      //开启集群  把注释#去掉
cluster-config-file  nodes_7000.conf      //集群的配置  配置文件首次启动自动生成 7000,7001,7002
cluster-node-timeout  5000                //请求超时  设置5秒够了
appendonly  yes                           //aof日志开启

有需要就开启,它会每次写操作都记录一条日志

在192.168.1.238创建3个节点:对应的端口改为7003,7004,7005.配置对应的改一下就可以了。 3、两台机启动各节点(两台服务器方式一样)

cd /usr/local
redis-server  redis_cluster/7000/redis.conf
redis-server  redis_cluster/7001/redis.conf
redis-server  redis_cluster/7002/redis.conf
redis-server  redis_cluster/7003/redis.conf
redis-server  redis_cluster/7004/redis.conf
redis-server  redis_cluster/7005/redis.conf

4、查看服务

    ps -ef | grep redis   #查看是否启动成功
    netstat -tnlp | grep redis #可以看到redis监听端口

三、创建集群 准备好了搭建集群的redis节点,接下来要把这些节点都串连起来搭建集群。官方提供了一个工具:redis-trib.rb(/usr/local/redis-3.2.1/src/redis-trib.rb),它是用ruby写的一个程序,所以需安装ruby.

yum -y install ruby ruby-devel rubygems rpm-build

再用 gem 这个命令来安装 redis接口 gem是ruby的一个工具包.

gem install redis

两台Server都要安装。 运行redis-trib.rb

 /usr/local/redis-3.2.1/src/redis-trib.rb
   Usage: redis-trib <command> <options> <arguments ...>
   reshard        host:port
                  --to <arg>
                  --yes
                  --slots <arg>
                  --from <arg>
  check          host:port
  call            host:port command arg arg .. arg
  set-timeout    host:port milliseconds
  add-node        new_host:new_port existing_host:existing_port
                  --master-id <arg>
                  --slave
  del-node        host:port node_id
  fix            host:port
  import          host:port
                  --from <arg>
  help            (show this help)
  create          host1:port1 ... hostN:portN
                  --replicas <arg>
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

使用参数create 创建 (在192.168.1.237中来创建)

 /usr/local/redis-3.2.1/src/redis-trib.rb  create  --replicas  1  192.168.1.237:7000 192.168.1.237:7001  192.168.1.237:7003 192.168.1.238:7003  192.168.1.238:7004  192.168.1.238:7005

--replicas 1 表示 自动为每一个master节点分配一个slave节点 上面有6个节点,程序会按照一定规则生成 3个master(主)3个slave(从) 防火墙一定要开放监听的端口,否则会创建失败。 运行中,提示Can I set the above configuration? (type 'yes' to accept): yes 接下来 提示 Waiting for the cluster to join.......... ,Sending Cluster Meet Message to join the Cluster. 需要到Server2上做这样的操作。 在192.168.1.238, redis-cli -c -p 700* 分别进入redis各节点的客户端命令窗口, 依次输入 cluster meet 192.168.1.238 7000…… 回到Server1,已经创建完毕了。 查看一下 /usr/local/redis/src/redis-trib.rb check 192.168.1.237:7000 到这里集群已经初步搭建好了。

四、测试 1)get 和 set数据 2)假设测试(down掉其中一台机器或某个节点)

五、CRM与REDIS-CLUSTER集群的接入 1、原crm系统通过node_redis包连接redis,采用redis-cluster集群后,redis-cluster采用去中心化方式,原连接代码无需更改。启动redis-cluster的ruby脚本不知道支不支持心跳(没有找到相关资料),不了解当应用连接的服务器挂掉之后是否可以继续保持高可用(应作实验决定是否在应用端做“连接失败连接下一个地址”的代码修改) 2、redis集群不支持涉及跨key的交集并集操作,需了解原系统涉及redis的操作是否有跨key的交并集操作,如有,应评估修改量的大小决定是否修改代码(升级请教)

二、Codis

Codis 是一个分布式 Redis 解决方式, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的差别 (不支持的命令列表), 上层应用能够像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 全部后边的一切事情, 对于前面的client来说是透明的, 能够简单的觉得后边连接的是一个内存无限大的 Redis 服务. 基本框架例如以下:

Codis 由四部分组成: Codis Proxy (codis-proxy) Codis Manager (codis-config) Codis Redis (codis-server) ZooKeeper

codis-proxy 是client连接的 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 分支, 基于 2.8.13 开发, 增加了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 仅仅能和这个版本号的 Redis 交互才干正常执行.

ZooKeeper(下面简称ZK)是一个分布式协调服务框架。能够做到各节点之间的数据强一致性。简单的理解就是在一个节点改动某个变量的值后。在其它节点能够最新的变化。这样的变化是事务性的。

通过在ZK节点上注冊监听器,就能够获得数据的变化。

Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.

注:1.codis新版本号支持redis到2.8.21
2.codis-group实现redis的水平扩展

以下我们来部署环境:

10.80.80.124 zookeeper_1 codis-configcodis-server-master,slave codis_proxy_1
10.80.80.126 zookeeper_2 codis-server-master,slavecodis _proxy_2
10.80.80.123 zookeeper_3 codis-serve-master,slavecodis _proxy_3

说明: 1.为了确保zookeeper的稳定性与可靠性。我们在124、126、123上搭建zookeeper集群来对外提供服务; 2.codis-cofig作为分布式redis的管理工具。在整个分布式server中仅仅须要一个就能够完毕管理任务。 3.codis-server和codis-proxy在3台服务器提供redis和代理服务。

一.部署zookeeper集群 1.配置hosts(在3台server上) 10.80.80.124 codis1 10.80.80.126 codis2 10.80.80.123 codis3 2.配置java环境(在3台server上)

vim /etc/profile

// JAVA
export JAVA_HOME=/usr/local/jdk1.7.0_71
export JRE_HOME=/usr/local/jdk1.7.0_71/jre
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
source /etc/profile

3.安装zookeeper(在3台server上)

cd /usr/local/src
wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
tar -zxvf zookeeper-3.4.6.tar.gz -C /usr/local

4.配置环境变量(在3台server上)

vim /etc/profile

// zookeeper
ZOOKEEPER_HOME=/usr/local/zookeeper-3.4.6
export PATH=$PATH:$ZOOKEEPER_HOME/bin
source /etc/profile

5.改动zookeeper配置文件(在3台server上)

创建zookeeper的数据文件夹和日志文件夹

mkdir -p /data/zookeeper/zk1/{data,log}
cd /usr/local/zookeeper-3.4.6/conf
cp zoo_sample.cfg zoo.cfg
vim /etc/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/zk1/data
dataLogDir=/data/zookeeper/zk1/log
clientPort=2181
server.1=codis1:2888:3888
server.2=codis2:2888:3888
server.3=codis3:2888:3888

6.在dataDir下创建myid文件。相应节点id(在3台服务器上)

// 在124上 
cd /data/zookeeper/zk1/data
echo 1 > myid
// 在126上 
cd /data/zookeeper/zk1/data
echo 2 > myid
// 在123上 
cd /data/zookeeper/zk1/data
echo 3 > myid

7.启动zookeeper服务(在3台server上)

/usr/local/zookeeper-3.4.6/bin/zkServer.sh start

注:在你所在的当前文件夹下会生成一个zookeeper.out的日志文件,里面记录了启动过程中的具体信息;因为集群没有所有信息,会报“myid 2或myid 3 未启动”的信息,当集群所有启动后就会正常,我们能够忽略。

8.查看zookeeper全部节点的状态(在3台server上)

#124
/usr/local/zookeeper-3.4.6/bin/zkServer.sh status
JMX enabled by default
Using config: /usr/local/zookeeper-3.4.6/bin/../conf/zoo.cfg
Mode: leader
#126
/usr/local/zookeeper-3.4.6/bin/zkServer.sh status
JMX enabled by default
Using config: /usr/local/zookeeper-3.4.6/bin/../conf/zoo.cfg
Mode: follower
#123
/usr/local/zookeeper-3.4.6/bin/zkServer.sh status
JMX enabled by default
Using config: /usr/local/zookeeper-3.4.6/bin/../conf/zoo.cfg
Mode: follower

二.部署codis集群 1.安装go语言(在3台server上)

tar -zxvf go1.4.2.linux-amd64.tar.gz -C /usr/local/

2.加入go环境变量(在3台server上)

vim /etc/profile

#go
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/usr/local/codis
source /etc/profile

3.安装codis(在3台server上)

go get github.com/wandoulabs/codis
cd $GOPATH/src/github.com/wandoulabs/codis

运行编译測试脚本,编译go和reids。

./bootstrap.sh make gotest #将编译好后,把bin文件夹和一些脚本复制过去/usr/local/codis文件夹下 mkdir -p /usr/local/codis/{conf,redis_conf,scripts} cp -rf bin /usr/local/codis/ cp sample/config.ini /usr/local/codis/conf/ cp -rf sample/redis_conf /usr/local/codis cp -rf sample/* /usr/local/codis/scripts
4.配置codis-proxy(在3台server上。在此以124为例)
#124
cd /usr/local/codis/conf
vim config.ini
zk=codis1:2181,codis2:2181,codis3:2181
product=codis
#此处配置图形化界面的dashboard。注意codis集群仅仅要一个就可以,因此所有指向10.80.80.124:18087
dashboard_addr=192.168.3.124:18087
coordinator=zookeeper
backend_ping_period=5
session_max_timeout=1800
session_max_bufsize=131072
session_max_pipeline=128
proxy_id=codis_proxy_1
#126
cd /usr/local/codis/conf
vim config.ini
zk=codis1:2181,codis2:2181,codis3:2181
product=codis
#此处配置图形化界面的dashboard,注意codis集群仅仅要一个就可以,因此所有指向10.80.80.124:18087
dashboard_addr=192.168.3.124:18087
coordinator=zookeeper
backend_ping_period=5
session_max_timeout=1800
session_max_bufsize=131072
session_max_pipeline=128
proxy_id=codis_proxy_2
#123
cd /usr/local/codis/conf
vim config.ini
zk=codis1:2181,codis2:2181,codis3:2181
product=codis
#此处配置图形化界面的dashboard,注意codis集群仅仅要一个就可以,因此所有指向10.80.80.124:18087
dashboard_addr=192.168.3.124:18087
coordinator=zookeeper
backend_ping_period=5
session_max_timeout=1800
session_max_bufsize=131072
session_max_pipeline=128
proxy_id=codis_proxy_3

5.改动codis-server的配置文件(在3台服务器上)

#创建codis-server的数据文件夹和日志文件夹
mkdir -p /data/codis/codis-server/{data,logs}
cd /usr/local/codis/redis_conf
#主库
vim 6380.conf
daemonize yes
pidfile /var/run/redis_6380.pid
port 6379
logfile "/data/codis_server/logs/codis_6380.log"
save 900 1
save 300 10
save 60 10000
dbfilename 6380.rdb
dir /data/codis_server/data
#从库
cp 6380.conf 6381.conf
sed -i 's/6380/6381/g' 6381.conf

6.加入内核參数

echo "vm.overcommit_memory = 1" >>  /etc/sysctl.conf
sysctl -p

7.依照启动流程启动

cat /usr/loca/codis/scripts/usage.md
start zookeeper 
change config items in config.ini 
./start_dashboard.sh 
./start_redis.sh 
./add_group.sh 
./initslot.sh 
./start_proxy.sh 
./set_proxy_online.sh

open browser to http://localhost:18087/admin 尽管scripts文件夹以下有对应启动脚本,也能够用startall.sh所有启动。但刚開始建议手动启动,以熟悉codis启动过程。

因为之前zookeeper已经启动,以下我们来启动其它项目。 注:1.在启动过程中须要指定相关日志文件夹或配置文件文件夹,为便于统一管理。我们都放在/data/codis下; 2.dashboard在codis集群中仅仅须要在一台server上启动就可以,此处在124上启动;凡是用codis_config的命令都是在124上操作,其它启动项须要在3台server上操作。 相关命令例如以下:

/usr/local/codis/bin/codis-config -h
usage: codis-config  [-c <config_file>] [-L <log_file>] [--log-level=<loglevel>]
        <command> [<args>...]
options:
   -c    set config file
   -L    set output log file, default is stdout
   --log-level=<loglevel>    set log level: info, warn, error, debug [default: info]

commands:
    server
    slot
    dashboard
    action
    proxy

(1)启动dashboard(在124上启动)

#dashboard的日志文件夹和訪问文件夹
mkdir -p /data/codis/codis_dashboard/logs
codis_home=/usr/local/codis
log_path=/data/codis/codis_dashboard/logs
nohup $codis_home/bin/codis-config -c $codis_home/conf/config.ini -L $log_path/dashboard.log dashboard --addr=:18087 --http-log=$log_path/requests.log &>/dev/null &

通过10.80.80.124:18087就可以訪问图形管理界面

(2)启动codis-server(在3台服务器上)

/usr/local/codis/bin/codis-server /data/codis_server/conf/6380.conf
/usr/local/codis/bin/codis-server /data/codis_server/conf/6381.conf

(3)加入 Redis Server Group(124上)

注意:每个 Server Group 作为一个 Redis server组存在, 仅仅同意有一个 master, 能够有多个 slave, group id 仅支持大于等于1的整数 眼下我们在3台server上分了3组,因此我们须要加入3组。每组由一主一从构成

#相关命令    
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server
usage:
    codis-config server list
    codis-config server add <group_id> <redis_addr> <role>
    codis-config server remove <group_id> <redis_addr>
    codis-config server promote <group_id> <redis_addr>
    codis-config server add-group <group_id>
    codis-config server remove-group <group_id>
#group 1
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 1 10.80.80.124:6380 master
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 1 10.80.80.124:6381 slave
#group 2
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 2 10.80.80.126:6380 master
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 2 10.80.80.126:6381 slave
#group 3
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 3 10.80.80.123:6380 master
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 3 10.80.80.123:6381 slave

注意:1.点击“Promote to Master”就会将slave的redis提升为master,而原来的master会自己主动下线。

2./usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini server add 能够加入机器到对应组中。也能够更新redis的主/从角色。 3.若为新机器,此处的keys应该为空 (4) 设置 server group 服务的 slot 范围(124上)

#相关命令
/usr/local/codis/bin/codis-config -c /usr/local/codis/conf/config.ini slot
usage:
    codis-config slot init [-f]
    codis-config slot info <slot_id>
    codis-config slot set <slot_id> <group_id> <status>
    codis-config slot range-set <slot_from> <slot_to> <group_id> <status>
    codis-config slot migrate <slot_from> <slot_to> <group_id> [--delay=<delay_time_in_ms>]
    codis-config slot rebalance [--delay=<delay_time_in_ms>]

#Codis 採用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过下面公式确定所属的 Slot Id : SlotId = crc32(key) % 1024 每个 slot 都会有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。

我们在此将1024个slot分为三段,分配例如以下:

/usr/local/codis/bin/codis-config -c conf/config.ini slot range-set 0 340 1 online /usr/local/codis/bin/codis-config -c conf/config.ini slot range-set 341 681 2 online /usr/local/codis/bin/codis-config -c conf/config.ini slot range-set 682 1023 3 online

(5)启动codis-proxy(在3台服务器上)

codis_proxy的日志文件夹

mkdir -p /data/codis/codis_proxy/logs
codis_home=/usr/local/codis
log_path=/data/codis/codis_proxy/logs
nohup $codis_home/bin/codis-proxy --log-level warn -c $codis_home/conf/config.ini -L $log_path/codis_proxy_1.log  --cpu=8 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 > $log_path/nohup.out 2>&1 &

黑线处:codis读取server的主机名。 注意:若client相关訪问proxy,须要在client加入hosts (6)上线codis-proxy

codis_home=/usr/local/codis
log_path=/data/codis/codis_proxy/logs
nohup $codis_home/bin/codis-proxy --log-level warn -c $codis_home/conf/config.ini -L $log_path/codis_proxy_1.log  --cpu=8 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 > $log_path/nohup.out 2>&1 &

注:启动codis_proxy后。proxy此时处于offline状态。无法对外提供服务,必须将其上线后才干对外提供服务。

CRM与codis的接入 1、原crm系统通过node_redis包连接redis,采用redis-cluster集群后,原连接代码无需更改。 2、redis集群不支持涉及跨key的交集并集操作,需了解原系统涉及redis的操作是否有跨key的交并集操作,如有,应评估修改量的大小决定是否修改代码(升级请教)

参考文献: 1、https://www.cnblogs.com/yuanermen/p/5717885.html //redis-cluster安装部署 2、https://www.cnblogs.com/softidea/p/5365640.html //codis安装部署

results matching ""

    No results matching ""