6

亲密接触Redis-第三天(Redis的Load Balance)

 3 years ago
source link: https://blog.csdn.net/lifetragedy/article/details/50885126
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

上两天讲述了Redis的基本搭建和基于HA的集群布署方式以及相关的策略和注意点。今天开始讲述Redis的Cluster功能,而这块目前来说网上资料不是太全,就算有1,2篇也只是单讲服务端的搭建也并未提及相关的客户端怎么和Redis Cluster间的调用问题。

我们今天要讲述的Redis Cluster是真正的Load Balance,它和Sentinel不一样,Sentinel虽然也叫集群,可是它是一种HA策略即High Available或者又通俗的被称为“灾难转移”策略。

Redis3.x中引入的Load Balance

从Redis3.x开始已经支持Load Balance功能了。

 Redis Cluster  是Redis的集群实现,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384 决定。在Redis Cluster里对于负载均衡和HA相关都已经支持的相当完善了。

  • 负载均衡(Load Balance):集群的Redis Instance之间可以迁移数据,以Slot为单位,但不是自动的,需要外部命令触发。
  • 集群成员管理:集群的节点(Redis Instance)和节点之间两两定期交换集群内节点信息并且更新,从发送节点的角度看,这些信息包括:集群内有哪些节点,IP和PORT是什么,节点名字是什么,节点的状态(比如OK,PFAIL,FAIL,后面详述)是什么,包括节点角色(master 或者 slave)等。
关于可用性,集群由N组主从Redis Instance组成。

主可以没有从,但是没有从 意味着主宕机后主负责的Slot读写服务不可用。

一个主可以有多个从,主宕机时,某个从会被提升为主,具体哪个从被提升为主,协议类似于Raft,参见这里。如何检测主宕机?Redis Cluster采用quorum+心跳的机制。从节点的角度看,节点会定期给其他所有的节点发送Ping,cluster-node-timeout(可配置,秒级)时间内没有收到对方的回复,则单方面认为对端节点宕机,将该节点标为PFAIL状态。通过节点之间交换信息收集到quorum个节点都认为这个节点为PFAIL,则将该节点标记为FAIL,并且将其发送给其他所有节点,其他所有节点收到后立即认为该节点宕机。从这里可以看出,主宕机后,至少cluster-node-timeout时间内该主所负责的Slot的读写服务不可用。

Redis Cluster的特点如下:

  • 节点自动发现
  • slave->master选举,集群容错
  • Hot resharding:在线分片
  • 集群管理:clusterxxx
  • 基于配置(nodes-port.conf)的集群管理
  • ASK 转向/MOVED转向机制
  • 布署无需指定master
  • 可以支持超过1,000台节点的集群

Redis Cluster的实现

Redis Cluster依赖于其官方位于Redis编译包内(我们此处使用的是redis-stable版本)/src目录下的redis-trib.rb 文件,这是一个ruby脚本,为此你必须把你的服务器环境作一个先期准备。

搭建Cluster前的环境准备

  • 安装CentOS或者是RHE
  • 在安装Linux时需要一定记得安装GCC库、LibC、LibStdC++、Rubby库(1.9.2或以上)、ZLIB库(1.2.6或以上),如果你装机时没有安装这些“optional package”可以通过yum install gcc这样的命令在Linux联网的情况下来进行Linux安装后的额外包的安装
  • 安装ruby gems库(1.8.16或以上)- rubygems-1.8.16.tgz(运行内在的setup.rb),下载 rubygems-1.8.16.tgz 后在解压包的/path/gem 运行
sudo ruby setup.rb 
  • 在ruby gems安装后,你必须安装gem的redis模块,可以通过官网或者相关可信任连接下载redis-3.2.1.gem(先下载.gem文件再用gem安装)如:
gem install -l redis-3.2.1.gem

Redis集群节点的规划

使用make PREFIX=/usr/local/redis1 install这样的命令连续搭建至少6个nodes,Redis Cluster的最低要求是(3个Master,3个Slave),这在我们的“亲密接触Redis-第一天”中有详细描述怎么编译安装一个redis了,此处全部是采用redis-stable这个版本。

集群节点的配置

每个节点在第一次配置时,除去:

  • .pid文件和路径
  • /logfile文件和路径
  • Data存放路径
其余配置,完全一样,并且无master和slave之分。

PORT端口配置要点:

所有Master(如3个Master的端口号以+1方式递增:7001,7002,7003)

所有的Slaver的端口号必须且一定要符合这样的原则:slave的端口比相关的master大1000号,如7001的slave的端口号为8001。


举例来说:

3个Master为7001,7002,7003,我们的3个Slave就为8001,8002,8003

