阶段十-分布式-Redis02

第一章 Redis 事务

1.1 节 数据库事务复习

数据库事务的四大特性

  • A:Atomic ,原子性,将所以SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
  • C:Consistent,一致性,事务完成后,所有的数据的状态都是一致的。即A账户只要减去100,B账户就必定增加100
  • I:Isolation,隔离性,如果有多个事务并发执行,每个事务做出的修改必须与其他事务隔离
  • D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储

1.2 节 Redis 事务介绍

Redis事务是一组命令的集合,一个事务中的所有命令都将被序列化,按照一次性、顺序性、排他性的执行一系列的命令。

Redis事务三大特性

  • 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断;

  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”。

  • 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚;

1.3 节 Redis 事务的基本操作

Multi、Exec、discard

示例1:正常执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 1
QUEUED
127.0.0.1:6379(TX)> get k1 
QUEUED
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "1"
3) (integer) 2
4) "2"

示例2:放弃事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k2 1
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> incr k2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> discard
OK

示例3:全部都不执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k3 1
QUEUED
127.0.0.1:6379(TX)> get k3 
QUEUED
127.0.0.1:6379(TX)> set k3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors

注意:

命令集合中含有错误的指令(注意是语法错误),全部失败。

示例4:运行时错误

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k4 1
QUEUED
127.0.0.1:6379(TX)> incr k4
QUEUED
127.0.0.1:6379(TX)> get k4
QUEUED
127.0.0.1:6379(TX)> set name zhangsan
QUEUED
127.0.0.1:6379(TX)> incr name
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (integer) 2
3) "2"
4) OK
5) (error) ERR value is not an integer or out of range
6) "zhangsan"

注意: 运行时错误,即非语法错误,正确命令都会执行,错误命令返回错误。

Redis有三种集群模式

  • 主从模式

  • Sentinel模式

  • Cluster模式

第二章 Redis 主从复制

2.1 节 Redis 主从复制概述

什么是主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点

主从复制的作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

  4. 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

2.2 节 Redis 主从复制搭建

在一台虚拟机上搭建

新建redis6379.conf

内容:

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

同理:

新建redis6380.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb

新建redis6381.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb

【2】启动三台redis服务器

redis-server ./redis6379.conf
redis-server ./redis6380.conf
redis-server ./redis6381.conf

【3】查看系统进程

ps -ef |grep redis

  会有已经运行的进程

root     122739      1  0 00:18 ?        00:00:00 redis-server 0.0.0.0:6379
root     122877      1  0 00:18 ?        00:00:00 redis-server 0.0.0.0:6380
root     122965      1  0 00:19 ?        00:00:00 redis-server 0.0.0.0:6381
root     123210   3414  0 00:19 pts/0    00:00:00 grep --color=auto redis

【4】查看三台主机运行情况

   info replication 查看节点相关信息

#打印主从复制的相关信息
./redis-cli -p 6379
./redis-cli -p 6380
./redis-cli -p 6381
127.0.0.1:6379> info replication
127.0.0.1:6380> info replication
127.0.0.1:6381> info replication

【5】配从库不配主库

slaveof <ip> <port>

示例:在6380和6381上执行

127.0.0.1:6380> SLAVEOF 192.168.184.100 6379
OK

【6】在主机上写,在从机上可以读取数据

set k1 v1

2.3 节 Redis 主从复制原理

主从复制可以分为3个阶段

  • 连接建立阶段(即准备阶段)

  • 数据同步阶段

  • 命令传播阶段

复制过程大致分为6个过程

  1. 保存主节点(master)信息。

  2. 从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接

  3. 从节点与主节点建立网络连接

    从节点会建立一个 socket 套接字,从节点建立了一个端口为51234的套接字,专门用于接受主节点发送的复制命令

  4. 发送ping命令

    连接建立成功后从节点发送 ping 请求进行首次通信。

  5. 权限验证。

    如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。

  6. 同步数据集。

    主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。

  7. 主从同步策略

        主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,            slave 在任何时候都可以发起全量同步。 redis 策略是,无论如何,首先会尝试进行增量同              步,如不成功,要求从机进行全量同步。

