Redis(三)——事务、快照 / AOF持久化、主从复制(两种方式和哨兵模式)、Redis集群(增加删除节点、分配插槽、创建失败处理方式、Jedis操作集群)、Redis常见问题和布隆过滤器

本文详细介绍了Redis的事务机制,包括MULTI/EXEC、异常处理和WATCH命令的使用。此外,还探讨了Redis的两种持久化方式:RDB快照和AOF日志,以及它们的优缺点。接着,阐述了Redis的主从复制,包括配置、操作和注意事项,以及哨兵模式在高可用性中的作用。最后,简要提及了Redis集群的搭建和管理,以及在实际应用中遇到的缓存问题和布隆过滤器的使用。
摘要由CSDN通过智能技术生成

Redis(三)

一、Redis 事务

既然redis是一种NoSQL数据库,那它当然也有事务的功能,不过这里的事务和我们关系型数据库中的事务有一点点差异。

1、 使用事务

使用事务很简单:
在这里插入图片描述

这样就是开启事务了。

在MULTI命令执行之后,我们可以继续发送命令去执行,此时的命令不会被立马执行,而是放在一个队列中,如下:
在这里插入图片描述

当使用 exec 命令时,这三个命令才会去执行:
在这里插入图片描述

2、事务中的异常

跟 mysql 不一样的是,这里的异常没有 rollback 功能。只能说是确保这些一起执行或者监控变量。

redis中事务的异常情况总的来说分为两类:
1、进入队列之前就能发现的错误,比如命令输错;
2、执行EXEC之后才能发现的错误,比如给一个非数字字符加1;

那么对于这两种不同的异常,redis中有不同的处理策略。
对于第一种错误,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务(这个是2.6.5之后的版本做法,之前的版本做法可以参考官方文档)
。如下:

a、执行错误

在这里插入图片描述

可以看到第一条指令错误,第二条成功,第一条不会 影响第二条:

在这里插入图片描述

比如自增字符串错误:
在这里插入图片描述
错误的指令也不会影响到正确的指令。

b、命令错误

命令错误时会立马显示错误信息:
在这里插入图片描述

可以看到命令错误时事务到此就终止了,后面再输入的东西也没用了,可以看到最后也没有运行第二条指令。

不同于关系型数据库,redis中的事务出错时没有回滚,对此,官方的解释如下:

Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

3、WATCH 命令

事务中的WATCH命令可以用来监控一个key,通过这种监控,我们可以为redis事务提供(CAS)行为。 如果有至少一个被WATCH监视的键在EXEC执行之前被修改了,那么整个事务都会被取消,EXEC返回nil-reply来表示事务已经失败。如下:

举个转账的例子:
现在希望开始执行事务之后,别的进程线程不能操作这个 money 的变量,如果有操作,这个事务就执行失败,确保事务执行期间这个 money 变量是一个固定的状态。那么这种时候就可以通过 watch 命令来操作(这个 key 可以给很多个,同时监控很多个变量):
在这里插入图片描述

事务中的WATCH命令可以用来监控一个key,通过这种监控,我们可以为redis事务提供(CAS)行为。 如果有至少一个被WATCH监视的键在EXEC执行之前被修改了,那么整个事务都会被取消,EXEC返回nil-reply来表示事务已经失败。如下:

这里开两个窗口:
在这里插入图片描述

接着窗口一开启监控和事务:
在这里插入图片描述

接着窗口二修改值:
在这里插入图片描述

接着窗口一修改失败,且 money 是 888:
在这里插入图片描述
所以这里 money 变了就会提交失败

4、UNWATCH 命令

如果监控了一个 key,突然又不想监控了,就输入 unwatch 命令。

二、Redis 快照持久化

1、引言和介绍

redis 一般用作两方面,一是缓存,缓存存储到内存中,电脑关机再开机就没了,没了就没了,反正也只是缓存;临时存储。
二是当作数据库来用,那么这个持久化就会存到硬盘上面。持久化默认是存到硬盘中去。

持久化分两种方式:

在这里插入图片描述
在 redis 文件夹中,会有个多出来的文件(刚开始装好 redis 时是没有这个文件的),这个就是做数据持久化备份下来的文件:
在这里插入图片描述
启动 redis 时会自动的从硬盘中加载这个文件并把数据恢复到内存中去。

只要把这个文件删掉, 把 redis 重启就会发现数据都没了。

默认情况下是开启的;不需要自己手动去配置,当然也可以自己修改配置:
在这里插入图片描述
在这里插入图片描述

a、关闭快照持久化

在这里插入图片描述

