redis再战之AKF的Z轴拆分和代理集群搭建《八》

容量问题

单机redis在使用的时候会碰到三个问题:单点故障、容量不足、访问压力。

  • 因此我们可以对redis进行AKF拆分,站在x轴的角度上可以对redis进行 主从复制 + 哨兵机制。
  • 主从复制:slave做master的全量备份保证数据的可靠性。master对外提供读写,slave对外提供读操作(读写分离),解决了部分访问压力。
  • 哨兵机制:对master做高可用,使用 哨兵集群 监控master健康状态,哨兵之间相互通信,如果发现master挂了会进行投票选举 其中一个个slave作为新的master。解决了单点故障的问题。
  • 但是由于slave是master的全量数据,在容量这个维度上来说,redis依然是一个单实例的。对于臃肿的redis实例来说,还需要对其进行y轴个z轴的拆分。

Z轴拆分

原因
Y轴拆分后某一业务的数据量还是很大,我们可以对Z轴方向上,在Client端根据 算法 继续拆分。(sharding 分片)

1. modula(hsah + 取模):

在这里插入图片描述

  • 这种方式是在Client增加算法逻辑,把要存入数据的进行 % 运算,后边有几个redis实例,就和几进行 % 运算,根据取模的值,把数据存入到不同的redis实例。

优点: 简单,容易操作。

缺点: 取模的值是固定的,影响分布式下的扩展性,如果添加新的redis实例会使 模数值 发生改变,再取数据的时候根据 模数 去取就无法查找到数据了。

2. random:

在这里插入图片描述

  • Client把数据随机放到不同的redis实例中:

应用

随机把数据放入不同的redis,取出成本很高?根本找不到数据?

如果存入的是一个list类型(lpush),key为ooxx,那么就会在两个redis中都生成ooxx的key,这个时候消费者并不是执行lpush的Client,而是执行rpop的另一个Client,都会从ooxx中取数据,无论从哪个redis取,都会取到key为ooxx的数据。这样就形成了一个类似于消息队列的功能。

3. ketama(一致性hash):

在这里插入图片描述

  • 在得到一个长度随机的字符串后(redis的key),经过算法得到一个等宽的其他的值(算法:hash、crc16、crc32、fnv、md5),这个值会和字符串做一个映射。
  • 和hash取模算法不同的是,一致性hash没有取模的过程(即:不会影响分布式扩展性),并且要求key和node都要参与计算。
  • 会在内存中虚拟出一个环形(哈希环)。
  • 在这里插入图片描述
  • 哈希环由0 -2^32个数字组成,每一个数字都是一个点。无论后面有多少个redis实例,或新增,或减少,都会给这些redis实例一个ID号(或者IP+Port之类的)唯一标识。

优点:

  • 没有固定node数量的限制,不会造成全局洗牌。

缺点:

  • 新增节点后,造成一小部分数据无法命中。
  • 如上图,新增一个节点 node3,把node3的ID进行hash运算得到一个数值,这个数值对应 哈希环 的点 恰好在之前数据映射的点和它存入node之间(data -> node2 变为 data -> node3 -> node2), 此时如果查询data,不会从node2查询,而是会从node3里面查找data,因此查询结果为null。
  • 这种方式只适合做缓存而不适合做数据库,缓存大多为期限,即使node2里面data数据永远不会被查询到,data也会随着时间的推移而被清除掉,或者开启缓存清理策略LRU、LFU。并且node3里面无法查询到数据,可以走数据库从新缓存到node3(缓存击穿),也可以修改为从比自己大的两个node中查找数据。

扩展:虚拟节点

  • 原因
    如果node1和node2映射在哈希环的点分别在最左边和最右边,把哈希环切分成了 上半环 和 下半环,在添加数据的时候就可能出现 数据集中在某个半环上而导致 数据量的倾斜。
  • 解决
    我们可以每个node ID后面依次拼10个数字,让一个ID变成10个,用这些ID做hash运算映射到 哈希环 不同的点上,如果是两个设备在 哈希环 上面就会有20个点,这样做的目的是让一个物理设备出现在多个点上,就可以间接的解决数据倾斜的问题。