第三章 Redis 哨兵监控

3.1 节 Redis哨兵概述

主从复制的缺点:当主机 Master 宕机以后,我们需要人工解决切换

哨兵概述

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

哨兵作用

  1. 集群监控:负责监控redis master和slave进程是否正常工作

  2. 消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员

  3. 故障转移:如果master node挂掉了,会自动转移到slave node上

  4. 配置中心:如果故障转移发生了,通知client客户端新的master地址

3.2 节 Redis哨兵搭建

【1】编写配置文件

新建sentinel-26379.conf文件

#端口
port 26379
#守护进程运行
daemonize yes
#日志文件
logfile "26379.log"
sentinel monitor mymaster 192.168.184.100 6379 2

参数解释:

sentinel monitor mymaster 192.168.92.128 6379 2 配置的含义是:该哨兵节点监控192.168.92.128:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移。

同理

新建sentinel-26380.conf文件

#端口
port 26380
#守护进程运行
daemonize yes
#日志文件
logfile "26380.log"
sentinel monitor mymaster 192.168.184.100 6379 2

新建sentinel-26381.conf文件

#端口
port 26381
#守护进程运行
daemonize yes
#日志文件
logfile "26381.log"
sentinel monitor mymaster 192.168.184.100 6379 2

【2】启动哨兵节点

redis-sentinel sentinel-26379.conf
redis-sentinel sentinel-26380.conf
redis-sentinel sentinel-26381.conf

【3】查看哨兵状态

  先进入哨兵客户端

redis-cli -p 26379

 查看哨兵信息

info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.9.133:6379,slaves=2,sentinels=3

 sentinel_masters:1 该哨兵为主节点 

 address=192.168.9.133:6379 监控的ip

 slaves=2 有两个从节点

 sentinels=3 总共有三个哨兵监控

【4】测试故障转移,使用kill命令杀掉主节点

 查看所有服务

ps -ef | grep redis

  根据id杀死6379进程

kill -9  进程id

  哨兵会重新票选新的主节点,注意:需要等待一定的时间

  【5】查看哨兵节点信息

info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.9.133:6380,slaves=2,sentinels=3

  监听的ip变成了6380,6380变成了新的主节点

3.3 节 Redis 哨兵原理

3.3.1 监控阶段

注意:

  1. sentinel(哨兵1)----->向master(主)和slave(从)发起info,拿到全信息。

  2. sentinel(哨兵2)----->向master(主)发起info,就知道已经存在的sentinel(哨兵1)的信息,并且连接slave(从)。

  3. sentinel(哨兵2)----->向sentinel(哨兵1)发起subscribe(订阅)。

3.3.2 通知阶段

sentinel不断的向master和slave发起通知,收集信息。

3.3.3 故障转移阶段

通知阶段sentinel发送的通知没得到master的回应,就会把master标记为SRI_S_DOWN,并且把master的状态发给各个sentinel,其他sentinel听到master挂了,说我不信,我也去看看,并把结果共享给各个sentinel,当有一半的sentinel都认为master挂了的时候,就会把master标记为SRI_0_DOWN。

3.3.4 投票阶段

方式: 自己最先接到哪个sentinel的竞选通知就会把票投给它。

剔除一些情况:

  1. 不在线的

  2. 响应慢的

  3. 与原来master断开时间久的

  4. 优先级原则

第四章 Redis Cluster

完善哨兵模式的缺点:

  1. 当master挂掉的时候,sentinel 会选举出来一个 master,选举的时候是没有办法去访问Redis的,会存在访问瞬断的情况;

  2. 哨兵模式,对外只有master节点可以写,slave节点只能用于读。尽管Redis单节点最多支持10W的QPS,但是在电商大促的时候,写数据的压力全部在master上。

  3. Redis的单节点内存不能设置过大,若数据过大在主从同步将会很慢;在节点启动的时候,时间特别长;