b、其他配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、手动触发备份和同步异步备份

快照可以手动的触发(SAVE 指令):
在这里插入图片描述

如果之前把备份文件删了,此时手动触发指令后,会发现备份文件会又有了。

上面这种方式的备份属于阻塞的方式,如果数据量很大会卡在这里。

还有一种备份时异步的方式,指令是:BGSAVE,后台备份:
在这里插入图片描述

如果执行了 shutdown,也会触发备份。其实备份的时机有很多个。
在这里插入图片描述

3、快照持久化的缺点

在这里插入图片描述

4、快照持久化流程

这里对上面作一个小结:

注意:下面的 3 是以前的版本,实际情况以配置文件中的为准。
在这里插入图片描述

三、Redis AOF持久化

1、AOF持久化介绍

AOF 持久化不同于快照的保存数据,而是记录一直以来操作的命令,当需要恢复数据时,会把一直以来操作的命令重新执行一遍,这样一来也相当于恢复了数据。

AOF 持久化默认是关闭的,如果想要测试这个,建议先把快照关闭了。

2、开启 AOF 备份与相关设置

开启 AOF 备份:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、AOF备份关键点和重写与压缩

在这里插入图片描述

4、实践前告知

在这里插入图片描述

5、redis 通信协议和自定义 Java 客户端

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、Redis 主从复制

Redis 主从复制有两种方式。

1、引言和介绍

主从复制可以在一定程度上扩展redis性能,redis的主从复制和关系型数据库的主从复制类似,从机能够精确的复制主机上的内容。实现了主从复制之后,一方面能够实现数据的读写分离,降低master的压力,另一方面也能实现数据的备份。

2、开始操作主从复制

这里以一个主机两个从机举例子:
需要三个 redis,分别设置端口号为:6379、6380、6381

首先需要三份 redis.conf 文件,接着需要更改里面的配置(注意:这里因为是用一个虚拟机来操作,如果是这样建议把 aof 关闭,因为三个 redis 的操作会产出三份备份文件,但是这三份备份文件的名字是一样的,所以会互相覆盖,如果是三台虚拟机分别操作就没这个问题。或者在配置文件中设置各个 redis 的 AOF 备份文件名不同也行。):

也可以将 redis.conf 文件更名为 redis6379.conf,方便我们区分,然后把 redis6379.conf 再复制两份,分别为 redis6380.conf 和 redis6381.conf。

打开redis6379.conf,将如下配置均加上6379,(默认是6379的不用修改),如下:

port 6379
pidfile /var/run/redis_6379.pid
logfile "6379.log"
dbfilename dump6379.rdb
appendfilename "appendonly6379.aof"

接着,分别打开redis6380.conf和redis6381.conf两个配置文件,将第二步涉及到6379的分别改为6380和6381:
全局搜索,将 6379 全部替换为 6380。
在这里插入图片描述

这样以来基本就搞好了,但是这样直接启动三个都是主机。且开启的时候后两个需要指定端口号:
在这里插入图片描述

要想把主机改成从机,需要去配置文件里面修改:
在这里插入图片描述

这时候保存退出再重新运行,查看信息,这时就是从机了:
在这里插入图片描述

这时候如果测试:在主机中存一条数据,会发现两个从机都有一样的数据。主机中的数据,会自动的同步到从机上面来。
所以以后写数据在主机中写,读数据从从机上面读。 这就是读写分离了。

自行测试也可以发现从机上面是不能写数据的:
在这里插入图片描述

默认情况下从机是只读的,当然也可以设置成可以写(但是不建议这么做):
在这里插入图片描述
但是从机即便可以写数据,也不会把数据反写到主机中去,因此会导致数据不一致。

3、主从复制注意点

1、如果主机已经运行了一段时间了,并且了已经存储了一些数据了,此时从机连上来,那么从机会将主机上所有的数据进行备份,而不是从连接的那个时间点开始备份。

2、配置了主从复制之后,主机上可读可写,但是从机只能读取不能写入(可以通过修改redis.conf中 replica-read-only 的值让从机也可以执行写操作)。

3、在整个主从结构运行过程中,如果主机不幸挂掉,重启之后,他依然是主机,主从复制操作也能够继续进行。

4、复制原理

在这里插入图片描述

5、第二种主从复制

上面讲的是第一种主从复制:
在这里插入图片描述
还有这一种的:
在这里插入图片描述

这么一来中间的机子对于左边的就是从机,对于右边的就是主机。

只需要把 6381 的主机改成 6380 即可。

6、哨兵模式