redis的连接成本很高

可以在Client和redis之间增加一个代理层(proxy),类似于Nginx这种应用层 的反向代理,基于反向代理的基础上负载均衡服务器。

  • redis自带的拆分:cluster
  • twemproxy
  • predixy

扩展
proxy是不需要记录Client状态,本身不存在数据库存储,所以proxy是无状态的 ,很容易的就可以把proxy一变多。

为了提高可用性,可以搭建LVS四层负载均衡服务器对两个proxy做负载均衡。

但是LVS也是一个单点,并且不能对后端的proxy集群做健康检查,所以可以使用keepalived建立VIP对LVS做主备HA高可用。
在这里插入图片描述

redis自带的拆分:cluster

规避了ketama新增redis实例时截断数据

在这里插入图片描述
拆分逻辑中进行预分区
redis1映射0,1,2,3,4
redis2映射5,6,7,8,9
(各领取5个槽位)。
如果redis3加入集群,会让redis1和redis2让出几个槽位,比如从redis1中拿到了3和4,在redis2中拿到了8和9(如上图)。移动数据的时候,不需要把redis全部rehash,只需要把3,4,8,9槽位的时点数据找到直接传输给redis3,redis3接收完数据后,会根据时点数据跟redis1和redis2传输期间内的数据做一个追平更新,追平的一刹那,再往3,4,8,9槽位存数据就会直接存入redis3。
Client只需要知道映射关系,就可以根据槽位正确的读取数据了

存取数据

Client想要存入k1,会随机访问redis1和redis2。可以让每个redis实例都能当家做主。k1随机进入一个redis实例后(假设这个实例是redis2),redis2会先拿k1进行hash取模算出槽位,用计算的槽位和自己的mapping映射的槽位做一个匹配,如果和自己匹配就直接存入redis2,如果不匹配再和redis2内保存的其他实例的槽位映射关系进行匹配,就能找到k1需要存的redis实例是哪个,把k1返回给Client并重定向到正确的redis实例中(假设匹配结果为redis3)。redis3拿到k1后同样要进行hash运算并且把结果和自身映射槽位进行匹配,匹配成功直接存入自己这个实例当中。

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念。
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽

问题: 聚合操作很难实现

操作的key都在相同的节点,可以用 hash tag 。
比如:把key设置成为{oo}k1,{oo}k2,{oo}k3这种带有{}内部有固定标识的 格式,这样在存入key的时候会使用 oo 进行取模,而不会使用k1,k2,k3进行取模。进而存入同一个redis节点。

twemproxy搭建过程

github

git clone https://github.com/twitter/twemproxy.git
yum install automake   libtool -y
cd twemproxy
autoreconf -fvi