4.1 节 Redis Cluster概述

Redis集群的优点

  • Redis集群有多个master,可以减小访问瞬断问题的影响

  • Redis集群有多个master,可以提供更高的并发量 

  • Redis集群可以分片存储,这样就可以存储更多的数据

4.2 节 Redis Cluster模式搭建

Redis的集群搭建最少需要3个master节点,我们这里搭建3个master,每个下面挂一个slave节点,总共6个Redis节点;

【1】 准备环境

 三个linux虚拟机

第1台机器: 192.168.9.131 8001端口 8002端口
第2台机器: 192.168.9.132 8001端口 8002端口
第3台机器: 192.168.9.133 8001端口 8002端口

拷贝配置文件

将redis安装目录下的 redis.conf 文件分别拷贝到8001和8002目录下

cp /usr/local/redis-6.2.6/redis.conf /usr/local/redis-cluster/8001
cp /usr/local/redis-6.2.6/redis.conf /usr/local/redis-cluster/8002

修改redis.conf文件以下内容 8001

# 端口
port 8001
# 后台启动
daemonize yes
# 进程id
pidfile "/var/run/redis_8001.pid"
#指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据
dir /usr/local/redis-cluster/8001/
#启动集群模式
cluster-enabled yes
#集群节点信息文件,这里800x最好和port对应上
cluster-config-file nodes-8001.conf
# 节点离线的超时时间
cluster-node-timeout 5000
#去掉bind绑定访问ip信息
#bind 127.0.0.1
#关闭保护模式
protected-mode no
#启动AOF文件
appendonly yes
#如果要设置密码需要增加如下配置:
#设置redis访问密码
#requirepass 123456
#设置集群节点间访问密码,跟上面一致
#masterauth 123456

修改redis.conf文件以下内容 8002

# 端口
port 8002
# 后台启动
daemonize yes
# 进程id
pidfile "/var/run/redis_8002.pid"
#指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据
dir /usr/local/redis-cluster/8002/
#启动集群模式
cluster-enabled yes
#集群节点信息文件,这里800x最好和port对应上
cluster-config-file nodes-8002.conf
# 节点离线的超时时间
cluster-node-timeout 5000
#去掉bind绑定访问ip信息
#bind 127.0.0.1
#关闭保护模式
protected-mode no
#启动AOF文件
appendonly yes
#如果要设置密码需要增加如下配置:
#设置redis访问密码
#requirepass 123456
#设置集群节点间访问密码,跟上面一致
#masterauth 123456

三台机器同理

【3】启动集群

每台机器都启动服务器

redis-server /usr/local/redis-cluster/8001/redis.conf
redis-server /usr/local/redis-cluster/8002/redis.conf

创建集群

redis-cli -a redis-pw --cluster create --cluster-replicas 1 
192.168.9.131:8001 192.168.9.131:8002	
192.168.9.132:8001 192.168.9.132:8002	
192.168.9.133:8001 192.168.9.133:8002

 没有密码去掉 -a   redis  -pw

查看帮助命令

 src/redis‐cli --cluster help

参数:

  • create:创建一个集群环境host1:port1 ... hostN:portN

  • call:可以执行redis命令

  • add-node:将一个节点添加到集群里,第一个参数为新节点的ip:port,第二个参数为集群中任意一个已经存在的节点的ip:port

  • del-node:移除一个节点

  • reshard:重新分片

  • check:检查集群状态

【4】测试集群

连接任意一个客户端

redis-cli -a redis-pw -c -h 192.168.9.131 -p 8001

参数:

  • ‐a表示服务端密码

  • ‐c表示集群模式

  • -h指定ip地址

  • -p表示端口号

查看集群的信息

cluster info

