Redis6(终章)

14.Redis_主从复制

简介

主机数据更新后根据配置和策略,自动同步到备机的 master/slaver,Master以写为主,Slave以读为主

能干什么

  • 读写分离,性能扩展
  • 容灾快速恢复

在这里插入图片描述

怎么玩:主从复制

在这里插入图片描述

1.创建 /myredis 文件夹
[root@lehua ~]# mkdir /myredis
[root@lehua ~]# cd /myredis
[root@lehua myredis]# 
2.复制 redis.conf 配置文件到文件夹中

cp /etc/redis.conf /myredis/redis.conf

3.配置 一主两从,创建三个配置文件

主机有密码 需要配置 masterauth

3.1新建 redis3366.conf

include /myredis/redis.conf

pidfile /var/run/redis_3366.pid

port 3366

dbfilename dump3366.rdb

3.2 新建 redis3367.cong

include /myredis/redis.conf

pidfile /var/run/redis_3367.pid

port 3367

dbfilename dump3367.rdb

masterauth ^^7750731hua

3.3新建 redis3368.cong

include /myredis/redis.conf

pidfile /var/run/redis_3368.pid

port 3368

dbfilename dump3368.rdb

masterauth ^^7750731hua

4.在三个配置文件写入内容
  • slave-priority 10
  • 设置从机的优先级,值越小,优先级越高,用于选举主机时使用。默认 100
[root@lehua ~]# cd /etc
[root@lehua etc]# vi redis.conf
[root@lehua etc]# vi redis3366.conf
[root@lehua etc]# vi redis3367.conf
[root@lehua etc]# vi redis3368.conf

在这里插入图片描述

启动三台redis

配置文件 是 no 不是on噢 打习惯了

在这里插入图片描述

查看主从信息: info replication

127.0.0.1:3366> info replication
# Replication
role:master			#  master主机
connected_slaves:0
master_failover_state:no-failover
master_replid:8d676e4eac8af28ea3ec95db424a9c6099c7100e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
配从机

slaveof < ip>< port>

  • 33673368上执行:slaveof 127.0.0.1 3366

在这里插入图片描述

查看 主机

在这里插入图片描述

开始测试:

3366开始

在这里插入图片描述

3367:在这里插入图片描述

3368:在这里插入图片描述

从机不能 操作:在这里插入图片描述

常用 3 招

一主二仆

切入点问题? slave1、slave2 是从头开始复制还是从切入点开始复制?比如从 k4 进来,

那之前的 k1,k2,k3是否也可以复制?

从机是否可以写? set 可否?

主机 shutdown 后情况如何?从机是上位还是原地待命

在这里插入图片描述

把3368 挂了

在这里插入图片描述

主机 进行 操作

127.0.0.1:3366> set a2 v2
OK
127.0.0.1:3366> set a3 v3
OK
127.0.0.1:3366> keys *
1) "a2"
2) "a1"
3) "a3"

从机 挂了 重启会变成 主机

slaveof 127.0.0.1 3366

在这里插入图片描述

从头数据同步了

  • 从挂了要配置重连

  • 主挂了 从还是会认大哥

复制原理

第一次连接时

从服务器进行

在这里插入图片描述

主服务器 主动

在这里插入图片描述

薪火相传

简介:

上一个 Slave 可以是下一个 slave 的 Master , Slave 同样可以接收其他 slave 的连接和同步请求,那么该 slave 作为了链条中下一个的 master,可以有效减轻 master 的写压力,去中心化降低风险

用 slaveof < ip>< port>

中途变更转向:会清除之前的数据,重新建立拷贝最新的

风险是一旦某个 slave 宕机,后面的 slave 都没法备份

主机挂了,从机还是从机,无法写数据了

树型传递

主3366 从 3367

3368连 3367 (从接从)

从连从

127.0.0.1:3367> slaveof 127.0.0.1 3368
OK

结果:

127.0.0.1:3368> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:3367
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:138864
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:56c9169aa9aadb69854ee54abe21c0f13efeaaa4
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:138864
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:138864

反客为主

简介:

当一个 master 宕机后,后面的 slave 可以立刻升为 master , 其后面的 slave 不用做任何修改

用 slaveof no one 将小弟变为大哥

主停了

在这里插入图片描述

**3367 **

