目录
- 1. Redis是什么?
- 2. Redis优缺点?
- 3. Redis为什么这么快?
- 4. 既然Redis那么快,为什么不用它做主数据库,只用它做缓存?
- 5. Redis的线程模型?
- 6. Redis 采用单线程为什么还这么快?
- 7. Redis 为什么6.0之前是单线程,而6.0之后引入了多线程?
- 8. Redis 持久化
- 9. Redis应用场景有哪些?
- 10. Memcached和Redis的区别?
- 11. 为什么要用Redis而不用map/guava做缓存?
- 12. Redis 数据类型有哪些?
- 13. Redis的内存用完了会怎样?
- 14. Redis如何做内存优化?
- 15. keys命令存在的问题?
- 16. Redis事务
- 17. WATCH命令
- 18. Redis事务支持隔离性吗?
- 19. Redis事务保证原子性吗,支持回滚吗?
- 20. Redis有哪些部署方案?
- 21. 过期键的删除策略?
- 22. 内存淘汰策略有哪些?
- 23. 如何保证缓存与数据库双写时的数据一致性?
- 24. 缓存雪崩、击穿、穿透?
- 25. Redis中pipeline的作用?
- 26. LUA脚本
- 27. Redis采用AP模式如何解决一致性问题
- 28. 分布式锁需要满足哪些特征?
- 28. Redis的原子性命令有哪些?
- 29. 热key 和 大key区别是什么,怎么解决?
1. Redis是什么?
Redis (Remote Dictionary Server )是一个使用 C 语言编写的,高性能非关系型的键值对数据库
。与传统数据库不同的是,Redis 的数据是存在内存
中的,所以读写速度非常快,被广泛应用于缓存方向。Redis可以将数据写入磁盘中,保证了数据的安全不丢失,而且Redis的操作是原子性
的。
2. Redis优缺点?
优点:
- a.基于内存操作,内存读写速度快。
- b. 支持多种数据类型,包括String、Hash、List、Set、ZSet等。
- c.支持持久化。Redis支持RDB和AOF两种持久化机制,持久化功能可以有效地避免数据丢失问题。
- d. 支持事务。Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
- e.支持主从复制。主节点会自动将数据同步到从节点,可以进行读写分离。
- f.Redis命令的处理是单线程的。Redis6.0引入了多线程,需要注意的是,多线程用于处理网络数据的读写和协议解析,Redis命令执行还是单线程的。
缺点:
- a.对结构化查询的支持比较差。
- b.数据库容量受到物理内存的限制,不适合用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的操作。
- c. Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
3. Redis为什么这么快?
- 基于内存:Redis是使用内存存储,没有磁盘IO上的开销。数据存在内存中,读写速度快。
- IO多路复用模型:Redis 采用 IO 多路复用技术。Redis 使用单线程来轮询描述符,将数据库的操作都转换成了事件,不在网络I/O上浪费过多的时间。
- 高效的数据结构:Redis每种数据类型底层都做了优化,目的就是为了追求更快的速度。
4. 既然Redis那么快,为什么不用它做主数据库,只用它做缓存?
虽然Redis非常快,但它也有一些局限性,不能完全替代主数据库。有以下原因:
- 事务处理:Redis只支持简单的事务处理,对于复杂的事务无能为力,比如跨多个键的事务处理。
- 数据持久化:Redis是内存数据库,数据存储在内存中,如果服务器崩溃或断电,数据可能丢失。虽然Redis提供了数据持久化机制,但有一些限制。
- 数据处理:Redis只支持一些简单的数据结构,比如字符串、列表、哈希表等。如果需要处理复杂的数据结构,比如关系型数据库中的表,那么Redis可能不是一个好的选择。
- 数据安全:Redis没有提供像主数据库那样的安全机制,比如用户认证、访问控制等等。
因此,虽然Redis非常快,但它还有一些限制,不能完全替代主数据库。所以,使用Redis作为缓存是一种很好的方式,可以提高应用程序的性能,并减少数据库的负载。
5. Redis的线程模型?
推荐参考(小林coding):Redis线程模型
Redis 单线程
指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」
这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。
但是,Redis 程序并不是单线程的,Redis 在启动的时候,是会启动后台线程(BIO)的:
Redis 6.0之前的版本会启动三个后台线程,作用于:关闭文件、AOF 刷盘、释放内存
Redis 6.0 版本之前的单线模式如下图:
Redis的线程模型是单线程的。这意味着在任何给定的时间点上,Redis只能处理一个请求。Redis使用事件驱动的方式来处理请求。其主要事件处理器是基于Reactor模式,通过使用I/O多路复用技术(如epoll或者kqueue)来监听多个socket。当有事件发生时,Redis会接收事件并进行处理。
6. Redis 采用单线程为什么还这么快?
推荐参考(小林coding):Redis 采用单线程为什么还这么快?
官方使用基准测试的结果是,单线程的 Redis 吞吐量可以达到 10W/每秒,如下图所示:
之所以 Redis 采用单线程(网络 I/O 和执行命令)那么快,有如下几个原因:
- 基于内存
- 避免多线程竞争(死锁、上下文切换)
- I/O 多路复用机制
7. Redis 为什么6.0之前是单线程,而6.0之后引入了多线程?
推荐参考(小林coding):Redis 为什么6.0之前是单线程?
6.0之前:
- CPU 并不是制约 Redis 性能表现的瓶颈所在,更多情况下是受到
内存大小
和网络I/O
的限制 - 使用了单线程后,可维护性高,而多线程模型增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。
6.0之后:
虽然 Redis 的主要工作(网络 I/O 和执行命令)一直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。
所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O 采用多线程
来处理。但是对于命令的执行依然使用单线程
来处理。
Redis 官方表示,Redis 6.0 版本引入的多线程 I/O 特性对性能提升至少是一倍以上。
因此, Redis 6.0 版本之后,Redis 在启动的时候,默认情况下会额外创建 6 个线程(这里的线程数不包括主线程)
:
- Redis-server : Redis的主线程,主要负责执行命令;
- bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;
- io_thd_1、io_thd_2、io_thd_3:三个 I/O 线程,io-threads 默认是 4 ,所以会启动 3(4-1)个 I/O 多线程,用来分担 Redis 网络 I/O 的压力。
8. Redis 持久化
推荐参考(小林coding):Redis 持久化 ,包括AOF写回流程、AOF写回策略、AOF重写机制
Redis 共有三种数据持久化的方式:
- AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
- RDB 快照:将某一时刻的内存所有数据,以二进制的方式写入磁盘;
- 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
Redis默认的持久化方式是 RDB快照
9. Redis应用场景有哪些?
- a. 缓存热点数据,缓解数据库的压力。
- b. 利用Redis原子性的自增操作,可以实现计数器的功能,比如统计用户点赞数、用户访问数等。
- c.分布式锁。在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用Redis自带的SETNX命令实现分布式锁,除此之外,还可以使用官方提供的RedLock分布式锁实现。
- d.简单的消息队列,可以使用Redis自身的发布/订阅模式或者List来实现简单的消息队列,实现异步操作。
- e. 限速器,可用于限制某个用户访问某个接口的频率,比如秒杀场景用于防止用户快速点击带来不必要的压力。
- f.好友关系,利用集合的一些命令,比如交集、并集、差集等,实现共同好友、共同爱好之类的功能。
- g.排行榜,利用zset数据结构的score的不同,可以实现一个排行榜的功能。
10. Memcached和Redis的区别?
- a. MemCached数据结构单一,仅用来缓存数据,而Redis支持多种数据类型。
- b.MemCached 不支持数据持久化,重启后数据会消失。Redis 支持数据持久化。
- c. Redis提供主从同步机制和cluster集群部署能力,能够提供高可用服务。Memcached没有提供原生的集群模式,需要依靠客户端实现往集群中分片写入数据。
- d. Redis的速度比Memcached快很多。
- e. Redis使用单线程的多路IO复用模型, Memcached使用多线程的非阻塞IO模型。 (Redis6.0引入了多线程IO,用来处理网络数据的读写和协议解析,但是命令的执行仍然是单线程)
- f. value 值大小不同: Redis 最大可以达到 512M; memcache只有 1mb.
11. 为什么要用Redis而不用map/guava做缓存?
- 使用自带的map或者guava实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着jvm的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。
- 使用redis 或 memcached之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。
12. Redis 数据类型有哪些?
基本数据类型:
- 1、 String:最常用的一种数据类型, String类型的值可以是字符串、数字或者二进制,但值最大不能超过512MB.
- 2、 Hash: Hash是一个键值对集合。
- 3、 Set:无序去重的集合。Set提供了交集、并集等方法,对于实现共同好友、共同关注等功能特别方便。
- 4、List:有序可重复的集合,底层是依赖双向链表实现的。
- 5、SortedSet:有序Set。内部维护了一个score的参数来实现。适用于排行榜和带权重的消息队列等场景。
特殊的数据类型:
- 1、Bitmap:
位图
,可以认为是一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在Bitmap中叫做偏移量。Bitmap的长度与集合中元素个数无关,而是与基数的上限有关。 - 2、 Hyperloglog:HyperLogLog是用来做
基数统计
的算法,其优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。典型的使用场景是统计独立访客。 - 3、 Geospatial :主要用于存储
地理位置
信息,并对存储的信息进行操作,适用场景如定位、附近的人等。
13. Redis的内存用完了会怎样?
默认情况下,如果达到设置的上限, Redis的写命令会返回错误信息(但是读命令还可以正常返回) 。
也可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容
14. Redis如何做内存优化?
可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes) ,散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。
15. keys命令存在的问题?
redis的单线程的。keys指令会导致线程阻塞一段时间,直到执行完毕,服务才能恢复。scan采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度是0(1) ,但是要真正实现keys的功能,需要执行多次scan。
scan的缺点:在scan的过程中如果有键的变化(增加、删除、修改),遍历过程可能会有以下问题:新增的键可能没有遍历到,遍历出了重复的键等情况,也就是说scan并不能保证完整的遍历出来所有的键。
16. Redis事务
事务的原理是将一个事务范围内的若干命令发送给Redis,然后再让Redis依次执行这些命令。Redis事务支持多条命令一起执行,但是不保证原子性,且没有回滚机制
。
事务的生命周期:
- a.使用MULTI开启一个事务
- b.在开启事务的时候,每次操作的命令将会被插入到一个队列中,同时这个命令并不会被真的执行
- c. EXEC命令进行提交事务
一个事务范围内某个命令出错不会影响其他命令的执行,不保证原子性
:
17. WATCH命令
WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行(类似于乐观锁)。执行EXEC命令之后,就会自动取消监控。
比如上面的代码中:
- a.
watch name
开启了对name
这个 key 的监控 - b. 修改
name
的值 - c. 开启事务a
- d.在事务a中设置了
name
和gender
的值 - e.使用
EXEC
命令进提交事务 - f. 使用命令
get gender
发现不存在,即事务a没有执行
使用 UNWATCH
可以取消 WATCH
命令对 key的监控,所有监控锁将会被取消。
18. Redis事务支持隔离性吗?
Redis 执行命令时单线程
的,并且它保证在执行事务时,不会对事务进行中断
,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的
。
19. Redis事务保证原子性吗,支持回滚吗?
Redis单条命令是原子性执行的,但事务不保证原子性,且没有回滚
。事务中任意命令执行失败,其余的命令仍会被执行。
20. Redis有哪些部署方案?
- 单机版:单机部署,单机Redis能够承载的QPS大概就在上万到几万不等。这种部署方式很少使用,存在的问题:内存容量有限处理能力有限无法高可用。
- 主从模式:一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支撑读高并发。master节点挂掉后,需要手动指定新的master,可用性不高,基本不用。
- 哨兵模式:主从复制存在不能自动故障转移、达不到高可用的问题。哨兵模式解决了这些问题。通过哨兵机制可以自动切换主从节点.master 节点挂掉后,哨兵进程会主动选举新的 master,可用性高,但是每个节点存储的数据是一样的,浪费内存空间。数据量不是很多,集群规模不是很大,需要自动容错容灾的时候使用
- Redis cluster(集群模式):服务端分片技术, 3.0版本开始正式提供.Redis Cluster并没有使用一致性hash,而是采用slot(槽)的概念,一共分成16384个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。主要是针对海量数据+高并发+高可用的场景,如果是海量数据,如果你的数据量很大,那么建议就用Redis cluster,所有主节点的容量总和就是Redis cluster可缓存的数据容量。
哈希分区算法有哪些?
-
节点取余分区:
使用特定的数据,如Redis的键或用户ID,对节点数量N取余: hash (key) % N计算出哈希值,用来决定数据映射到哪一个节点上。
优点是简单性。扩容时通常采用翻倍扩容,避免数据映射全部被打乱导致全量迁移的情况。 -
一致性哈希分区:
为系统中每个节点分配一个token,范围一般在0~232,这些token构成一个哈希环。数据读写执行节点查找操作时,先根据key计算hash值,然后顺时针找到第一个大于等于该哈希值的token节点。
这种方式相比节点取余最大的好处在于加入和删除节点只影响哈希环中相邻的节点,对其他节点无影响。 -
虚拟槽分区:
所有的键根据哈希函数映射到0~16383整数槽内,计算公式: slot=CRC16 (key)
&16383。每一个节点负责维护一部分槽以及槽所映射的键值数据。Redis Cluser采用虚拟槽分区算法。
21. 过期键的删除策略?
1、被动删除。在访问key时,如果发现key已经过期,那么会将key删除。
2、主动删除。定时清理key,每次清理会依次遍历所有DB,从db随机取出20个key,如果过期就删除,如果其中有5个key过期,那么就继续对这个db进行清理,否则开始清理下一个db。
3、内存不够时清理。Redis有最大内存的限制,通过maxmemory参数可以设置最大内存,当使用的内存超过了设置的最大内存,就要进行内存释放,在进行内存释放的时候,会按照配置的淘汰策略清理内存。
22. 内存淘汰策略有哪些?
当Redis的内存超过最大允许的内存之后,Redis会触发内存淘汰策略,删除一些不常用的数据,以保证Redis服务器正常运行。
Redis v4.0前提供6种数据淘汰策略:
volatile-lru
: LRU (Least Recently Used),最近最少使用。利用LRU算法移除设置了过期时间的key(时间维度)allkeys-lru
:当内存不足以容纳新写入数据时,从数据集中移除最近最少使用的keyvolatile-ttl
:从已设置过期时间的数据集中挑选将要过期的数据淘汰volatile-random
:从已设置过期时间的数据集中任意选择数据淘汰allkeys-random
:从数据集中任意选择数据淘汰no-eviction
:禁止删除数据,当内存不足以容纳新写入数据时,新写入操作会报错
Redis v4.0后增加以下两种:
volatile-Ifu
: LFU(Least Frequently Used),最不常用,从已设置过期时间的数据集中挑选最不经常使用的数据淘汰(频次维度)。allkeys-lfu
:当内存不足以容纳新写入数据时,从数据集中移除最不经常使用的key.
内存淘汰策略可以通过配置文件来修改,相应的配置项是maxmemory-policy
,默认配置是no-eviction
。
23. 如何保证缓存与数据库双写时的数据一致性?
推荐参考(小林coding):数据库和缓存如何保证一致性
1. 先删除緩存再更新数据库
进行更新操作时,先删除缓存,然后更新数据库,后续的请求再次读取时,会从数据库读取后再将新数据更新到缓存。
存在的问题:删除缓存数据之后,更新数据库完成之前,这个时间段内如果有新的读请求过来,就会从数据库读取旧数据重新写到缓存中,再次造成不一致,并且后续读的都是旧数据。
解决方案:延迟双删
。先删除缓存再更新数据库,睡眠一段时间再删除缓存。能尽量保持数据一致性,极端情况下依然也会出现缓存不一致的现象。
2. 先更新数据库再删除缓存
进行更新操作时,先更新MySQL,成功之后,删除缓存,后续读取请求时再将新数据回写缓存。
存在的问题:
- 更新MySQL和删除缓存这段时间内,请求读取的还是缓存的旧数据,不过等数据库更新完成,就会恢复一致,影响相对比较小。而且更新缓存速度较快。
- 事务A查询缓存不存在,然后查询数据库值为10,在还未写入缓存时。事务B更新数据为11,并清空缓存。事务A写入缓存数据为10,这时写入的是旧数据,而数据库存的数据是11。
解决方案:
- 在更新缓存前先加个
分布式锁
,保证同一时间只运行一个请求更新缓存,就会不会产生并发问题了,当然引入了锁后,对于写入的性能就会带来影响。 - 在更新完缓存时,给缓存加上较短的
过期时间
,这样即时出现缓存不一致的情况,缓存的数据也会很快过期,对业务还是能接受的。
3. 异步更新缓存
数据库的更新操作完成后不直接操作缓存,而是把这个操作命令封装成消息扔到消息队列中,然后由Redis自己去消费更新数据,消息队列可以保证数据操作顺序一致性,确保缓存系统的数据正常。
以上几个方案都不完美,需要根据业务需求,评估哪种方案影响较小,然后选择相应的方案。通常可以使用第二种方案。
24. 缓存雪崩、击穿、穿透?
推荐参考(小林coding):什么是缓存雪崩、击穿、穿透?
1. 缓存雪崩
通常我们为了保证缓存中的数据与数据库中的数据一致性,会给 Redis 里的数据设置过期时间,当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里,这样后续请求都可以直接命中缓存。
那么,当大量缓存数据在同一时间过期(失效)
或者 Redis 故障宕机
时,如果此时有大量的用户请求
,都无法在 Redis 中处理,于是全部请求都直接访问数据库
,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
解决方案:
- 均匀设置过期时间:如果要给缓存数据设置过期时间,应该避免将大量的数据设置成同一个过期时间。我们可以在对缓存数据设置过期时间时,给这些数据的过期时间
加上一个随机数
,这样就保证数据不会在同一时间过期。 - 加锁:当业务线程在处理用户请求时,如果发现访问的数据不在 Redis 里,
就加个互斥锁,保证同一时间内只有一个请求来构建缓存(从数据库读取数据,再将数据更新到 Redis 里)
,当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
Redis 故障宕机
解决方案:服务熔断或请求限流机制、构建 Redis 缓存高可靠集群;
2. 缓存击穿
我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据。
如果缓存中的某个热点数据过期了,此时大量
的请求访问了该热点数据
,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
可以发现缓存击穿跟缓存雪崩很相似,你可以认为缓存击穿是缓存雪崩的一个子集。
应对缓存击穿可以采取前面说到两种方案:
- 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
- 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;
3. 缓存穿透
当发生缓存雪崩或击穿时,数据库中还是保存了应用要访问的数据,一旦缓存恢复相对应的数据,就可以减轻数据库的压力,而缓存穿透就不一样了。
当用户访问的数据,既不在缓存中,也不在数据库中
,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据。那么当有大量这样的请求到来时,数据库的压力骤增就可能宕机,这就是缓存穿透
的问题。
缓存穿透的发生一般有这两种情况:
- 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
- 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;
应对缓存穿透的方案,常见的方案有三种。
- 第一种方案,非法请求的限制;
- 第二种方案,缓存空值或者默认值;
- 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在;
25. Redis中pipeline的作用?
26. LUA脚本
27. Redis采用AP模式如何解决一致性问题
在分布式系统中,AP(Availability and Partition Tolerance)和CP(Consistency and Partition Tolerance)是指CAP定理的两个方面。CAP定理指出,在一个分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)三者不可兼得,最多只能同时满足其中的两个。
- AP(Availability and Partition Tolerance):在面临网络分区的情况下,系统仍然能够保证可用性。这意味着系统可以继续响应请求,即使无法保证所有节点之间的数据一致性。这种设计使得系统能够在部分故障的情况下继续提供服务。比如允许访问到旧数据。
- CP(Consistency and Partition Tolerance):在面临网络分区的情况下,系统能够保证数据的一致性。这意味着系统可以保证所有节点之间的数据是一致的,但在出现网络分区的情况下可能会导致部分节点的不可用。
在Redis中,由于其分布式特性,在设计上更偏向于AP
,即在面临网络分区时更注重保证可用性。
可以通过一些其他的方式来保证数据的一致性,比如用消息队列MQ。
Rocket MQ当中是有一个延迟队列
,社区版不支持随意定义那个延迟时间的,但是它商业版
是可以定义随意延迟的时间,比如说把这些会过期的数据,我都放在这个Rocket MQ 里面,那么一旦它到那个延迟的消息点上面了,那么它就会被投递到我的 consumer 当中,那我把这一批数据去同步到我的那个数据库里面去
28. 分布式锁需要满足哪些特征?
可重入性
- 有一个
标识位
,不能把别人的锁给释放了 超时时间
满足CP
,满足一致性,不能访问到另一个节点发现这个锁不存在
28. Redis的原子性命令有哪些?
SET:设置指定 key 的值。
SETNX:如果指定的键不存在,则设置键的值为指定值。该操作是原子性的,只在键不存在时执行。
GETSET:设置指定 key 的值并返回其旧值。
INCR:将 key 中储存的数字值增一。
DECR:将 key 中储存的数字值减一。
HSET:在存储于 key 的哈希中设置字段的字符串值。
HINCRBY:为哈希 key 中的字段值加上指定增量值。
LPUSH:将一个或多个值插入到列表头部。
29. 热key 和 大key区别是什么,怎么解决?
在 Redis 中,热key和大key是两种不同的性能问题:
- 热key:指的是被频繁访问的特定键,由于读写频率过高,可能导致单个键成为瓶颈,影响整体性能。
- 大key:指的是单个键存储的内容过大,可能导致内存碎片、网络传输等问题,从而影响 Redis 的性能。
解决这些问题可以采取以下措施:
对于热key问题:
- 通过数据分片(sharding)将热点数据均匀分散到多个 Redis 实例上,减少单个实例的负载。
- 使用主从复制(replication)或者集群模式来分担读取请求,减轻热key的压力。
- 使用缓存淘汰策略,定期清理不常用的热key,让资源得到更合理的分配。
对于大key问题:
- 对于大key,可以考虑对其进行拆分,将大的键值对拆分成多个键值对,或者使用 Redis 的数据结构来分解大key。
- 使用合适的数据结构,例如使用列表(List)或集合(Set)来存储大量数据,避免单个键值对的大小过大。
- 定期清理大key,以释放内存空间,或者使用 Redis 的过期键(TTL)功能,通过设置键的过期时间来定期清理过大的键。