4.3 节 Redis Cluster 原理

Redis Cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。只有master节点会被分配槽位,slave节点不会分配槽位。

槽位定位算法: k1 = 127001

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。

HASH_SLOT = CRC16(key) % 16384

命令执行

set k1 v1

存入了12706槽位中

可以通过{}来定义组的概念,从而是key中{}内相同内容的键值对放到同一个slot中。

mset k1{test} v1 k2{test} v2 k3{test} v3

 让三个key在同一个槽位之中

故障恢复案例:

杀死Master节点之后还会重新选举

观察节点信息

cluster nodes

第五章 SpringDataRedis 连接集群

 【1】添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

【2】编写配置

spring:redis:cluster:nodes: 192.168.9.131:8001,192.168.9.131:8002,192.168.9.132:8001,192.168.9.132:8002,192.168.9.133:8001,192.168.9.133:8002

【3】编写测试

@SpringBootTest
class RedisDemo2ApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {redisTemplate.opsForValue().set("k6","v6");System.out.println(redisTemplate.opsForValue().get("k6"));}
}

第六章 Redis常见问题探析(面试题)

6.1 节 Redis脑裂问题

6.1.1 什么是集群脑裂

Redis的集群脑裂是指因为网络问题,导致Redis Master节点跟Redis slave节点和Sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点。

个人理解就是有一个主节点宕机了,无法与客户端进行连接,就不会参与新的选举,在其恢复状态后还是以主节点的身份参与工作,造成了多个主节点同时存在的问题,这就是脑裂问题。 

6.1.2 解决方案

redis.conf配置参数:

min-replicas-to-write 1
min-replicas-max-lag 5

参数:

  • 第一个参数表示最少的slave节点为1个

  • 第二个参数表示数据复制和同步的延迟不能超过5秒

6.2 节 Redis 缓存预热问题

6.2.1 缓存冷启动

缓存中没有数据,由于缓存冷启动一点数据都没有,如果直接就对外提供服务了,那么并发量上来Mysql就裸奔挂掉了。

6.2.2 冷启动应用场景

新启动的系统没有任何缓存数据,在缓存重建数据的过程中,系统性能和数据库负载都不太好,所以最好是在系统上线之前就把要缓存的热点数据加载到缓存中,这种缓存预加载手段就是缓存预热。

6.2.3 解决思路

  • 提前给redis中灌入部分数据,再提供服务

  • 如果数据量非常大,就不可能将所有数据都写入redis,因为数据量太大了,第一是因为耗费的时间太长了,第二根本redis容纳不下所有的数据

  • 需要根据当天的具体访问情况,实时统计出访问频率较高的热数据

  • 然后将访问频率较高的热数据写入redis中,肯定是热数据也比较多,我们也得多个服务并行读取数据去写,并行的分布式的缓存预热

6.3 节 Redis缓存穿透问题

6.3.1 概念

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

用户访问空的数据库与缓存

解释:

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。

6.3.2 解决方案

  • 对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果缓存,设置空结果的过期时间会很短,最长不超过5分钟。简单的说就是返回一个空值

  • 布隆过滤器:如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。

6.3.3 布隆过滤器

布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。

所以判断不存在的数据最快

6.3.4 代码实现

【1】引入依赖

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.17</version>
</dependency>

【2】java代码实现

// 初始化 注意 构造方法的参数大小10 决定了布隆过滤器BitMap的大小
BitMapBloomFilter filter  = new BitMapBloomFilter(10);
filter.add("123");
filter.add("abc");
filter.add("ddd");
boolean abc = filter.contains("abc");
System.out.println(abc);

6.4 节 Redis 缓存击穿问题

6.4.1 概念

某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。

6.4.2 解决方案

  • 互斥锁:在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,其他线程直接查询缓存。

  • 热点数据不过期:直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存(不咋靠谱)

6.4.3 代码实现(有待改进)

理念是对的,但是满足不了的企业的实际需求

