1 为什么要搭建Redis集群

Redis的分片机制能对Redis数据库进行扩容,但由于每个Redis分片中的内容都是自己独有的,所以万一有一个宕机了,用户就可能查不到数据了。没法做到高可用。
Redis的哨兵机制能让Redis能监控主机的状态,保证Redis的高可用。但是每个主机和从机中保存的数据都是相同的。存储这些相同的海量的缓存数据相当浪费内存。
怎么才能做到二者兼得呢?
那就是 Redis集群
采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.
并且在内部实现高可用的机制(不用引进第三方,如哨兵).实现了服务故障的自动迁移.

1.1 Redis集群搭建的步骤

1.1.1 集群搭建计划

共要有6台Redis数据库,端口号7000到7005
主从划分:
3台Redis主机,3台Redis从机

1.1.2 准备集群文件夹

在redis根目录下新建个文件夹 名为cluster
由于这个集群中有6台Redis,要想把这么多节点管理得井井有条,就给每个Redis节点都在cluster文件夹中,再单独设置个文件夹。
命名为7000到7005。

1.1.3 给每个Redis数据库安排一个redis.conf文件

哪个redis.conf文件还一直保持原样,没有被我修改过呢?
就是redis根目录下的那个redis.conf。这个文件不要改。留作最原始的备份。
先把这个redis.conf文件分别复制到7000文件夹下。
然后配置7000文件夹下的这个redis.conf文件。
配置好后,再把这个配置好的redis.conf文件复制到7001到7005中,各一份,这样改动的地方就不至于那么多了。

1.1.4 编辑7000中的redis.conf文件

