Redis相关

Redis

一. Redis简介

1.1 主流应用架构

在这里插入图片描述

解读: 首先使用缓存可以快速查找所需要的内容,不必每次都请求数据库;1-2则表示直接查询缓存;如果缓存中没有的话,就从数据库中查询到内容,然后返回存入Redis中再返回给客户端,这样下次请求此数据的时候就可以直接从缓存中查询了–>3,4,5,6 ; 而熔断7,8则表示直接对外提供一个服务,当存储器挂掉了,那么也可以直接从缓存中取值,然后直接返回结果;

1.2 缓存中间件–Memcache和Redis的区别?

  • Memcache: 代码层次类似Hash

    • 支持简单数据类型
    • 不支持数据持久化存储
    • 不支持主从
    • 不支持分片
  • Redis:

    • 数据类型丰富
    • 支持数据磁盘持久化存储
    • 支持主从

1.3 为什么Redis能这么快?

  • 完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高;
  • 数据结构简单,对数据操作也简单;
  • 采用单线程,单线程也能处理高并发请求,想多核也可启动多实例
  • 使用多路I/O复用模型,非阻塞IO
    • Redis采用I/O多路复用函数: epoll/kqueue/evport/select?
      • 因地制宜
      • 优先选择时间复杂度为O(1)的I/O多路复用函数作为底层实现
      • 以时间复杂度为O(n)的select 作为保底
      • 基于react设计模式监听I/O事件-

二. Redis常用的数据类型

2.1 常用数据类型

  • String : 最基本的数据类型,二进制安全
  • Hash: String元素组成的字典,适合用于存储对象
  • List: 列表,按照String 元素插入顺序排序
  • Set:String元素组成的无序集合,通过哈希表实现,不允许重复
  • Sorted Set: 通过分数来为集合中的成员进行从小到大的排序
  • 用于计数的HyperLogLog,用于支持存储地理位置信息的Geo等;

存入相同的key,但value不同的时候,会被重写,value值为最新输入的value值;

2.2 从海量Key里查询出某一固定前缀的Key

  • 留意细节:
    • 摸清数据规模,即问清楚边界
  • KEYS pattern: 查找所有给定模式pattern的Key
    • KEYS指令一次性返回所有匹配的key
    • 键的数量过大会使服务卡顿
  • SCAN cursor [MATCH pattern] [COUNT count]
    • 基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程
    • 以0作为游标开始一次新的迭代,直到命令返回游标0完成一次遍历
    • 不保证每次执行都返回某个给定数量的元素,支持模糊查询
    • 一次返回的数量不可控,只能是大概率符合count参数

可能会获取到重复数据,需要每次添加新的游标

三. 如何通过Redis实现分布式锁

3.1 分布式锁需要解决的问题

  • 互斥性
  • 安全性
  • 死锁
  • 容错

3.2 分布式锁的尝试:

在这里插入图片描述

可以使用setnx来实现分布式锁;当获取到锁的时候返回1,没有获取到则返回0,通过get还能确定是否为这个锁;

  • 如何解决SETNX长期有效的问题:
    • EXPIRE key seconds
      • 设置key的生存时间,当key过期时(生存时间为0),会被自动删除
    • 缺点:
      • 原子性得不到满足
RedisService redisService= SpringUtils.getBean(RedisService.class);
long status=redisService.setnx(key,"1");
if(status==1){
	redisService.expire(key,expire);
	//执行独占资源逻辑
	doOcuppiedWork();
}

使用过期时间,可以当一个线程获取到了锁之后,给它设置一个过期时间,在这个时间内执行方法;过期后就相当于释放锁;
存在的风险: 在设置过期时间前被挂掉的话,这个线程可能就会一直占用此线程

3.3 分布式锁的优化:

  • SET key value [EX seconds] [PX milliseconds] [NX|XX]

    • EX second: 设置键 的过期时间为second 秒
    • PX millisecond: 设置键的过期时间为millisecond 毫秒
    • NX: 只在键不存在时,才对键进行设置操作
    • XX: 只在键已经存在时,才对键进行设置操作
    • SET 操作成功完成时,返回OK,否则返回nil
  • 操作代码如下:

RedisService redisService =SpringUtils.getBean(RedisService.class);
String result=redisService.set(lockKey,requestId,SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME,expireTime);
if("OK",equals(result)){
	//执行独占资源逻辑
	doOcuppiedWork()
}

3.4 大量的Key同时过期的注意事项

  • 集中过期,由于清除大量的Key很耗时,会出现短暂的卡顿现象
    • 解决方案: 在设置key的过期时间的时候,给每个Key加上随机值;

3.5 如何使用Reids做异步队列

  • 使用List作为队列,PRUSH生产消息,LPOP消费消息

    • 缺点:没有等待队列里有值就直接消费
    • 弥补:可以通过在应用层引入Sleep机制去调用LPOP重试
  • BLPOP key [key…] timeout: 阻塞直到队列有消息或者超时

    • 缺点:只能供一个消费者消费
  • pub/sub: 主题订阅模式:

    • 发送者[pub]发送消息,订阅者(sub)接收消息

    • 订阅者可以订阅任意数量的频道

    • 图示:
      在这里插入图片描述

Redis Client1:
subscribe myTopic

Redis Client2: 
subscribe myTopic

Redis Client3:
subscribe anotherTopic

Redis Client4:
publish myTopic "Hello"


//publish这个返回值为订阅者数量,在这里面clent4推送的消息只有1,2能收到,3因为订阅的内容不同,所以无法收到

消息的发布是无状态的,无法保证可达

四. Redis的持久化方式–RDB

4.1 RDB持久化

  • RDB(快照)持久化: 保存某个时间点的全量数据快照

    • SAVE:阻塞Redis的服务器进程,直到RDB文件被创建完毕
    • BGSAVE: Fork出一个子进程来创建RDB文件,不阻塞服务器进程
  • 手动触发操作:

ls dump.rbd				# 显示dump.rdb
rm -f dump.rdb			# 删除所有dump.rdb
./redis-cli				#连接Redis客户端
save					#保存RDB持久化   会卡顿一段时间
exit					#退出
ls dump.rbd				...
rm-f dump.rdb			...
ls dump.rbd				# 已经被删除了,会提示:No such file or directory
./redis-cli				...
lastsave				# 快照最后一次保存的时间
bgsave					# 保存RDB持久化[单独开一个线程]  提示: Background saving started    不会卡顿
lastsave				# 最后一次的执行时间,这里会被更新;因为使用了bgsave
exit
  • 自动化触发RDB持久化的方式
    • 根据redis.conf 配置里的SAVE m n 定时触发(用的是BGSAVE)
    • 主从复制时,主节点自动触发
    • 执行Debug Reload
    • 执行Shutdown 且没有开启AOF持久化

4.2 BGSAVE原理

  • 示意图:
    在这里插入图片描述

系统调用fork(): 创建进程,实现了Copy-on-Write

4.3 Copy-on-Write

  • 概述:
    • 如果有多个调用者同时要求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正赋值一份专用副本给该调用者,而其他调用者所见到的最初的资源仍然保持不变;

4.4 RDB 持久化的缺点:

  • 内存数据的全量同步,数据量大会由于I/O而严重影响性能
  • 可能会因为Redis挂掉而丢失从当前至最近一次快照期间的数据

五. 持久化方式-- AOF及混合模式

5.1 概述:

  • AOF(Append-Only-File)持久化: 保存写状态
    • 记录下除了查询以外的所有变更数据库状态的指令
    • 以append的形式追加保存到AOF文件中(增量)

appendonly.aof[默认名字] 它是默认关闭的
vim redis.conf -> 将appendonly no 改为appendonly yes

ls appendonly.aof			# 判断是否已经存在,如果不存在则继续,假设不存在
config set appendonly yes
set aofTest "hehe"
exit
ls appendonly.aof			# 这时已经能正常显示了;