真正的解决方案是使用第三方的软件进行控制

public String get(String key) throws InterruptedException {String value = jedis.get(key);// 缓存过期if (value == null){// 设置3分钟超时,防止删除操作失败的时候 下一次缓存不能load db//setnx 如果有值返回0,如果没有值设置值返回1Long setnx = jedis.setnx(key +"mutex", "1");           jedis.pexpire(key + "mutex", 3 *60);// 代表设置成功if (setnx == 1){// 数据库查询//value = db.get(key);//保存缓存jedis.setex(key,3*60,"");jedis.del(key + "mutex");return value;}else {// 这个时候代表同时操作的其他线程已经load db并设置缓存了。需要重新重新获取缓存           //这个睡眠不够严谨,不能保证操作完成,value的值已经更新完成Thread.sleep(50);// 重试return get(key);}}else {return value;}
}

6.5 节 Redis缓存雪崩问题

6.5.1 概念

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

就是大量的数据同时过期

6.5.2 解决方案

二级缓存解决:先查询本地nginx缓存查询有没有数据,有数据,直接返回;nginx缓存没有数据再去redis分布式缓存查询,如果有将redis缓存同步nginx缓存在返回;如果redis没有,取数据库查询,数据库存在将数据同步到redis并返回。只要nginx的过期时间和redis的过期时间不一样就解决了缓存雪崩问题,并合理使用了本地缓存和分布式缓存。

6.6 节 Redis 开发规范

6.6.1 key设计技巧

  1. 把表名转换为key前缀,如 tag:

  2. 把第二段放置用于区分key的字段,对应msyql中主键的列名,如 user_id

  3. 第三段放置主键值,如 2,3,4

  4. 第四段写存储的列名

6.6.2 value设计

拒绝bigkey

防止网卡流量、慢查询,string类型控制在10KB以内,hash、 list、set、zset元素个数不要超过5000。

6.6.3 命令使用

  1. 禁用命令 :禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。

  2. 合理使用select :redis的多数据库较弱,使用数字进行区分,很多客户端支持较差, 同时多业务用多数据库实际还是单线程处理,会有干扰。

  3. 使用批量操作提高效率

    1. 原生命令:例如mget、mset。

    2. 非原生命令:可以使用pipeline提高效率

注意:但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。

  1. 不建议过多使用Redis事务功能

    Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上。

6.7 节 Redis 数据一致性问题

三种更新策略

  1. 先更新数据库,再更新缓存

  2. 先删除缓存,再更新数据库

  3. 先更新数据库,再删除缓存

先更新数据库,再更新缓存

这套方案,大家是普遍反对的。为什么呢?

线程安全角度 ,同时有请求A和请求B进行更新操作,那么会出现

(1)线程A更新了数据库

(2)线程B更新了数据库

(3)线程B更新了缓存

(4)线程A更新了缓存

这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

先删缓存,再更新数据库

该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:

(1)请求A进行写操作,删除缓存

(2)请求B查询发现缓存不存在

(3)请求B去数据库查询得到旧值

(4)请求B将旧值写入缓存

(5)请求A将新值写入数据库

注意: 该数据永远都是脏数据。

先更新数据库,再延时删缓存

这种情况存在并发问题吗?

(1)缓存刚好失效

(2)请求A查询数据库,得一个旧值

(3)请求B将新值写入数据库

(4)请求B删除缓存

(5)请求A将查到的旧值写入缓存

发生这种情况的概率又有多少?

发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的,因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。

第七章 总结

【1】简述以下redis事务?

答:redsi的事务和关系型数据库事务解决问题不一样,原则也不一样,没有acid原则,redis事务保证命令按照队列顺序执行问题,所以redis事务分为两个阶段,第一个阶段是命令入队,第二个阶段是命令执行。

如果队列中命令都证正确,那么按照入队顺序执行,如果队列中命令语法错误,队列所有命名都不执行,如果队列命令语法没错,但是执行失败,只有该命令本身不会执行,其他命令都会执行