127.0.0.1:3367> slaveof no one
OK
127.0.0.1:3367> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=3368,state=online,offset=140810,lag=0
master_failover_state:no-failover
master_replid:268c9a22d0ebc1c01aa9d98d80925440cbfc366d
master_replid2:56c9169aa9aadb69854ee54abe21c0f13efeaaa4
master_repl_offset:140810
second_repl_offset:140783
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:4297
repl_backlog_histlen:136514

14.6 哨兵模式(sentinel)

简介: 反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

在这里插入图片描述

14.6.2 怎么玩(使用步骤)

首先 切换 大哥 和 两个兄弟的 模式 (一主二仆)

不记得指令就后台复习嘿

  • 1.自定义的/myredis 目录下新建 sentinel.conf 文件(不能错

  • 2.配置哨兵

    • sentinel monitor mymaster 127.0.0.1 6633 1
    • sentinel 哨兵 monitor 监控 其中 mymaster 为监控对象起的服务器名称,1 为至少有多少个哨兵同意迁移的数量
    • 如果 redis 配置了 密码 记得 在sentinel.conf 文件配置 sentinel auth-pass mymaster 123456(密码)
  • 3.当主机挂掉,从机选举中产生新的主机

(大概 10 秒 左右可以看到哨兵窗口日志,切换了新的主机)

哪个从机会被选举为主机呢?根据优先级别:slave-priority

原主机重启后会变为从机

栗子:

大哥挂了

19354:X 29 May 2021 23:11:04.527 * +fix-slave-config slave 127.0.0.1:3367 127.0.0.1 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:11:04.528 * +fix-slave-config slave 127.0.0.1:3368 127.0.0.1 3368 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:11:14.302 * +slave slave 8.135.114.163:3368 8.135.114.163 3368 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:11:14.305 * +slave slave 8.135.114.163:3367 8.135.114.163 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:11:44.371 # +sdown slave 8.135.114.163:3368 8.135.114.163 3368 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:11:44.371 # +sdown slave 8.135.114.163:3367 8.135.114.163 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:30.380 # +sdown master mymaster 8.135.114.163 3366			//大哥挂了
19354:X 29 May 2021 23:18:30.380 # +odown master mymaster 8.135.114.163 3366 #quorum 1/1
19354:X 29 May 2021 23:18:30.380 # +new-epoch 1
19354:X 29 May 2021 23:18:30.380 # +try-failover master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:30.383 # +vote-for-leader 3b447ca4b0b46c258af4f5b908ace8aee9bcac60 1
19354:X 29 May 2021 23:18:30.383 # +elected-leader master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:30.383 # +failover-state-select-slave master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:30.459 # +selected-slave slave 127.0.0.1:3367 127.0.0.1 3367 @ mymaster 8.135.114.163 3366  //重新选大哥 选了3367
19354:X 29 May 2021 23:18:30.459 * +failover-state-send-slaveof-noone slave 127.0.0.1:3367 127.0.0.1 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:30.525 * +failover-state-wait-promotion slave 127.0.0.1:3367 127.0.0.1 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:31.184 # +promoted-slave slave 127.0.0.1:3367 127.0.0.1 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:31.184 # +failover-state-reconf-slaves master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:18:31.264 * +slave-reconf-sent slave 8.135.114.163:3368 8.135.114.163 3368 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:21:31.216 # +failover-end-for-timeout master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:21:31.216 # +failover-end master mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:21:31.216 * +slave-reconf-sent-be slave 8.135.114.163:3367 8.135.114.163 3367 @ mymaster 8.135.114.163 3366
19354:X 29 May 2021 23:21:31.216 * +slave-reconf-sent-be slave 127.0.0.1:3368 127.0.0.1 3368 @ mymaster 8.135.114.163 3366 //3366 变从机了
19354:X 29 May 2021 23:21:31.216 # +switch-master mymaster 8.135.114.163 3366 127.0.0.1 3367		
19354:X 29 May 2021 23:21:31.216 * +slave slave 8.135.114.163:3368 8.135.114.163 3368 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:21:31.216 * +slave slave 8.135.114.163:3367 8.135.114.163 3367 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:21:31.216 * +slave slave 127.0.0.1:3368 127.0.0.1 3368 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:21:31.216 * +slave slave 8.135.114.163:3366 8.135.114.163 3366 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:22:01.286 # +sdown slave 8.135.114.163:3368 8.135.114.163 3368 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:22:01.286 # +sdown slave 8.135.114.163:3366 8.135.114.163 3366 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:22:01.286 # +sdown slave 8.135.114.163:3367 8.135.114.163 3367 @ mymaster 127.0.0.1 3367
19354:X 29 May 2021 23:24:31.822 * +fix-slave-config slave 127.0.0.1:3368 127.0.0.1 3368 @ mymaster 127.0.0.1 3367

查看3368 3367 3366

127.0.0.1:3368> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:3367		//切换成功
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:101441
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:f0b6c6fb5a1c647839419abf7410f7870c5f6b9f
master_replid2:f637af23604e4d9d97987335fff7d7944c3ca688
master_repl_offset:101441
second_repl_offset:46630
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:101441
    
127.0.0.1:3367> info replication
# Replication
role:master			//成为主机了
connected_slaves:1			//因为  3366已经挂了
slave0:ip=127.0.0.1,port=3368,state=online,offset=107272,lag=1
master_failover_state:no-failover
    
127.0.0.1:3366> info replication
# Replication
role:slave			//成为从机了
master_host:127.0.0.1
master_port:3367
master_link_status:down
    
// 因为 3366  重启 要密码  设置密码验证重启 检查到3366
127.0.0.1:3367> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=3368,state=online,offset=173452,lag=0
slave1:ip=127.0.0.1,port=3366,state=online,offset=173452,lag=0
master_failover_state:no-failover

这里有个小知识

比如redis有设置密码 谁做主机 都要配上masterauth xxx(主从认证密码)

14.6.3 复制延时(缺点)

由于所有的写操作都是先在 Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重

在这里插入图片描述

  • 优先级在 redis.conf 中默认:replica-priority 100 , 值越小优先级越高
  • 偏移量是指获得原主机数据最全部的
  • 每个 redis 实例启动后都会随机生成一个 40 位的 runid

哨兵连接池

在这里插入图片描述

15. Redis 集群

15.1 问题

容量不够,redis 如何进行扩容?

并发写操作,redis 如何分摊?

主从模式、薪火相传模式、主机宕机,导致 ip 地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息。

之前通过代理主机来解决,但是 redis3.0 中提供了解决方案。 就是 无中心化集群配置。

15.2 什么是集群

Redis 集群实现了对 Redis 的水平扩容,即启动 N 个 redis 节点, 将整个数据库分布式存储在这 N 个节点中,每个节点存储总数据的 1/N

Redis 集群通过分区( partition )来提供一定程度的可用性( availability ):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求

搭建 Redis 集群
1.删除持久化数据

记得停服务先 ps -ef | grep redis

清除之前的 rm -rf dump33*

2.制作 6 个实例

如果是阿里云 需要开发 这几个端口 还有 在开放 13366、 13367等等 这是总线端口 (坑记得)

3366、3367、3368 在起3376、3377、3378

3.配置基本信息
  • 开启 daemonize yes
  • Pid 文件名字
  • 指定端口
  • Log 文件名字
  • Dump.rdb 名字
  • Appendonly 关掉或者换名字
3.1 redis cluster 配置修改
  • cluster-enabled yes 打开集群模式
  • Cluster-config-file nodes-3366.conf 设定节点配置文件名
  • cluster-node-timeout 15000 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换

3366修改

[root@lehua myredis]# vi redis3366.confinclude /myredis/redis.confpidfile
"/var/run/redis_3366.pid"port 3366dbfilename "dump3366.rdb"
masterauth "^^7750731hua"cluster-enabled yescluster-config-file
nodes-3366.confcluster-node-timeout 15000

删除 3367 3368 重新复制

cp redis3366.conf redis3367.conf

cp redis3366.conf redis3368.conf

cp redis3366.conf redis3376.conf

cp redis3366.conf redis3377.conf

cp redis3366.conf redis3378.conf

然后 打开 3367 3368 3376 3377 3378

  • vi redis3367.conf
  • 输入 :%s/3366/3367
3.2 启动6个 redis服务

在这里插入图片描述

3.3 将6个节点合成1个集群

组合前, 确认所有 redis 实例启动后,nodes-xxxx.conf 文件都生成正常

进入 redis安装 地址 cd /usr/local/src/software/Redis6/redis-6.2.3/src

合成指令 这里使用 真实 ip地址 别使用 127.0.0.1 localhost -a 是设置的密码

redis-cli --cluster create 127.0.0.1:3366 127.0.0.1:3367 127.0.0.1:3368 127.0.0.1:3376 127.0.0.1:3377 127.0.0.1:3378 -a ^^7750731hua --cluster-replicas 1

在这里插入图片描述

记住复制 最后的 16384 slots covered 这个值

3.4通过 cluster nodes 命令查看集群信息

在启动 集群的 文件夹 查看

  • 连接 集群中的 redis redis-cli -c -p 3366 -a ^^7750731hua
  • cluster nodes

在这里插入图片描述

3.5 redis cluster 如何分配这六个节点?

一个集群至少要有三个主节点

选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点

在这里插入图片描述

3.6 什么是 slots

在这里插入图片描述

一个 Redis 集群包含 16384 个插槽(hash slot),数据库中的每个键都属于这 16384 个插槽的其中一个

集群使用公式 CRC16(key)% 16384 来计算键 kye 属于哪个槽,其中 CRC16(key)语句用于计算键 key 的CRC16 校验和

集群中的每个节点负责处理一部分插槽。起栗子,如果一个集群可有主节点,

在这里插入图片描述

3.7 在集群中录入值

插槽的概念 (这里端口 不是 3366、3367等了 使用视频的端口展示 因为服务器被攻击太多了)

在 redis-cli 每次录入、查询键值,redis 都会计算出该 key 应该送往的插槽,如果不是该客户端对应服务器的插槽,redis 会报错,并告知应前往的 redis 实例地址和端口。

redis-cli 客户端提供了 -c 参数实现自动重定向

redis-cli -c -p 3366 登入后,再录入、查询键值对可以自动重定向

不在一个 slot 下的键值,是不能使用 mget,mset等多键操作

在这里插入图片描述

批量操作 mset name{组名} add age{组名} 20

在这里插入图片描述

3.8 查询集群中的值

CLUSTER GETKEYSINSLOT < slot>< count> 返回 count个 slot 槽中的键 查看 集群 时 注意 服务器 是哪一个槽值

比如 12706 第二个主机的值 第一个主机是查不到的

在这里插入图片描述

故障恢复

如果主节点下线? 从节点能否自动升为主节点? 注意:15 秒超时

  • 停止 主机6379
  • 查看 cluster nodes
  • 发现 6379 停止了
  • 重启 6379 服务 redis-server redis6379.conf
  • 查看 cluster nodes
  • 发现 6379 变从机了

在这里插入图片描述

如果所有某一段插槽的主从节点都宕机, redis 服务是否还能继续?

如果某一段插槽的主从都挂掉,而 cluster-require-full-coverage 为 yes , 那么,整个集群都挂掉

如果某一段插槽的主从都挂掉,而 cluster-require-full-coverage 为 no , 那么,插槽数据全都不能使用,也无法存储

redis.conf参数 cluster-require-full-coverage

集群的 Jedis 开发

即使连接的不是主机,集群会自动切换主机存储。主机写,从机读。

无中心化主从集群。无论从哪台写的数据,

SpringBoot 连接 集群测试

package com.blog.config;import redis.clients.jedis.HostAndPort;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisCluster;import redis.clients.jedis.JedisPoolConfig;import java.util.HashSet;import java.util.Set;/** * redis集群操作 */public class JedisCluterDemo {    public static void main(String[] args) {        //创建对象        JedisPoolConfig config = new JedisPoolConfig();        config .setMaxTotal(500);        config .setMinIdle(2);        config .setMaxIdle(500);        config .setMaxWaitMillis(10000);        config .setTestOnBorrow(true);        config .setTestOnReturn(true);        Set<HostAndPort> nodes = new HashSet<>();        nodes.add(new HostAndPort("xxx.x.x.x", 3366));        nodes.add(new HostAndPort("xxx.x.x.x", 3367));        nodes.add(new HostAndPort("xxx.x.x.x", 3368));        nodes.add(new HostAndPort("xxx.x.x.x", 3376));        nodes.add(new HostAndPort("xxx.x.x.x", 3377));        nodes.add(new HostAndPort("xxx.x.x.x", 3378));        JedisCluster jedisCluster = new JedisCluster(nodes, 10000, 10000, 100, "^^7750731hua", config);        //进行操作        jedisCluster.set("b1","value1");        String b1 = jedisCluster.get("b1");        System.out.println("value"+" "+b1);        jedisCluster.close();    }}
Redis 集群提供了以下好处
  • 实现扩容
  • 分摊压力
  • 无中心配置相对简单
Redis 集群的不足

多键操作是不被支持的

多键的 Redis 事务是不被支持的。lua脚本不被支持

由于集群方案出现较晚,很多公司已经采用了其他的集群方案,

而代理或者客户端分片的方案想要迁移至 redis cluster,需要整体迁移而不是逐步过渡,复杂度较大

16.1应用问题解决-缓存穿透

简介:

key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,违法分子利用漏洞进行攻击可能压垮数据库

在这里插入图片描述

  • 1.查缓存没有的数据 比如 id:-1 命中率降低
  • 2.导致大量请求直接访问DB(数据库)压力过大

解决方案

  • 1.对空值缓存

    • 如果一个查询返回的数据为空(不管是数据是否不存在),我们把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
  • 2.设置可访问的名单(白名单):

    • 使用 bitmaps 类型定义一个可以访问的名称, 名单 id 作为 bitaps 的偏移量,每次访问 和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问
  • 3.采用布隆过滤器

    • (布隆过滤器(Bloom Filter)是 1970 年由布隆提出的它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希数))
    • 有缺点 1.性能占用 2.存在误判 3.删除困难
    • 最大数值非常大的时候,布隆过滤器需要的空间少的多
    • 查到元素不存在容器中,hash得到k个位置上的值都是1,可以建立白名单存储可能会误判的元素
    • 放入容器的元素映射到bit数组的k个位置上是1,删除时不能直接重置为0,可能会影响元素的判断 ,采用Counting Bloom Filter
  • 4.进行实时监控

    • 当发现 Redis 的命中率急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单

16.2应用问题解决-缓存击穿

简介:

key 对应的数据存在,在 redis 中过期,此时有大量并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端 DB 压垮

在这里插入图片描述

解决方案:

key 可能会在某些瞬间点被超高并发地访问,是一种非常 “热点” 的数据。这个时候,需要考虑一个问题:缓存被 “击穿” 的问题

    1. 预先设置热门数据:在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长
    2. 实时调整:现在监控那些数据热门,实时调整 key 的过期时长
    3. 使用锁
      • (1)就是在缓存失效的时候(判断拿出来的值为空),不是立即去 load db
      • (2)先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX)去 set 一个 mutex key
      • (3)当操作返回成功时,再进行 load db 的操作,并回设缓存,最后删除 mutex key
      • (4)当操作返回失败,证明有线程在 load db, 当前线程睡眠一段时间再重试整个 get 缓存的方法

在这里插入图片描述

16.3应用问题解决-缓存雪崩

简介

key 对应的数据存在,但在 redis 中过期,此时有大量并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端 DB 压垮

缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是每一个 key 正常访问

在这里插入图片描述

解决方案

缓存失效时的雪崩效应对底层系统的冲击非常可怕!

解决方案:

  • (1)构建多级缓存架构:nginx 缓存 + redis 缓存 + 其他缓存(ehcache等)

  • (2)使用锁或队列

    • 用加锁或队列的发生保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不合适高并发情况
  • (3)设置过期标志更新缓存

    • 记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际 key 的缓存
  • (4)将缓存失效时间分散开

    • 失效时间加随机值

17. 分布式锁

简介

在这里插入图片描述

分布式锁主流的实现方案:

  • 1.基于数据库实现方案
  • 2.基于缓存(Redis 等)
  • 3.基于 Zookeeper

每一种分布式锁解决方案都有各自的优缺点:

1.性能:redis 最高

2.可靠性:zookeeper 最高

17.1 解决方案: 使用 redis 实现 分布式锁

redis:命令

EX second:设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value

127.0.0.1:3366> setnx users 10		//加锁-> Redirected to slot [14124] located at 8.135.114.163:3368(integer) 18.135.114.163:3368> setnx users 20		// 需要释放了 才能在加锁(integer) 08.135.114.163:3368> setnx users 20(integer) 08.135.114.163:3368> del users			//释放(integer) 18.135.114.163:3368> setnx users 20(integer) 1

PX millisecond 设置键的过期时间为 millisecond 毫秒。

SET key value PX millisecond 效果等同于 PSETEX key millisecond vale

NX:只在 键 不存在时 ,才对键进行设置操作。

SET key value NX 效果等同于 SETNX key value

XX:只在键已经存在时,才对键进行设置操作。

在这里插入图片描述

设置: set users 10 nx ex 12

在这里插入图片描述

测试栗子:

package com.blog.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class RedisTestController {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/redistestRedis")
    public void testRedis()  {
        //1.获取锁,setne
        Boolean heng = redisTemplate.opsForValue().setIfAbsent("heng", "111");
        //2.获取锁成功、查询null的值
        if(heng){
            Object value = redisTemplate.opsForValue().get("num");
            // 2.1 判断num为空return
            if(StringUtils.isEmpty(value)){
                return;
            }
            //2.2有值就转成成int
            int num = Integer.parseInt(value + "");
            // 2.3把redis的num加1
            redisTemplate.opsForValue().set("num",++num);
            //2.4 释放锁,del
            redisTemplate.delete("heng");
        } else {
            // 3.获取锁失败、每隔0.1秒再获取
            try {
                Thread.sleep(100);
                testRedis();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        // 设置值到redis
//        redisTemplate.opsForValue().set("name","heng");
        //redis获取值
//        String name = (String) redisTemplate.opsForValue().get("name");

    }
}

在集群里 添加 set num “0”

使用apache-jmeter 10线程 100循环 等于 1000次数 100并发

在这里插入图片描述

17.2 锁使用 UUID 防误删

栗子

在这里插入图片描述

栗子

a服务器卡了,a锁过期了,但没执行完。b进去上锁,但是a突然反应过来了,就把lock锁释放了,a锁自动过期的,所以a释放了b的锁

b上锁的前提是,a锁自动过期,或者a自己释放锁

在这里插入图片描述

问题:删除操作缺乏原子性

在这里插入图片描述

为了确保分布式锁可用,我们至少确保锁的实现同时满足以下四个条件

  • 互斥性

    • 在任意时刻,只有一个客户端能持有锁
  • 不会发送死锁

    • 即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁
  • 解铃还须系铃人

    • 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了
  • 加锁和解锁必须具有原子性

18. Redis6.0 新功能

18.1 ACL

简介:

Redis ACL 是 Access Control List(访问控制列表)的缩写,该功能允许根据可以执行的命令和可以访问的键来限制某些连接

在 Redis 5 版本之前, Redis 安全规则只有密码控制 还有通过 rename 来调整高危命令比如 flushdb , shutdown 等。Redis 6 则提供 ACL 的功能对用户进行更细粒度的权限控制

  • (1)接入权限:用户名和密码
  • (2)可以执行的命令
  • (3)可以操作的 KEY

命令:

  1. 使用 acl list 命令展现用户权限列表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdVi8QuT-1622453406756)(C:\Users\heng\AppData\Roaming\Typora\typora-user-images\image-20210531154104798.png)]

  1. 使用 acl cat <类型> 查看相关的操作命令
127.0.0.1:3376> acl cat string 1) "incrby" 2) "decr" 3) "setrange" 4) "psetex" 5) "stralgo" 6) "substr" 7) "getex" 8) "append" 9) "msetnx"10) "mget"11) "incrbyfloat"12) "decrby"13) "mset"14) "set"15) "setex"16) "get"17) "incr"18) "setnx"19) "getset"20) "getrange"21) "strlen"22) "getdel"
  1. 使用 acl whoami 命令查看当前用户在这里插入图片描述

  2. 使用 aclsetuser 命令创建和编辑用户 ACL

  • 某些规则只是用于激活或删除标志,或对用户 ACL 执行给定更改的单个单词。其他规则是字符前缀,它们与命令或类别名称、键模式等连接在一起

在这里插入图片描述

在这里插入图片描述

  1. 新增 用户 acl setuser lucy
  2. 新增 用户 给与权限 acl setuser lucy on >password ~cached:* +get

在这里插入图片描述

  1. 切换 用户 auth 用户 password 使用权限 只有 get

在这里插入图片描述

18.2 IO 多线程

简介

IO多线程指客户端交互部分网络 IO ** 交互处理模块多线程**,而非 执行命令多线程 、Redis6 执行命令依然是单线程

Redis 的多线程部分只是用来处理网络数据的带写和协议解析,执行命令仍然是单线程

之所以这么设计是不想因为多线程而变的复杂,需要去控制 key、lua、事务、LPUSH/LPOP 等并发问题

多线程 IO 开启

io-threads-do-reads yes

io-threads 4 // 4 是线程数

18.3 工具支持 Cluster

在这里插入图片描述

新功能还有:

在这里插入图片描述

在这里插入图片描述

完了完了 一致性没有讲 可以自行复习

抛出一个问题 比如:

redis 存了 同一个key 两个 相同的value值 是怎么回事?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值