报错:autoconf版本过低
解决办法

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo
yum clean all
yum install  autoconf268
cd twemproxy
autoconf268  -fvi
./configure
make
cd scripts/
cp nutcracker.init /etc/init.d/twemproxy
cd /etc/init.d/
chmod +x twemproxy  
mkdir  /etc/nutcracker/
cd  twemproxy /conf
cp ./*     /etc/nutcracker/
cd  twemproxy/src
cp nutcracker  /usr/bin
cd /etc/nutcracker
cp nutcracker.yml nutcracker.yml.back
vi nutcracker.yml
service twemproxy start

nutcracker.yml


alpha:
  listen: 127.0.0.1:22121
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 127.0.0.1:6379:1
   - 127.0.0.1:6380:1

客户端直接连接22121端口
谈到集群管理不得不又说到数据的分片管理(shard),为了满足数据的日益增长和扩展性,数据存储系统一般都需要进行一定的分片,如传统的MySQL进行横向分表和纵向分表,然后应用程序访问正确的位置就需要找的正确的表。这时候,这个数据定向工作一般有三个位置可以放:

数据存储系统本身支持,Redis Cluster就是典型的试图在数据存储系统上支持分片;
客户端支持,Memcached的客户端对分片的支持就是客户端层面的;
代理支持,twemproxy就是试图在服务器端和客户端中间建代理支持;

predixy搭建过程

github

mkdir predixy
cd predixy/
wget https://github.com/joyieldInc/predixy/releases/download/1.0.5/predixy-1.0.5-bin-amd64-linux.tar.gz
cd predixy/

vi predixy.conf
GENERAL模块:Bind 127.0.0.1:7617    			//设置对外暴露的统一接口
SERVERS模块:Include sentinel.conf				//引入哨兵配置文件

vi sentinel.conf

sentinel.conf

SentinelServerPool {
    Databases 16
    Hash crc16
    HashTag "{}"
    Distribution modula
    MasterReadPriority 60
    StaticSlaveReadPriority 50
    DynamicSlaveReadPriority 50
    RefreshInterval 1
    ServerTimeout 1
    ServerFailureLimit 10
    ServerRetryTimeout 1
    KeepAlive 120
    Sentinels {
        + 127.0.0.1:26379								//三个哨兵的 IP+端口
        + 127.0.0.1:26380
        + 127.0.0.1:26381
    }
    Group ooxx {						//一套哨兵可以监控多套主从,一个Group为一套主从。
    }									//Client写入的数据会被打散分别存入ooxx主从的master和xxoo主从的master。
    Group xxoo {
    }
}

配置哨兵

vi 26379.conf 
port 26379
sentinel monitor ooxx 127.0.0.1 36379 2			//第一套主从ooxx的master ID+ Port,组为ooxx
sentinel monitor xxoo 127.0.0.1 46379 2			//第二套主从xxoo的master ID+ Port	组为xxoo

vi  26380.conf
port 26380
sentinel monitor ooxx 127.0.0.1 36379 2
sentinel monitor xxoo 127.0.0.1 46379 2

vi  26381.conf
port 26381
sentinel monitor ooxx 127.0.0.1 36379 2
sentinel monitor xxoo 127.0.0.1 46379 2

#启动哨兵
redis-server 26379.conf --sentinel
 redis-server 26380.conf --sentinel
redis-server 26381.conf --sentinel

# 建立四个个文件夹36379、36380、46379、46380,分别进去启动对应的redis

redis-server --port 36379
redis-server --port 46379

//开启两个从机,追随对应的主机
 redis-server --port 36380 --replicaof 127.0.0.1 36379
 redis-server --port 46380 --replicaof 127.0.0.1 46379

//进入代理predixy的根目录
./predixy ../conf/predixy.conf 

//客户端连接
redis-cli -p 7617

cluster操作演示

#自带配置
cd utils/create-cluster
vim create-cluster
./create-cluster start
./create-cluster create
redis-cli -c -p 3000


./create-cluster satrt				//启动节点
 ./create-cluster create			//创建集群
./create-cluster stop				//停止集群和节点
 ./create-cluster clean				//清理数据文件

# 手工启动的redis实例需要在配置文件中开启 cluster-enabled yes 
redis-cli --cluster create 127.0.0.1:30001 127.0.0.1:30002 127.0.0.1:30003 127.0.0.1:30004 127.0.0.1:30005 127.0.0.1:30006 --cluster-replicas 1

redis-cli --cluster reshard 127.0.0.1:30001

redis-cli --cluster info 127.0.0.1:30001		//随便选一个节点的ip端口

redis-cli --cluster check 127.0.0.1:30001	

总结:

  1. 三种搭建都是分摊redis的内存压力,将数据分到不同的redis
  2. 正常数据会分到不同节点上,不支持事务
  3. 人为干涉将数据分到同一个redis从而支持事务,watch也是一样的道理
  4. {tag}key 可以分发到同一redis支持事务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值