进到7000文件夹中,再进入到redis.conf文件中,开始修改。(共11处需修改)

  1. 注释掉原conf文件中绑定的本机的IP地址
  2. 关闭保护模式 (默认是开启的)
  3. 修改端口号(默认是6379)
  4. 启动后台启动(默认不在后台启动,会将运行信息全打印出来,并且客户端一关闭,redis集群也就不干活了)
  5. 修改pid文件 (默认写的是 /var/run/redis_6379.pid pid就是进程号 这个文件保存的就是当前这个redis数据的进程号信息)
    为了管理方便,这个.pid文件 我可以放在每个redis数据库自己的文件夹中。
  6. 修改持久化文件路径
    由于缓存数据都是保存在内容中的,为了防止万一断电,导致数据丢失。就要定期将缓存数据写到一个文件中,进行数据持久化。
    这个文件就是dump.rdb文件。
    可以给每个redis数据库都配置这么一个文件,放在各自的文件夹下就好了。
    (默认的是 dir ./)
  7. 设定内存优化策略 (默认是maxmemory-policy noeviction)
    改为:通过lru算法优化redis内存
  8. 关闭AOF模式 (默认就是no)
    关闭持久化方式
  9. 开启集群配置 (默认是被注释掉的,把注释打开即可)
    表示要不要开启集群。(当然是yes)
  10. 开启集群配置文件 (默认是# cluster-config-file nodes-6379.conf)
    把注释去掉,再将-6379去掉即可

    这个nodes.conf文件中的内容如下:(大体就是主机和从机的关系)
  11. 修改集群超时时间 (默认是15s)
    这个设置的就是 集群在发现主节点在宕机了多长时间之后开始选举新主机(保持默认的15s即可)

    这样7000的redis.conf文件就修改完了。

1.1.5 复制修改后的7000的redis.conf文件 到7001到7005文件夹中

1.1.6 批量修改redis.conf文件

每个redis.conf文件中只需要修改1.1.4中的第3条,第5条,第6条中的端口号就行了。
只需要分别进入到每个redis的redis.conf文件中
比如7001
再通过命令:%s/7000/7001/g
就能快速定位到这3处需要修改端口号的地方,并自动进行修改。
之后:wq 保存退出即可。
7002,7003,7004,7005的操作相同

1.1.7 通过脚本start.sh和shutdown.sh 一键开启/关闭6个redis服务器

1.一键开启6台服务器
在cluster目录下,创建一个start.sh脚本文件

2.一键关闭6台服务器
在cluster目录下,创建一个shutdown.sh脚本文件

1.1.8 启动6台redis,检查是否都能正常运行


1.1.9 创建redis集群

上面8步只是创建了6台redis数据库服务器,还没有将它们联系起来。
下面要通过命令将它们联系起来。

redis-cli --cluster create --cluster-replicas 1 192.168.35.130:7000 192.168.35.130:7001 192.168.35.130:7002 192.168.35.130:7003 192.168.35.130:7004 192.168.35.130:7005

说明: --cluster-replicas 1
这个1 指的是 主机后面 跟 几个从机
1 就是 主机后面跟 1个从机
2 就是 主机后面跟 2个从机
······

在出现如下内容后,输入yes
然后 如果出现以下信息,说明集群搭建成功

1.2 测试Redis集群

1.2.1 Redis集群高可用推选原理:

Redis的所有节点都会保存当前redis集群中的全部主从状态信息.并且每个节点都能够相互通信.当一个节点发生宕机现象.则集群中的其他节点通过PING-PONG检测机制检查Redis节点是否宕机.当有半数以上的节点认为宕机.则认为主节点宕机.同时由Redis剩余的主节点进入选举机制.投票选举链接宕机的主节点的从机.实现故障迁移.

1.2.2 Redis集群存储数据的原理:

Redis hash槽算法 (也叫Redis分区算法) 储数据的原理

CRC16哈希函数是 哈希算法中众多函数中的一种。
hash槽算法就是通过将key传给CRC16这个哈希函数,得到一个数,再将得到的数字%16384。(即CRC16[key]%16384)
算得的结果的范围就是 0到16383 (共16384个数)
Redis集群就规定个“槽”,并把这个“槽”平均分割成16834个“槽位”,“槽位”的编号从 0 到 16383
如果我的Redis集群中有3台主机,
那么Redis集群就会把这16384个“槽位”分成3份:
然后让3台redis主机去管理这些“槽位”。
比如:我想存入一条数据{“aa”,“abc”}
那我该存到哪台redis主机中呢? 7000?7001?还是7002?
蒙一个,我进入到7002主机中,尝试存入

结果人家提示我,redis集群通过CRC16[“aa”]%16384 得到的结果是 1180
它归7000这个主机管。所以我得把这个数据存到7000的主机中。

面试题

1.理论上,Redis集群中最多可以设置多少台Redis主机?
16384台,即每个主机管1个“槽位”。

2.Redis集群中 可以存放多少个“Key”?
注意:key的个数跟“槽位”的个数没关系。
比如有5个key:key1,key2,key3,key4,key5
它们经过CRC16[key]%16384 计算后 ,假如都为 2000
那么它们5个就都属于 2000号这个“槽位”。
集群中能存多少个Key,取决于Redis内存容量的大小。内存无限大,就能无限存。

1.2.3 测试Redis集群是否实现了高可用

以7000这个主机为例。
之前7000为主机,它的从机是7003。
现在将7000的服务器关掉(gg了)。
15s后,再将7000的服务器开启。

查询7000服务器的状态,发现它已经变成了从机,它的主机成了7003

查询7003的服务器的状态,发现它已经成了主机,它有一个从机,是7000

1.3 万一Redis集群搭建错了,补救措施

1.3.1 关闭所有的Redis服务

1.3.2 删除7000到7005 每个文件夹中的nodes.conf和dump.rdb文件

由于搭建集群之后,所有的集群的信息(谁是主机,谁是从机,以及主机与从机之间的练习)都会写入nodes.conf文件中,
如果下次重启,还是会读取其中的配置信息,实现redis集群的主从的搭建.
所以如果需要重新搭建集群,则必须删除该文件重新生成.

1.3.3 重启Redis服务器之后重新搭建集群

redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005

2 关于Redis集群的面试题

原则: Redis的内存缺失则集群崩溃。(即如果主机宕机了,没有从机能顶上去,那么原主机中的数据就丢失了,就是内存缺失)

2.1 如果3主3从(1主1从) 最少宕机几台集群崩溃?

(答:2台:主机A和它的从机a 都gg了)

2.2 如果3主6从(1主2从) 最少宕机几台集群崩溃?

(答:5台:主机A和它的两个从机a1,a2都gg了,并且管主机B和主机C借来的从机b1和c1也都gg了)

3 SpringBoot整合Redis集群

3.1 测试:在测试类中测试往集群中插入一条数据

在TestRedis.java中添加一个测试方法,用于测试往Redis集群中插入一条数据{“clusterKey”,“集群的测试”},看能否通过key,get出value。

/*** redis集群的入门案例*/@Testpublic void testCluster(){//第2步 新建一个set集合,里面装集群中Redis各数据库的ip和portSet<HostAndPort> sets = new HashSet<>();//第3步 将各个Redis节点的信息都封装到HostAndPort对象中,再将HostAndPort对象放到sets集合中sets.add(new HostAndPort("192.168.126.129",7000));sets.add(new HostAndPort("192.168.126.129",7001));sets.add(new HostAndPort("192.168.126.129",7002));sets.add(new HostAndPort("192.168.126.129",7003));sets.add(new HostAndPort("192.168.126.129",7004));sets.add(new HostAndPort("192.168.126.129",7005));//第1步  新建一个JedisCluster对象  它需要的参数是一个set集合//这个set集合里装的是集群中Redis各数据库的ip和portJedisCluster jedisCluster = new JedisCluster(sets);//第4步  往集群中插入一条数据jedisCluster.set("clusterKey","集群的测试");//第5步 打印System.out.println(jedisCluster.get("clusterKey"));}

3.2 正式:将Redis集群对象—JedisCluster交给Spring管理

3.2.1 修改redis.properties文件

将原有代码注释掉,加上redis集群中6台redis节点的host和port信息

# 添加redis集群
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005

3.2.2 编辑JedisConfig.java

将JedisConfig.java中原来的redis单台机和redis分片的配置注释掉,新加上redis缓存的配置代码

@Value("${redis.nodes}")private String nodes;   //redis集群时的设置node1,node2,node3,node4,node5,node6/*** 将redis集群对象JedisCluster交给Spring管理*/@Beanpublic JedisCluster jedisCluster(){//第2步 将从redis.properties中获取到的nodes进行切割,得到一个个的redis节点// ["192.168.126.129:7000","192.168.126.129:7001","192.168.126.129:7002","192.168.126.129:7003","192.168.126.129:7004","192.168.126.129:7005"]String[] strNodes = nodes.split(",");//第3步 新建一个set集合,用来存放HostAndPort对象,因为人家JedisCluster就要这样的对象Set<HostAndPort> sets = new HashSet<>();//第4步,遍历第1步中得到的字符串数组strNodes,得到String类型的数据,命名为node,(node的格式就是:"host:port")for (String  node:  strNodes) {//第5步,将node用:分隔,取前半部分,就是String类型的host数据String host = node.split(":")[0];//第6步,取后半部分数据,就是String类型的port数据String port = node.split(":")[1];//第7步,然而,人家HostAndPort对象  要的port是int类型,还得转一下类型int port1 = Integer.parseInt(port);//第8步,将String类型的host数据 和 int类型的port1数据  赋值给HostAndPort对象HostAndPort hostAndPort = new HostAndPort(host,port1);//第9步,将HostAndPort对象放到set集合中sets.add(hostAndPort);}//第1步 新建个JedisCluster对象//要的参数是一个set集合 里面存放的是集群中的redis各数据库的ip和portJedisCluster jedisCluster = new JedisCluster(sets);//第10步,将jedisCluster对象上交给Springreturn  jedisCluster;}

3.2.3 在CacheAOP.java这个切面文件中,引入redis集群对象jedisCluster

只需改一处:
将原来的注入对象的代码删掉,注入在上一步配置好的jedisCluster对象

3.2.4 验证 京淘项目中Redis集群是否布置成功

在后台管理主页中,如果叶子类目中能显示出分类的名字,再刷新几次,依然可以正确显示,就说明Redis集群布置成功了。
因为后几次叶子类目的数据都是从Redis集群中得到的。

4 Redis持久化策略

4.1 Redis数据持久化需求的引出

Redis数据都保存在内存中,如果内存断电则导致数据的丢失.为了保证用户的内存数据不丢失,需要开启持久化机制.
什么是持久化: 定期将内存中的数据保存到磁盘中.

4.2 Redis中持久化的2种方式

方式1: RDB模式 dump.rdb 它是redis默认的持久化方式
方式2: AOF模式 appendonly.aof 它在redis.conf文件中默认是关闭的,需要手动开启.

4.2.1 RDB模式

说明: RDB模式是Redis中默认的持久化策略.
特点:
1. RDB模式可以实现定期的持久化,但是可能导致数据丢失(在上一次持久化到下一次持久化的时间中途发生了断电,那么上一次持久化以后到断电时,的数据将丢失).
2. RDB模式作的是内存数据的快照,并且后拍摄的快照会覆盖之前的快照.所以持久化文件较小.恢复数据的速度较快. 工作的效率较高.

命令:
我可以通过save命令和bgsave命令去告诉redis 什么时候去持久化数据。
1.save 是要求redis立即执行持久化操作。 (同步操作)
在redis.conf文件中,如图:

这样,当我又想往redis里存数据时,如果此时redis正在持久化数据,那我是存不了新数据的。只能等它持久化完以后,我才能存新数据。阻塞了我。

2.bgsave 即(backgroundsave,后台保存) 。 (异步操作)
如果我在redis.conf中 218行这里 设置成了bgsave,redis会单独再开启一个线程执行持久化操作。
我可以随时往redis里添加数据,查询数据。等redis闲下来了,它还记得要bgsave数据呢,就去持久化数据了。

持久化方案:
我怎么设置save才合理?
redis.conf文件中给了3种默认方案:

save 900 1 的意思是 如果redis在900s内执行了1次set操作,那么它就会持久化一次
save 300 10 的意思是 如果redis在300s内执行了10次set操作,它也会持久化一次
save 60 10000 的意思是 如果redis在60s内 执行了10000次操作,它也会持久化一次

用户操作越频繁则持久化的周期越短.

持久化文件存放的目录:
我可以指定redis执行持久化时,产生的dump.rdb文件存放的位置
在redis.conf的第263行设置

设置持久化文件的名字:
我可以设置持久化后产生的rdb文件的名字,默认是dump
在redis.conf的第253行设置

4.2.2 AOF模式

特点:

  1. AOF模式默认的条件下是关闭状态,需要手动开启. (redis.conf文件中的第699行)
  2. AOF模式记录的是用户对redis的每一步操作。所以持久化文件占用空间相对较大.恢复数据的速度较慢.所以效率较低.
  3. 但它的优势就是可以保证用户的数据尽可能不丢失.

配置:
1.开启AOF配置
2. AOF模式的持久化策略
在redis.conf文件中的第728到第730行,设置了3中持久化策略

① appendfsync always 如果用户执行了一次set操作,redis就持久化一次
② appendfsync everysec redis每秒持久化一次
③ appendfsync no 不主动持久化.
**更改完redis配置后,记得要重启一下redis!!!**然后就会发现多了一个appendonly.aof文件。

4.3 关于RDB/AOF模式特点

1.如果用户可以允许少量的数据丢失可以选用RDB模式(快).
2.如果用户不允许数据丢失则选用AOF模式.
3.实际开发过程中一般2种方式都会配置. 一般主机开启RDB模式,从机开启AOF模式.

4.4 情景题:

1.公司的redis.conf中没开启AOF模式,只开启了RDB模式,如果我不小心执行了flushAll,清空了redis中的数据。
那么即使有dump.rdb,但dump.rdb里面存的是内存数据的快照,我flushAll以后,内存数据都没了,快照里面也啥都没有了。
所以即使我重启redis,也无法找回redis中的数据了!(后果很严重,不要轻易去执行flushAll语句。)
2.公司的redis.conf中开启了AOF模式,如果我不小心执行了flushAll,清空了redis中的数据。
但还有补救措施。
我要马上将redis服务器关闭!!!不要让用户再往redis服务器中存数据了,就当是服务器在维护中···
打开appendonly.aof文件 看一眼 我都干了啥:
于是,我要赶紧用vim命令,进到appendonly.aof文件中,把“FLUSHALL”这条语句删掉!!!

然后再重启redis服务器。
然后就惊喜地发现,数据又回来了!!!!!!

不要单纯地认为: redis只是缓存服务器,里面的数据也都是缓存数据,丢了的话,再从数据库查一遍就又有了。
要注意,redis也可以是普通数据库,消息中间件,这时它里面保存的都是业务数据。就比如记录着我对redis数据库都做了哪些操作,等等。这些数据在MySQL数据库中可是没有的,Redis中如果丢了可就真丢了!!!!

5 Redis内存优化的说明

5.1 问题引出

Redis可以当做内存使用,但是如果一直往里存储不删除数据,则必然导致内存溢出.
思考: 怎么管理Redis中的数据, 可以避免内存溢出,让用户永远都可以存数据呢?

5.2 方法一:借助LRU算法

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法。
删除那些到目前为止,最长时间未使用的数据。
该算法赋予redis数据库中每条数据一个访问字段t,用来记录这个数据自上次被访问以来所经历的时间 ,
当需要淘汰一个数据时,选择现有数据中, t 值最大的,即最近最少使用的数据予以淘汰。
维度:上一次最后使用 到 目前为止的 时间长度 t
LRU算法是当下实现内存清理的最优算法.

5.3 方法二:借助LFU算法

LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用的数据的置换算法
要求是,在需要更换redis数据库中的数据时,置换掉那些之前被引用次数最少的数据,因为经常被访问的数据的被访问次数一般都会很大。
但是有些数据在开始存入redis数据库时使用次数很多,但以后就不再被访问了,这类数据将会长时间留在redis内存中,占用着redis宝贵的资源,也不合适。
针对这种情况,可以将计数器定时右移一位,让这条老数据的使用次数定期不断地减少。
(比如:最开始这条数据被访问了10000次,经过一段时间后,即要把这个次数变成1000,再经过一段时间,变成100,再经过一段时间,变成10.。。。以此类推,当小到一定程度时,就被淘汰删除了)
维度: 被引用的次数

5.4 方法三:Random算法

随机删除Redis数据库中的数据!!!这个方法很危险!!!

5.5 方法四:TTL算法

对于那些被设置了生命时长的数据,可以监控它们的剩余生命时长。
当redis内存不足,需要删除一些数据时,就选择那些剩余生命时长最短的数据,优先删除。

5.6 内存优化方法的指定

可以在redis.conf文件中,人为地指定选择哪种方法去优化redis内存。
在第597行进行设置:

共有8中选择,想换哪个,就把后面的方法名换掉即可。

1.volatile-lru  在设定了超时时间的数据中,采用lru算法.
2.allkeys-lru  所有数据采用lru算法
3.volatile-lfu  在设定了超时时间的数据中,采用lfu算法
4.allkeys-lfu -> 所有数据采用lfu算法
5.volatile-random -> 在设定了超时时间的数据中,采用随机算法
6.allkeys-random -> 所有数据随机删除
7.volatile-ttl ->  在设定了超时时间的数据中,删除存活时间少的数据
8.noeviction -> 不会删除数据,如果内存溢出报错返回.

Lesson14 Redis集群的搭建相关推荐

  1. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  2. Redis集群架构搭建详解

    一.简介 这其实是一种分布式数据库,就是通过分片的机制储存数据,cluster中的每个节点仅仅储存数据哭的一部分数据,本质上就是实现数据库分片. 这种集群是一种去中心化的集群,也就是说,集群中的每个节 ...

  3. redis集群的搭建详细教程

    1 Redis-cluster架构图             redis-cluster投票:容错  (至少要三个才可以,才能超过半数) 架构细节: (1)所有的redis节点彼此互联(PING-PO ...

  4. (转) 淘淘商城系列——Redis集群的搭建

    http://blog.csdn.net/yerenyuan_pku/article/details/72860432 本文我将带领大家如何搭建Redis集群.首先说一下,为何要搭建Redis集群.R ...

  5. Redis集群环境搭建实践

    本文是Redis集群学习的实践总结(基于Redis 6.0+),详细介绍逐步搭建Redis集群环境的过程,并完成集群伸缩的实践. Redis集群简介 Redis集群(Redis Cluster) 是R ...

  6. Redis集群的搭建与主从复制,redis-cluster

    注意:我是搭建的伪集群,我在一个服务器上启动了6个redis ,ip地址一致端口号不同:与搭建正式集群方法一致,只是正式集群用了6台服务器,IP地址不同,端口号一致: Redis集群的搭建 redis ...

  7. redis常用命令及安全Redis集群环境搭建

    2019独角兽企业重金招聘Python工程师标准>>> redis 安装 在centos 上很简单 yum install redis 即可完成redis的安装 安装redis cd ...

  8. 2W 字详解 Redis 集群环境搭建实践

    点击上方 "终端研发部"关注, 星标或置顶一起成长 本文是Redis集群学习的实践总结(基于Redis 6.0+),详细介绍逐步搭建Redis集群环境的过程,并完成集群伸缩的实践. ...

  9. Redis数据库搭建集群(集群概念、redis集群、搭建集群(配置机器1、2、创建集群、数据操作验证)、Python与redis集群交互)

    1. 集群的概念 集群是一组相互独立的.通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理.一个客户与集群相互作用时,集群像是一个独立的服务器.集群配置是用于提高可用性和可缩放性. ...

最新文章

  1. Windows2003实用技巧
  2. Python系统调用——运行其他程序
  3. Discord 公司如何使用 Cassandra 存储上亿条线上数据
  4. python包管理机制_Go 1.5之前的多种包管理机制简介(
  5. VS2012手动关联xaml与CS文件
  6. linux 服务器硬件报警,Linux服务器硬件运行状态及故障邮件提醒的监控脚本分享...
  7. bzoj 1131: [POI2008]Sta(DPS)
  8. 540.有序数组中的单一元素(力扣leetcode) 博主可答疑该问题
  9. java jdk 8 中文文档
  10. winform控件之notifyicon
  11. HTTP Live Streaming直播
  12. 系统管理、系统安全命令
  13. Originpro绘制y轴偏移堆积图无法设置偏移量
  14. Ocata Neutron代码分析(一)——Neutron API启动过程分析
  15. 初识swipe.js
  16. 报告:ICO项目2019年第一季度融资总额仅1.18亿美金,相较于2018年同比下降逾58倍...
  17. 南邮-2043(有才华的罗老师)
  18. M41ST85W_3.0/3.3 V I²C组合实时时钟、NVRAM监控器和微处理器监控——科时进商城
  19. 净空法师:陈晓旭往生的教训(转载)
  20. CSS3中的animation属性实现无限循环的无缝滚动

热门文章

  1. 拓嘉辰丰:拼多多赠品链接是怎样做出来的
  2. 通用mapper归纳
  3. 遗传算法求解无人机路径多目标规划问题(python实现)
  4. 傅里叶变换的虚数部分
  5. erp服务器备份文件太大,一键ghost 备份文件太大了,导致无法备份,怎么处理?
  6. jdk卸载及常见问题
  7. 番外5京都咖啡的味道——《地与光》
  8. python在哪个城市工资高_“英语学科教学和笔译专业,哪个工资较高?”
  9. PMP认证考试内容有哪些?
  10. 在vim中快速复制粘贴多行