结合上篇文章,我们一共介绍了两种主从模式了,但是这两种,不管是哪一种,都会存在这样一个问题,那就是当主机宕机时,就会发生群龙无首的情况,如果在主机宕机时,能够从从机中选出一个来充当主机,那么就不用我们每次去手动重启主机了,这就涉及到一个新的话题,那就是哨兵模式。

在这里插入图片描述
一个哨兵可以监控很多个 master,不是只能监控一个。最后面的数字是投票的数量;哨兵可以有一个也可以有多个,所以剩下的服务器要获得多少票才能当选 master。这里因为只有一个哨兵,所以只能是 1。哨兵会测量剩下的服务器,会去发消息,看哪个响应快,就哪个优先。一般如果有多个哨兵,这个值是哨兵总数的一半即可:
在这里插入图片描述
设置好后启动:
在这里插入图片描述

这时候让主机宕机,让其他从机当选主机,看看日志信息:
在这里插入图片描述
这时候会发现 6379 变成从机了。

这时候即便重新启动 6379,也依然是从机。

这时候看看 6379 的日志信息:
在这里插入图片描述
这里是哨兵往配置文件里面写的。这样以后 6379 每次启动都是从机;因为配置文件限制了。

如果再打开 6380 的配置文件,会发现少了一行,这样每次启动 6380 都是 master 了。

这样看来哨兵模式作出的更改是持久的。

五、Redis 集群

1、原理

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2、集群搭建

这里从一个默认干净的 redis.conf 文件开始改;这里为了方便区分,命名为 redis7001.conf 一直到 redis7006.comf。这里只要把 7001 改好,再复制五份,再批量修改即可(这六个文件可以统一放到一个 文件夹中去管理):
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
到此就配置好了,后面只需要复制五份,并把里面的 7001 改成对应的数字即可。

之后就是启动 redis,跟正常那样启动即可(这里是启动节点):
在这里插入图片描述
启动节点成功后就开始进行集群的创建:
在这里插入图片描述

./src/redis-cli --cluster create --cluster-replicas 1 192.168.5.131:7001 192.168.5.131:7002 192.168.5.131:7003 192.168.5.131:7004 192.168.5.131:7005 192.168.5.131:7006 -a 123

创建成功前模拟的信息:
在这里插入图片描述
上图信息中可以看到分了三组,每组分配的插槽等等之类的信息,还有主机从机对应的信息。

在这里插入图片描述
这个意思是对这次分配是否接受,选择 no 就会重新分配。yes则开始分配。

3、查看集群的状态及相关信息

想要查看集群的状态,只需要随便登录到一个 redis 里面:
在这里插入图片描述
上面的 -c 意思是以集群的方式登录。

然后输入 cluster info 即可查看集群的状态。

cluster nodes :查看集群的信息:
在这里插入图片描述
这时随便存入一个值,看看展示的信息:
在这里插入图片描述

展示了分配的插槽和对应的机子,而且自动跳到了 7003 中去。

4、添加节点

a、添加 master

现在有三组,想要动态的加一个 master 进来,是可以的:
先弄出一个 7007 出来,配置按照之前的方式改,然后启动:
在这里插入图片描述
接着加入到集群中:
在这里插入图片描述

src/redis-cli -a 123 -p 7001 --cluster add-node 127.0.0.1:7007 127.0.0.1:7001

b、分配插槽

加入集群成功后看一下集群信息,会发现新加入的节点不仅没有从机,还没有插槽,没有插槽意味着加进来也是白加,因为存储是根据插槽来存的。所以这里最后一件事就是分配插槽;因为 16384 个插槽已经分配完了,所以只能从已有的地方取出来分配给新节点:
在这里插入图片描述

src/redis-cli -a 123 -p 7001 --cluster reshard 127.0.0.1:7001

接着就是要输入迁移的数量。这里其实移动的还是比较慢,因为涉及到数据的迁移。
在这里插入图片描述
在这里插入图片描述
接着就是输入这些插槽由哪些机子出,如果是 all(指三个主机)那么就是三个主机出,如果是某一个或者某几个,那么一个个输入完对应的机子 id 之后,最后输入一个 done,就意味着输完了。
在这里插入图片描述
这里就输入 all。接着就会展示三个主机打算分出的插槽信息,会询问我们是否接受这种分配:
在这里插入图片描述
分配完成后查看 7007 的插槽:
在这里插入图片描述

c、添加从节点

也可以添加丛节点,添加丛节点比较简单,直接添加进来即可,下面是例子:
在这里插入图片描述

5、删除节点

a、删除从机

从机删除很简单,直接删除即可,例子:
在这里插入图片描述