redis.conf文件内:

  • maxmemory-policy allkeys-lru 
  • cluster-enabled yes(启用,把前面的#注释掉)
  • cluster-config-file nodes-7001.conf(启用,把前面的#注释掉,此处建议使用本节点的PORT号为文件名,这样便于区分
  • cluster-node-timeout 15000(启用,把前面的#注释掉)
  • cluster-migration-barrier 1(启用,把前面的#注释掉)

使用Rubb Gem的Redis模块+redis-trib.rb创建集群

一切准备就绪后,把6个redis节点全部启动起来。

redis-trib.rb位于下载下来的redis-stable目录的/src目录内。

使用如下命令创建Redis集群:

./redis-trib.rb create --replicas 1 192.168.0.1:7001 192.168.0.1:7002 192.168.0.1:7003 192.168.0.1:8001 192.168.0.1:8002 192.168.0.1:8003

注:

命令行中一定要把所有的master列出后,再列出所有的slave(依照master的顺序列slave),6个节点全部列在命令行中。

命令执行后过了一段时间系统会提示你如下信息

集群创建成功后会显示如下信息:

这就说明Redis集群已经创建了,以后只要使用redis-server redis.conf这样的命令把每个节点启动起来就可以了。

使用Jedis Client来连接Redis集群(Load Balance)

目前Redis和Spring的结合都是依靠Jedis和Spring Data的redisTemplate来做的,而现在spring data似乎对redis cluster的功能支持并不好(此处指的是load balance功能),为此我们自己封装了一个redis的客户端来支持redis的cluster方式,也结合spring来用(如果redistemplate已经支持redis的load balance功能后建议大家使用spring data的redis template,因为那个无论是在封装性还是性能上会更好)。

先给出代码需要的相关jar包吧。

pom.xml

spring配置文件redis-cluster.xml

这边我们看到有一个叫com.qf.platform.redis.cluster.JedisClusterFactory的类,这个类就是我们通过“GenericObjectPoolConfig”来封装的用于支持redis cluster功能的客户端接口。

com.qf.platform.redis.cluster.JedisClusterFactory类内容

通过该类和spring中的配置


我们得知,该类会通过/src/main/resources目录下的/spring目录中的redis.properties去读各个redis cluster节点的信息

redis.properties文件内容

# Redis settings

cach.host.ip=192.168.0.101
cach.host.port=6380
  

redis.host.ip=192.168.0.101
redis.host.port=6379
  

redis.maxTotal=1000  
redis.maxIdle=100
redis.maxWait=2000
redis.testOnBorrow=false
redis.testOnReturn=true

redis.sentinel.addr=172.30.32.127:26379


clusternode1=192.168.0.101:7001
clusternode2=192.168.0.101:7002
clusternode3=192.168.0.101:7003
clusternode4=192.168.0.101:8001
clusternode5=192.168.0.101:8002
clusternode6=192.168.0.101:8003

该类使用时很方便,看下面的示例代码

客户端调用Redis Cluster示例代码

简单吧。

Redis集群的注意事项(与坑)

redis-cli客户端使用事项

  • 使用redis-cli连接cluster时要使用: redis-cli –c –h –p这样的格式
  • 在客户端连上任意一个redis节点set一个值后,该值不一定存到该节点,而是自动转向至由Redis集群选举出来的一个节点中并存入值,此时客户端的物理连接也会被指向该节点。举例:
此时你的redis-cli连接已经被重定向至了7002了而不是在7001下虽然显示符>前显示的还是7001

使用redis-cli连接cluster中任意一个节点如:

可以看到7003节点内无 key=1的元素,但是集群内是有key=1的元素的,于是:

reds-cli会动态从集群中查到含有key=1的节点,把客户端连接重定向至该节点并调用该key所绑的value

添加新master节点

  • 添加一个master节点:创建一个空节点(empty node),然后将某些slot移动到这个空节点上,这个过程目前需要人工干预
  • establish_config.sh根据端口生成配置文件establish_config.sh 6386?> conf/redis-6386.conf
  • 启动该节点
  • 加入空节点到集群redis-trib.rb add-node newip:newport 已有集群中任意ip:已有集群中任意port
注:

新节点没有包含任何数据, 因为它没有包含任何slot。新加入的加点是一个主节点, 当集群需 要将某个从节点升级为新的主节点时, 这个新节点不会被选中,同时新的主节点因为没有包含任何slot,不参加选举和failover。

  • 为新节点分配slot:redis-trib.rb reshard ip:port

添加slave节点

  1. 按照添加master节点的前3步
  2. redis-cli连接上新节点shell,输入命令:cluster replicate 对应master的node-id
注意:

在线添加slave 时,需要bgsave整个master数据,并传递到slave,再由 slave加载rdb文件到内存,rdb生成和传输的过程中消耗Master大量内存和网络IO,以此不建议单实例内存过大,线上小心操作。

删除Master节点

  1. 删除master节点之前首先要使用reshard移除当前master的全部slot到新的master上
  2. 删除空的master节点。

JEDIS(Redis JAVA客户端)的一些坑

  • cluster环境下slave默认不接受任何读写操作,在slave执行readonly命令后,可执行读操作
  • client端不支持多key操作(mget,mset等),但当keys集合对应的slot相同时支持mget操作
  • 不支持多数据库,只有一个db,select 0。
  • JedisCluster 没有针对byte[]的API,需要自己扩展(Jedis-3.0.0及以上开始才支持byte[]操作)

截止到今天,Redis所有搭建和使用讲解完毕,还有更深入的功能由其是性能优化、配置还需要大家在平时工作中不断的实践,我在文中也只能涉及到50%左右的内容,更多还是要靠读者自己去潜心发掘。

总得来说Redis是一个相当优秀的NOSQL,大都网站都在使用它作为主选NOSQL或者是缓存。

用,人人都会!

但用的精,这是需要付出一定的专研精神的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK