侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

redis分布式集群搭建介绍

Redis  /  管理员 发布于 7年前   226

Redis集群架构图

1.jpg

上图蓝色为redis集群的节点。

节点之间通过ping命令来测试连接是否正常,节点之间没有主区分,连接到任何一个节点进行操作时,都可能会转发到其他节点。

1、Redis的容错机制

节点之间会定时的互相发送ping命令,测试节点的健康状态,当节点接受到ping命令后,会返回一个pong字符串。

投票机制:如果一个节点A给节点B发送ping没有得到pong返回,会通知其他节点再次给B发送ping,如果集群中有超过一半的节点收不B节点的pong。那么就认为B节点挂了。一般会为每个节点提供一个备份节点,如果挂掉会切换到备份节点。

2、Redis集群存储原理

Redis对于每个存放的key会进行hash操作,生成一个[0-16384]的hash值(先进行

crc 算法再对16384取余)。

集群的情况下,就是把[0-16384]的区间进行拆分,放到不同的redis中。

3、Redis的持久化

Snapshotting:定时的将Redis内存中的数据保存到硬盘中

AOF:将所有的command操作保存到aof中,AOP的同步频率很高,数据即使丢失,粒度也很小,但会在性能上造成影响。

二、集群环境搭建

redis集群管理工具redis-trib.rb依赖ruby环境,首先需要安装ruby环境

安装ruby

yum install rubyyum install rubygems

安装ruby和redis的接口程序

拷贝redis-3.0.0.gem至/usr/local下

执行:

gem install /usr/local/redis-3.0.0.gem

三、创建Redis集群

在一台服务器上,可以用不同端口号来表示不同redis服务器。

Redis集群最少需要三台服务器,而每台服务器有需要备用服务器,所以最少需要6台服务器。端口规划如下:

主服务器:192.168.100.66 :7001 :7002 :7003

从服务器:192.168.100.66 :7004 :7005 :7006

在/usr/local 创建文件夹用来存放服务器程序

mkdir 7001 7002 7003 7004 7005 7006

如果想让redis支持集群需要修改redis.config配置文件的cluster-enabled yes

本例中我们以端口来区别不同的redis服务,所以还需要修改redis.config的port为对应端口

修改完配置文件,将redis安装目录的bin复制到上面每个目录中。

分别进入7001/bin/ 7002/bin .....

启动服务./redis-server ./redis.conf

查看redis进程:ps -aux|grep redis 如下图则说明启动成功

2.jpg

创建集群:

将之前解压的文件夹的redis-3.0.0/src/redis-trib.rb复制到redis-cluster目录

运行

./redis-trib.rb create --replicas 1 192.168.100.66:7001 192.168.100.66:7002 192.168.100.66:7003 192.168.100.66:7004 192.168.100.66:7005  192.168.100.66:7006

如果执行时报如下错误:

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解决方法是删除生成的配置文件nodes.conf,如果不行则说明现在创建的结点包括了旧集群的结点信息,需要删除redis的持久化文件后再重启redis,比如:appendonly.aof、dump.rdb

如果成功最终输入如下:

3.jpg

查询集群信息:

4.jpg

说明:

./redis-cli -c -h 192.168.101.3 -p 7001 ,其中-c表示以集群方式连接redis,-h指定ip地址,-p指定端口号

cluster nodes 查询集群结点信息

cluster info 查询集群状态信息

5.jpg

hash槽重新分配

第一步:连接上集群

./redis-trib.rb reshard 192.168.101.3:7001(连接集群中任意一个可用结点都行)

第二步:输入要分配的槽数量

6.JPG

输入 500表示要分配500个槽

第三步:输入接收槽的结点id

7.jpg

这里准备给7007分配槽,通过cluster nodes查看7007结点id为15b809eadae88955e36bcdbb8144f61bbbaf38fb

输入:15b809eadae88955e36bcdbb8144f61bbbaf38fb

第四步:输入源结点id

8.jpg

这里输入all

第五步:输入yes开始移动槽到目标结点id

9.jpg

添加从节点

集群创建成功后可以向集群中添加节点,下面是添加一个slave从节点。

添加7008从结点,将7008作为7007的从结点。

./redis-trib.rb add-node --slave --master-id 主节点id 添加节点的ip和端口 集群中已存在节点ip和端口

执行如下命令:

./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7008 192.168.101.3:7001

cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 是7007结点的id,可通过cluster nodes查看。

10.jpg

注意:如果原来该结点在集群中的配置信息已经生成cluster-config-file指定的配置文件中(如果cluster-config-file没有指定则默认为nodes.conf),这时可能会报错:

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解决方法是删除生成的配置文件nodes.conf,删除后再执行./redis-trib.rb add-node指令

查看集群中的结点,刚添加的7008为7007的从节点:

11.jpg

删除结点:

./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017

删除已经占有hash槽的结点会失败,报错如下:

[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.

需要将该结点占用的hash槽分配出去(参考hash槽重新分配章节)。

测试:

Maven:<dependencies>    <dependency>        <groupId>redis.clients</groupId>        <artifactId>jedis</artifactId>        <version>2.7.0</version>    </dependency>    <!-- https://mvnrepository.com/artifact/junit/junit -->    <dependency>        <groupId>junit</groupId>        <artifactId>junit</artifactId>        <version>4.12</version>        <scope>test</scope>    </dependency>    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-test</artifactId>        <version>4.3.10.RELEASE</version>        <scope>test</scope>    </dependency></dependencies>

普通测试:

@Testpublic void redisClusterTest1(){    JedisPoolConfig config=new JedisPoolConfig();    config.setMaxTotal(30);    config.setMaxIdle(2);    Set<HostAndPort> jedisNode=new HashSet<HostAndPort>();    jedisNode.add(new HostAndPort("192.168.100.66",7001));    jedisNode.add(new HostAndPort("192.168.100.66",7002));    jedisNode.add(new HostAndPort("192.168.100.66",7003));    jedisNode.add(new HostAndPort("192.168.100.66",7004));    jedisNode.add(new HostAndPort("192.168.100.66",7005));    jedisNode.add(new HostAndPort("192.168.100.66",7006));    JedisCluster jc=new JedisCluster(jedisNode,config);    jc.set("name","老王");    String value=jc.get("name");    System.out.println(value);}

Spring测试:

配置文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">    <!-- 连接池配置 -->    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">        <!-- 最大连接数 -->        <property name="maxTotal" value="30" />        <!-- 最大空闲连接数 -->        <property name="maxIdle" value="10" />        <!-- 每次释放连接的最大数目 -->        <property name="numTestsPerEvictionRun" value="1024" />        <!-- 释放连接的扫描间隔(毫秒) -->        <property name="timeBetweenEvictionRunsMillis" value="30000" />        <!-- 连接最小空闲时间 -->        <property name="minEvictableIdleTimeMillis" value="1800000" />        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->        <property name="softMinEvictableIdleTimeMillis" value="10000" />        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->        <property name="maxWaitMillis" value="1500" />        <!-- 在获取连接的时候检查有效性, 默认false -->        <property name="testOnBorrow" value="true" />        <!-- 在空闲时检查有效性, 默认false -->        <property name="testWhileIdle" value="true" />        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->        <property name="blockWhenExhausted" value="false" />    </bean>    <!-- redis集群 -->    <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">        <constructor-arg index="0"><set>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7001"></constructor-arg>    </bean>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7002"></constructor-arg>    </bean>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7003"></constructor-arg>    </bean>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7004"></constructor-arg>    </bean>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7005"></constructor-arg>    </bean>    <bean class="redis.clients.jedis.HostAndPort">        <constructor-arg index="0" value="192.168.100.66"></constructor-arg>        <constructor-arg index="1" value="7006"></constructor-arg>    </bean></set>        </constructor-arg>        <constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>    </bean></beans>

测试类:

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration({"classpath:spring-config.xml"})public class RedisClusterTest {    @Autowired    private JedisCluster jedisCluster;    @Test    public void redisClusterTest2(){        jedisCluster.set("username","小明啦啦");        String name=jedisCluster.get("username");        System.out.println(name);    }}

更多redis知识请关注redis数据库教程栏目。

以上就是redis分布式集群搭建介绍的详细内容,更多请关注其它相关文章!


  • 上一条:
    redis数据过期时间设置
    下一条:
    Redis分布式锁的正确实现方式介绍
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在Redis中能实现的功能、常见应用介绍(0个评论)
    • 2024年Redis面试题之一(0个评论)
    • 在redis缓存常见出错及解决方案(0个评论)
    • 在redis中三种特殊数据类型:地理位置、基数(cardinality)估计、位图(Bitmap)使用场景介绍浅析(2个评论)
    • Redis 删除 key用 del 和 unlink 有啥区别?(1个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-12
    • 2020-03
    • 2020-05
    • 2021-04
    • 2022-03
    • 2022-05
    • 2022-08
    • 2023-02
    • 2023-04
    • 2023-07
    • 2024-01
    • 2024-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客