redis事务命令

multi 开启事务
exec 执行事务
discard 取消事务

【2】简述一下Redis的主从复制模式

答:Redis集群模式分三种

  • 主从模式

  • 哨兵模式

  • 集群模式

主从模式从一定程度上解决单机Redis的并发问题和可用性问题。但是主从模式问题很大,主节点挂了,需要手动将从节点切换为主节点,所以实际开发很少用到。然后Redis主从复制是哨兵机制和集群机制的根本,所以理解主从模式很重要。

主从模式原理如下:

  1. 从节点保存主节点(master)信息。

  2. 从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接。

  3. 从节点与主节点建立网络连接 。

  4. 发送ping命令 :连接建立成功后从节点发送 ping 请求进行首次通信

  5. 权限验证:如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。

  6. 主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。

  7. 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。 redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

【3】简述一下哨兵模式

答:哨兵模式主要解决主从复制master节点挂掉之后的,切换从节点为主节点问题,哨兵模式通过监控主从复制主节点和从节点完成自动切换主节点功能。

原理如下:

【4】简述以下Redis集群模式

答:集群模式至少需要6个redis服务器,集群模式就是n个主从复制模式,但是需要根据插槽机制分配每个节点存取数据范围。来解决单个主从redis不能存取数据过大问题,因为会降低从节点复制速度。

原理:

【5】Redis脑裂问题解决?

答:Redis主从模式下,由于主节点挂了,从节点新选出主节点,由于网络情况,挂掉主节点没有降级为从节点,导致有两个主节点可以写数据。导致挂掉的主节点的数据无法同步而丢失问题。解决办法

min-replicas-to-write 1
min-replicas-max-lag 5

【6】如何解决缓存冷启动问题?

答:冷启动是指服务器缓存中没有数据直接启动,访问量有比较大,mysql直接裸机运行。通过缓存预热解决,通过storm实时计算出热点数据,然后定时将热点数据写入缓存。

【7】如何解决缓存穿透问题?

答:查询一个redis和mysql肯定都不存在的数据是缓存穿透,例如查询id为-1的数据,多半为认为恶意攻击。解决方案:去数据库查不存在在redis存null,并且设置过期时间5分钟。

或者用布隆过器解决:布隆过滤器是一个bitMap数组,它说不存在的元素一定不存在,他说存在的未必存在。

【8】如何缓存击穿问题?

答:某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。从造成问题的原因去解决,当热点Key失效的一刹那,大并发裸奔访问数据库,数据库被打垮。我们只需要在热点Key失效的一刹那保证只有一个请求过来就可以了。这种需求肯定用锁解决,理论上可以用同步锁解决,但这个不靠谱,锁只能锁一个进程,但是微服务是多个服务是多个进程,根本不起作用。所以用分布式锁解决。

【9】如何解决缓存雪崩问题?

答:大量缓存同时失效,数据库被击垮问题。解决思路不让缓存同时失效,比如加给缓存过期时间加随机数,但是当缓存数据足够大时,这个效果不那么明显了,可以通过二级缓存技术实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/594391.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day04 两两交换链表中的节点 删除链表的倒数第N个节点 链表相交 环形链表Ⅱ

题目1&#xff1a;24 两两交换链表中的节点 题目链接&#xff1a;24 两两交换链表中的节点 题意 两两交换链表中相邻的节点&#xff0c;返回交换后链表的头节点 虚拟头节点 注意终止条件&#xff0c;考虑节点的奇偶数&#xff0c;根据奇偶数确定终止条件 注意定义中间变量…

新闻稿发布:媒体重要还是价格重要

在当今信息爆炸的数字时代&#xff0c;企业推广与品牌塑造不可或缺的一环就是新闻稿发布。新闻稿是一种通过媒体渠道传递企业信息、宣传品牌、事件或产品新闻的文本形式。发布新闻稿的过程旨在将企业的声音传递给更广泛的受众&#xff0c;借助媒体平台实现品牌故事的广泛传播。…