5.2 日志重写解决AOF文件大小不断增大的问题,原理如下;

  • 调用fork(),创建一个子进程
  • 子进程把新的AOF写到一个临时文件里,不依赖原来的AOF文件
  • 主进程持续将新的变动同时写到内存和原来的AOF里
  • 主进程获取子进程重写AOF的完成信号,往新AOF同步增量变动
  • 使用新的AOF文件替换掉旧的AOF文件

5.3 RDB和AOF文件共存情况下的恢复流程:

在这里插入图片描述

5.4 RDB和AOF的优缺点

  • RDB

    • 优点:全量数据快照,文件小,恢复快
    • 缺点: 无法保存最近一次快照之后的数据
  • AOF:

    • 优点:可读性高,适合保存增量数据,数据不易丢失
    • 缺点: 文件体积大,恢复时间长

5.5 RDB-AOF混合持久化方式:

  • 概述:
    • 细细想来aofrewrite时也是先写一份全量数据到新AOF文件中再追加增量只不过全量数据是以redis命令的格式写入。那么是否可以先以RDB格式写入全量数据再追加增量日志呢这样既可以提高aofrewrite和恢复速度也可以减少文件大小还可以保证数据的完毕性整合RDB和AOF的优点那么现在4.0实现了这一特性——RDB-AOF混合持久化。
  • 方式:BGSAVE做镜像全量持久化,AOF做增量持久化
  • 操作: 通过aof-use-preamble配置项可以打开混合开关

六. Pipeline及主从同步

6.1 使用Pipeline的好处:

  • Pipeline和Linux的管道类似
  • Redis基于请求/响应模型,单个请求处理需要一一应答
  • Pipeline批量执行指令,节省多次IO往返的时间
  • 有顺序依赖的指令建议分批发送

6.2 Redis全同步过程:

  • Salve发送sync命令到Master
  • Master启动一个后台进程,将Redis中的数据快照保存到文件中
  • Master 将保存数据快照期间接收到的写命令缓存起来
  • Master完成写文件操作后,将该文件发送给Salve
  • 使用新的AOF文件替换掉旧的AOF文件
  • Master将这期间收集的增量写命令发送给Salve端;

6.3 增量同步过程

  • Master 接收到用户的操作指令,判断是否需要传播到Slave
  • 将操作记录追加到AOF文件
  • 将操作传播到其他Slave: 1. 对其主从库 2. 往响应缓存写入指令 3. 将缓存中的数据发送给Slave

6.4 解决主从同步Master宕机后的主从切换问题:

  • 监控: 检查主从服务器是否运行正常
  • 提醒: 通过API向管理员或者其他应用程序发送故障通知
  • 自动故障迁移: 主从切换

6.5流言协议:Gossip

  • 在杂乱无章中寻求一致:
    • 每个节点都随机地与对方通信,最终所有节点的状态达成一致
    • 种子节点定期随机向其他节点发送节点列表以及需要传播的消息
    • 不保证信息一定会传递给所有节点,但是最终会趋于一致

七. Redis的集群原理

7.1 如何从海量数据里快速找到所需?

  • 分片:按照某种规则去划分数据,分散存储在多个节点上
  • 常规的按照哈希划分无法实现节点的动态增减

7.2 一致性哈希算法:

  • 概述: 对2^32取模,将哈希值空间组织成虚拟的圆环
  • 方式: 将数据key使用相同的函数Hash计算出哈希值:
    在这里插入图片描述

好处: 一个节点宕机后,其他的Node节点不会受到影响

7.3 Hash环的数据倾斜问题

  • 概述: 当节点数比较少的时候,比如只有2个的时候,当数据计算出来都存入了节点A,只有较小部分的数据存入了节点B,则会造成数据倾斜,数据没有平均的分配到各节点上,若A节点宕机则也会造成较大的影响;
  • 解决: 引入虚拟节点解决数据倾斜的问题:
    在这里插入图片描述

引入了虚拟节点,将本来只有A、B两个节点变成了A#1,A#2,A#3,B#1,B#2,B#3等六个节点,解决了节点少而造成数据分布不均匀的问题;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗余

码字来之不易,您的鼓励我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值