目录
1.redis常用数据结构
2.redis的持久化机制有哪些?
3.redis的高可用方案分片集群模式
4.redis的高可用方案哨兵哨兵模式
5.redis的高可用方案主从模式介绍
6.redis key的删除策略?
7.redis 缓存淘汰策略?
8.Redisson实现分布式锁的原理?
9.是否了解缓存穿透
10.是否了解缓存雪崩?
针对于雪崩问题,可以分情况进行解决:
11.是否了解缓存击穿?
12.redis为什么被设计成单线程?
13.redis为什么那么快?
14.redis的脑裂问题是什么?如何解决?
redis常用的数据类型有String、list、hash、set、Zset
1. String是普通的字符串,存储一些简单的数据,例如用户登陆的时候后端保存短信验证码
2. list相当于java中的集合,有序,假如存储12345,查看时则是54321,场景例如网页中的轮播图、网页中特价商品
3. hash 相当于Java中的hashmap,可以定义一个键之后,后面设置多个值,例如用于存储用户信息,商品信息等等
4. set 是String类型的无序集合,但是其中的元素是唯一的,中间不能出现重复元素,当输入时有重复元素,存储的时候能够自动去重,需要去重的少量信息,比如身份证信息、手机号码作为黑白名单共同好友查询
5. Zset是一个有序集合,但存储的时候成员名字不能重复,就跟一个班级成绩一样,名字不能重复,但是分数可以重复,查询的时候会按照成绩高低进行排序,例如视频网站的点击量排名、收藏量排名等等。
Zset底层维护了跳表结构!--》JUC并发包中有类似结构
持久化的方案有两种,分别是RDB和AOF,根据不同的场景,可以选择只使用其中一个或者一起使用
RDB是通过保存快照的方式来对数据进行持久化处理,所保存的数据的本身,默认使用的是bgsave来保存快照数据。
RDB的优缺点:
优点:
● 基于二进制文件完成数据备份,占用空间少,便于文件传输。
● 能够自定义规则,根据Redis繁忙状态进行数据备份
缺点:
● 无法保证数据完整性,会丢失最后一次快照后的所有数据
● bgsave执行每次执行都会阻塞Redis服务进程创建子线程,频繁执行影响系统吞吐量
RDB方式会出现数据丢失的问题,对于这个问题,可以通过Redis中另一个持久化方式解决:AOF
当AOF持久化开启之后,Redis会将客户端发送的所有更改数据的命令保存至磁盘中,通过读取AOF文件,按照顺序获取所记录的数据命令,来达到恢复数据的效果。
AOF的触发机制有三种,分别为:
● always:每操作一条命令,都往磁盘当中同步一次,该方式效率最高,不会丢失数据,安全性最高,但是十分浪费资源。
● everysec:每次执行写入命令,都将aof_buf缓冲区文件全部写入到AOF文件中,并且每隔一秒同步到磁盘当中一次,该方式兼备了效率和安全,即使出现宕机情况,也就丢失一秒钟的数据。
● no:将同步操作交给操作系统来做,该方式最快,但是最不安全。
RDB是默认开启的,AOF需要手动开启
RDB性能优于AOF
AOF的安全性优于RDB
AOF的优先级高于RDB
RDB存储某个时刻的数据快照,AOF存储写命令
RDB在配置触发状态会丢失最后一次快照以后更改的所有数据,AOF默认使用everysec,每一秒保存一次。
Redis的高可用方案分片集群模式是将数据分散到多个节点上,以提高系统吞吐量和可用性。其中,每个节点负责一部分数据,称为分片,客户端通过路由算法将操作发送到相应的节点。
优点:
可以水平扩展,增加节点数可以增加系统容量。
单个节点故障不会影响整个集群。
分布式存储可以提高系统的可靠性和可用性。
缺点:
集群管理比较复杂,需要考虑节点间的路由、负载均衡、数据迁移等问题。
数据分布不均匀时可能导致某些节点热点数据过多,从而影响性能。
事务操作有限制,只支持单个节点内的事务,跨节点事务需要手动实现。
总体来说,Redis的分片集群模式适合于需要处理海量数据的场景,并且要求高可用性和可伸缩性,但也需要在架构设计和节点管理上进行充分考虑和规划。
Redis分片集群架构的原理是将一个大的Redis数据库拆分成多个小的Redis数据库,每个小的Redis数据库叫做分片(shard),每个分片存储一部分数据。这种方式可以提高整个系统的可扩展性和容量。
Redis分片集群使用哈希槽(hash slot)来将数据分配到不同的分片中。哈希槽是一个固定数量的数字范围,通常是0-16383。当客户端发送一个写请求时,Redis会根据键值计算出相应的哈希槽,并将该请求发送到负责管理该哈希槽的分片节点上进行处理。
在一个Redis分片集群中,每个节点都可以有多个分片,每个分片都是独立的Redis实例。所有分片共享一个哈希槽空间,每个分片负责管理其中一部分哈希槽。为了确保每个哈希槽只由一个分片管理,Redis采用了一种叫做哈希槽映射(hash slot mapping)的算法,它可以将每个哈希槽映射到唯一的一个分片。
哈希槽映射算法的具体实现可以简单地使用crc16算法计算键值的哈希值,然后将哈希值对16384取模得到对应的哈希槽。这种方式可以确保键值在哈希槽空间中的均匀分布,并且每个哈希槽只被一个分片管理。
在Redis分片集群中,常见的部署方式是使用一组主节点和一组从节点。每个主节点都负责管理若干个分片,每个从节点都复制其对应主节点上的数据。当主节点发生故障时,从节点会自动接替其工作,确保整个系统的高可用性。
总的来说,Redis分片集群架构的原理就是将一个大的Redis数据库拆分成多个小的Redis数据库,通过哈希槽映射算法将数据分配到不同的分片中,以提高整个系统的可扩展性和容量。最大支持16384个哈希槽。
Redis哨兵模式是一种用于实现Redis高可用性的解决方案。该架构包含了一个或多个哨兵节点,它们会监控主Redis节点和备份Redis节点的运行状态,并在主Redis节点失效时自动将备份节点升级为新的主Redis节点。
优点:
可以保证Redis的高可用性,在主Redis节点出现故障时可以快速将备份节点升级为新的主节点,避免了因单点故障导致服务不可用的情况。
哨兵节点之间相互独立,可以提高系统的可靠性和稳定性。
配置简单,易于扩展。
缺点:
哨兵节点不能自动进行故障恢复,只能进行自动故障转移,需要人工介入进行故障恢复操作。
在进行自动故障转移时,会存在短暂的数据不一致现象。
哨兵节点本身也可能成为系统的单点故障,需要进行高可用部署。
总结:
哨兵模式是Redis高可用性的一种解决方案,通过引入哨兵节点来实现主备Redis节点的自动故障转移,从而保障系统的可用性。但同时也存在一些限制和缺陷,需要在实际应用中根据实际情况进行权衡和考虑。
Redis的高可用方案之一是主从复制模式,它可以实现数据的自动备份和故障转移。该模式下,一个Redis服务器作为主服务器,而其他Redis服务器则作为从服务器,主服务器会将写入的数据同步到所有从服务器上。当主服务器出现故障时,从服务器中选取一个成为新的主服务器。
主从模式的优点包括:简单易懂、易于部署、能够提高系统的可扩展性和容错性。同时,数据读取可以通过从服务器进行负载均衡,提高系统的读并发性能。
缺点包括:数据同步存在延迟,可能会导致主服务器和从服务器之间的数据不一致。同时需要考虑数据的备份和恢复问题,以及主服务器的单点故障问题。
● 定时删除:对于设定了过期时间的key,同时还创建了一个定时器,当key达到删除时间,定时器就会被触发,此时就会将过期的key删除,该策略对内存空间足够友好, 但对CPU非常不友好,会拉低系统性能,因此不建议使用。
● 惰性删除:为了解决定时删除会占用大量CPU的问题,因此产生了惰性删除,它不持续关注key的过期时间,而是在获取key时,它才会检查key是否过期,如果过期则删除该key,这样子的话,对CPU很友好,但是对内存就不友好了,因为有的key假如一直没有用到,则会占用内存
● 定期删除:定期删除是对定时删除和惰性删除做了平衡,redis默认每秒运行10次对具有过期时间的key进行一次扫描,但是不会扫描全部的key,因为这样会大大延长扫描时间。每次默认只会扫描20个key,同时删除这20个key中已经过期的key,如果这20个key中过期key的比例超过25%,则继续扫描
Redis的内存参数配置,在64位操作系统中,如果未设置或设置0,代表无限制,而在32位系统中,默认内存大小为3GB。但是在实际生产环境下,一般会设置物理内存的四分之三左右。当客户端执行命令添加数据时,Redis会检查内存空间大小,如果超过最大内存,则会触发内存淘汰策略。淘汰策略分为以下三种八类:
1.对设置了过期时间数据淘汰:
● 设置了过期时间,且最近最久没有使用的数据进行淘汰
● 设置了过期时间,且最近最少没有使用的数据进行淘汰
● 设置了过期时间,且即将过期的数据进行淘汰
● 设置了过期时间的数据进行随机淘汰
2.对所有数据淘汰:
● 从所有数据中,删除最近最久没有被使用的数据进行淘汰
● 从所有数据中,删除最近最少没有被使用的数据进行淘汰
● 从所有的数据中,随机删除
3.不淘汰:(默认)
● 当内存空间不足时,直接返回错误信息
● 加锁机制
线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。
线程去获取锁,获取失败: 一直通过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis
● WatchDog自动延期看门狗机制
第一种情况:在一个分布式环境下,假如一个线程获得锁后,突然服务器宕机了,那么这个时候在一定时间后这个锁会自动释放,你也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生
第二种情况:线程A业务还没有执行完,时间就过了,线程A 还想持有锁的话,就会启动一个watch dog后台线程,不断的延长锁key的生存时间
● lua脚本-保证原子性操作
主要是如果你的业务逻辑复杂的话,通过封装在lua脚本中发送给redis,而且redis是单线程的,这样就保证这段复杂业务逻辑执行的原子性
缓存穿透是指,如果一个 key 在缓存和数据库都不存在,那么访问这个 key 每次都会进入数据库
● 很可能被恶意请求利用
● 缓存雪崩与缓存击穿都是数据库中有,但缓存暂时缺失
● 缓存雪崩与缓存击穿都能自然恢复,但缓存穿透则不能
针对缓存穿透,一般有两种解决方案,分别是:
● 如果数据库没有,也将此不存在的 key 关联 null 值放入缓存,缺点是这样的 key 没有任何业务作用,白占空间
● 采用BloomFilter(布隆过滤器)解决,基本思路就是将存在数据的哈希值存储到一个足够大的bitmap中,在查询redis时,先查询布隆过滤器,如果数据不存在直接返回即可,如果存在的话,再执行缓存中命中、数据库查询等操作。
缓存雪崩的情况往往是由两种情况产生:
● 情况1:由于大量 key 设置了相同的过期时间(数据在缓存和数据库都存在),一旦到达过期时间点,这些 key 集体失效,造成访问这些 key 的请求全部进入数据库。
● 情况2:Redis 实例宕机,大量请求进入数据库
● 情况1的解决方案
○ 错开过期时间:在过期时间上加上随机值(比如 1~5 分钟)
○ 服务降级:暂停非核心数据查询缓存,返回预定义信息(错误页面,空值等)
● 情况2的解决方案
○ 事前预防:搭建高可用集群
○ 构建多级缓存,实现成本稍高
○ 熔断:通过监控一旦雪崩出现,暂停缓存访问待实例恢复,返回预定义信息(有损方案)
○ 限流:通过监控一旦发现数据库访问量超过阈值,限制访问数据库的请求数(有损方案)
缓存击穿是指,某一热点数据存储到redis中,该数据处于高并发场景下,如果此时该key过期失效,这样就会有大量的并发请求进入到数据库,对数据库产生大的压力,甚至会压垮数据库。
针对于缓存击穿这种情况,常见的解决方案有两种:
● 热数据不设置过期时间
● 使用互斥锁,可以使用redisson的分布式锁实现,就是从redis中查询不到数据时,不要立刻去查数据库,而是先获取锁,获取到锁后再去查询数据库,而其他未获取到锁的请求进行重试,这样就可以确保只有一个查询数据库并且更新缓存的请求。
Redis 被设计成单线程的原因是为了最大限度地利用 CPU 缓存和避免多线程并发带来的锁争用、上下文切换等开销,从而实现更高的性能和更低的延迟。此外,Redis 采用异步 I/O 模型,可以同时处理多个客户端请求,进一步提高了并发能力。
Redis 之所以快,主要有以下几方面原因:
内存存储:Redis 将所有数据存储在内存中,这使得它能够快速地读写数据。与传统的磁盘存储相比,内存存储的访问速度更快。
单线程架构:Redis 是单线程的,这意味着 Redis 不需要进行上下文切换,也不需要考虑线程同步和加锁等问题,从而避免了这些常见的多线程问题所带来的开销。
异步非阻塞 I/O:Redis 使用了事件驱动机制,并采用了异步非阻塞 I/O 模型,这使得 Redis 能够处理大量的并发连接请求,提高了系统的吞吐量。
基于内存的操作:Redis 的所有操作都是基于内存的,这使得 Redis 能够在微秒级别完成大部分操作,从而提高了系统的响应速度
Redis的脑裂问题是指在Redis集群中,由于网络分区或其他原因,导致不同节点之间失去连接,从而导致同一份数据在不同节点上出现不一致的情况。
解决Redis的脑裂问题有以下几种方法:
使用Redis Sentinel来监控和自动故障转移。Sentinel可以在主节点出现故障时自动将从节点提升为新的主节点,并将客户端重定向到新的主节点。
使用Redis Cluster来分片和复制数据。如果一个节点失效,Cluster会重新分配槽位,并且客户端可以自动通过其他节点访问集群的其他部分。
配置Redis的持久化方式,如AOF或RDB,以确保在故障发生时可以快速恢复数据。
配置合适的超时时间,以避免网络分区过长导致误判节点状态,并定期检查集群健康状况。