探索Allure Report:提升自动化测试效率的秘密武器

亲爱的小伙伴们&#xff0c;由于微信公众号改版&#xff0c;打乱了发布时间&#xff0c;为了保证大家可以及时收到文章的推送&#xff0c;可以点击上方蓝字关注测试工程师成长之路&#xff0c;并设为星标就可以第一时间收到推送哦&#xff01; 一.使用 Allure2 运行方式-Python…

阿里云服务器云盘ESSD Entry、SSD、高效云盘性能测评

阿里云服务器系统盘或数据盘支持多种云盘类型&#xff0c;如高效云盘、ESSD Entry云盘、SSD云盘、ESSD云盘、ESSD PL-X云盘及ESSD AutoPL云盘等&#xff0c;阿里云百科aliyunbaike.com详细介绍不同云盘说明及单盘容量、最大/最小IOPS、最大/最小吞吐量、单路随机写平均时延等性…

什么猫粮比较好?哪些牌子的主食冻干健康又实惠?

很多养猫的小伙伴们都磨刀霍霍准备给猫咪屯猫些猫冻干吧&#xff0c;特别是家里有挑食猫咪的家庭。有养猫的铲屎官们应该都知道&#xff0c;猫咪是对蛋白质的需求量很高&#xff0c;而且对植物蛋白的吸收效率比较低&#xff0c;所以蛋白质最好都是来自动物的优质蛋白。猫咪挑食…

基于rk3568 Android H265推流SRS低延迟网页播放方案

在音视频领域&#xff0c;融合推流&#xff0c;低码流&#xff0c;低延迟&#xff0c;浏览器H5化是一个降低成本&#xff0c;提升用户体验的重要手段。同时适配现有直播的生态也是一个必要条件。 在满足上述要求的情况下&#xff0c;我做了以下实践&#xff0c;取得了良好的效果…

赴一场AI星河之约:他们改变了什么?

你认识AI开发者吗&#xff1f; 在工作中&#xff0c;我们会采访形形色色的AI开发者。他们来自不同的地方&#xff0c;说着不同的口音。年纪小的还没上小学&#xff0c;年纪大的在退休之后又找到了新的兴趣与梦想。他们有人心怀温暖&#xff0c;用AI技术帮助听障人士恢复听力&am…

电商数仓可视化1--数据导入

1、数据来源介绍以及数据文件下载 1、业务数据 业务数据往往产生于事务型过程处理&#xff0c;所以一般存储在关系型数据库中&#xff0c;如mysql、oracle 业务数据源&#xff1a; 用户基本信息、商品分类信息、商品信息、店铺信息、订单数据、订单支付信息、活动信息…

小白也能看得懂的Jmeter性能测试中服务端资源监控技术

操作步骤&#xff1a; 1、安装插件管理器 插件管理器的作用&#xff1a;可以提供扩展插件的在线安装升级和卸载。因为我们需要在线安装监控插件&#xff0c;首先我们就要先安装插件管理器。 插件管理器的下载地址&#xff1a;https://jmeter-plugins.org/install/Install/ 如…

Allins 官网正式上线,铭文赛道进入 AMM 交易时代

“Allins正在通过全新的AMM方案为BRC20及多链铭文资产拓展DeFi场景&#xff0c;官网的全新上线意味着铭文资产的交易正式进入AMM时代。” 在2023年1月开始&#xff0c;Ordinals协议的推出成为了铭文赛道发展的开端&#xff0c;并为比特币这类非图灵完备的生态&#xff0c;带来了…

全院级医学影像PACS源码,影像采集传输与存储管理、影像诊断查询与报告管理