b、删除主机

主机删除就比较麻烦了,因为主机上面有槽,直接删除会报错。要删除也不难,先要把槽分配出去才能删,因为如果槽不完整,集群也就用不了了。把槽分配出去的方式就跟前面的一模一样。这里就不举例子了。

6、创建失败处理方式

创建集群如果可以最好是一次性的成功,如果是失败了,先要把这几个文件删除:
在这里插入图片描述

7、Jedis 操作集群

在这里插入图片描述

六、Redis常见问题和布隆过滤器

1、key的生存时间到了,Redis会立即删除吗?

在这里插入图片描述

2、Redis的淘汰机制

在这里插入图片描述

3、缓存的常见问题

a、缓存穿透问题

典型场景:
在这里插入图片描述

在这里插入图片描述
虽然都是一些常见的办法,但是并不是最佳的解决方案。比较专业的做法是使用布隆过滤器。关于布隆过滤器看下一个小节。

b、缓存击穿问题

 就是说在短时间内或者同一时间突然缓存都过期了或者失效了,然后大量访问都跑去数据库中,这就叫缓存击穿。

解决方案:不要设置统一的过期时间,过期时间应该是随机的。

c、缓存雪崩

在这里插入图片描述
解决方案同上。

d、缓存倾斜问题

在这里插入图片描述
解决方案:搭建 redis 主从。

4、布隆过滤器

a、应用场景

在这里插入图片描述

b、布隆过滤器介绍

在这里插入图片描述

c、 布隆过滤器原理

在这里插入图片描述
大白话解释就是: 布隆过滤器中有好几个哈希函数,会对要存的数据进行运算,分别算出哈希值出来,接着这几个哈希值会对数组的长度取余,求出来的余数会存进数组中(余数是多少,就存哪个位置)。接着下次想找有没有存过这个数据,又会再次去求哈希值出来,接着去对应的数组位置去找,比如这个位置分别是 1、5、8。如果这三个位置都有,那么这个数据就可能会存在;之所以说可能会存在,是因为其他数据求出来的结果也可能是 1、5、8。但是如果这三个位置有一个不存在,或者都不存在,那么这个数据就一定不存在。所以说这里求出来的数据结果是:如果有,就可能存在,如果没有,那么就一定不存在。

如果要查询一个数据,就会先用这个布隆过滤器先过滤一遍。

看上图。位数组的大小可以自己自定义。这个大小跟误判的概率有关:位数组越大,误判概率越小,当然占用的存储空间越大;位数组越小,误判概率越大,当然占用的存储空间就小。

虽然精确度没有 redis 那么精确,但是也能筛选出大部分的数据,已经足以起到保护数据库的作用。

还有一点要注意:这里只是判断数据是否存在,但是不能逆运算出存的数据是什么值,因为多种多样的数据他们的值可能是一样的,所以只能求出是否可能存在,但不能求出该值是多少。

d、安装

切记不要安装最新的版本,要去找正式发布的版本。github 页面的右边去找:
在这里插入图片描述
下载压缩文件,去 linux 系统里面解压。

自己编译安装(如果手动解压压缩包可跳过下面第二步):

cd redis-5.0.7
git clone https://github.com/RedisBloom/RedisBloom.git 
cd RedisBloom/
make 
cd ..
redis-server redis.conf --loadmodule ./RedisBloom/redisbloom.so

在这里插入图片描述

e、使用布隆过滤器

存数据:
在这里插入图片描述
检查数据是否存在:
在这里插入图片描述

默认的位数组的长度是100。

f、设置布隆过滤器

在这里插入图片描述
上图的 k1 是过滤器的名字。系统会根据错误率和预计存储数量计算出一个大致的位数组长度。

g、Jedis 操作布隆过滤器

测试前记得还需要 Jedis 的依赖
在这里插入图片描述
可以先自定义过滤器的初始条件。
在这里插入图片描述

测试代码:

GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setMaxIdle(300);
        config.setMaxTotal(1000);
        config.setMaxWaitMillis(30000);
        config.setTestOnBorrow(true);
        JedisPool pool = new JedisPool(config, "192.168.91.128", 6379, 30000, "javaboy");
        Client client = new Client(pool);
        //存入数据
        for (int i = 0; i < 100000; i++) {
        	// 第一个参数是过滤器的名字
            client.add("myfilter", "javaboy-" + i);
        }
        //检查数据是否存在
        boolean exists = client.exists("myfilter", "javaboy-9999999");
        System.out.println(exists);

如果不手动设置,过滤器条件则是默认的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值