全院医学影像PACS源码&#xff0c;数字化影像信息系统源码&#xff0c;带三维影像后处理技术 全院影像设备联网与影像信息数字化存储&#xff0c;建立涵盖全院的PACS/RIS系统&#xff0c;实现从预约、登记、分诊、排队叫号、检查、诊断阅片、报告发布、自助胶片打印等流程化管…

Android逆向入门教程

前言 什么是 Android 逆向开发&#xff1f; Android 逆向开发是指对已发布的 Android 应用进行分析和破解&#xff0c;以了解应用程序的内部工作原理&#xff0c;获取应用程序的敏感信息&#xff0c;或者修改应用程序的行为。逆向开发可以帮助开发人员了解他人的代码实现&…

Java网络编程之IP,端口号,通信协议(UDP,TCP)

目录 1.软件架构2.网络编程三要素3.IP1.IPV42.IPV6 4.端口号5.协议1.UDP协议1.单播2.组播3.广播 2.TCP协议1.三次握手2.四次挥手 1.软件架构 ①C/S&#xff1a;客户端/服务器 在用户本地需要下载安装客户端程序&#xff0c;在远程有一个服务器端程序。 优点&#xff1a;画面精美…

Python学习笔记之(一)搭建Python 环境

搭建Python 环境 1. 使用工具准备1.1 Python 安装1.1.1 下载Python 安装包1.1.2 安装Python 1.2 VScode 安装1.2.1 下载VScode安装包1.2.2 给VScode安装Python 扩展 2. 第一次编写Python 程序 本篇文章以Windows 系统为例。 1. 使用工具准备 1.1 Python 安装 1.1.1 下载Pytho…

【设计模式】策略模式

文章目录 前言一、概述结构 二、实现案例三、优缺点使用场景 四、JDK源码分析总结 前言 【设计模式】策略模式——行为型设计模式。 一、概述 先看下面的图片&#xff0c;我们去旅游选择出行模式有很多种&#xff0c;可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为…

性能测评高效云盘、ESSD Entry云盘、SSD云盘、ESSD云盘、ESSD PL-X云盘及ESSD AutoPL云盘

阿里云服务器系统盘或数据盘支持多种云盘类型&#xff0c;如高效云盘、ESSD Entry云盘、SSD云盘、ESSD云盘、ESSD PL-X云盘及ESSD AutoPL云盘等&#xff0c;阿里云百科aliyunbaike.com详细介绍不同云盘说明及单盘容量、最大/最小IOPS、最大/最小吞吐量、单路随机写平均时延等性…

​如何把图片里背景的路人P掉?教你四种方法消除路人

在日常生活中&#xff0c;我们经常会遇到需要将图片中背景的路人P掉的情况。有时候&#xff0c;这些路人会破坏图片的整体美感&#xff0c;或者我们只想要图片中的某些元素&#xff0c;而路人的出现会分散注意力。那么&#xff0c;如何才能有效地将图片中的背景路人P掉呢&#…

天津大数据培训机构 大数据时代已到来!

大数据时代已经来临&#xff0c;越来越多的人开始关注大数据&#xff0c;并且准备转行大数据。但是&#xff0c;对于一个外行人或者小白来说&#xff0c;大数据是什么&#xff1f;大数据需要学什么&#xff1f;什么样的大数据培训机构是靠谱的&#xff1f;这几个简单的问题就足…

Ubuntu无网络解决办法

1.进入root并输入密码 sudo su 2.更新NetworkManager的配置 用vim打开NetworkManager.conf vim /etc/NetworkManager/NetworkManager.conf 将第五行 managedFalse 改为 managedTrue 。 如果本身就是True就不用改了。 3.删除NetworkManager配置 service NetworkManager st…

服务器终端快速下载coco数据集

######解压到当前文件夹 sudo apt-get install aria2 aria2c -c <url> #<url>即为官网下载地址# url # download images http://images.cocodataset.org/zips/train2017.zip http://images.cocodataset.org/zips/val2017.zip# download annotations http://i…