Redis简介与基础命令
Redis简介与命令
- Redis简介
- Redis下载与安装
- Redis图形化工具
- Redis数据存储类型
- 字符串(String)
- 列表(List)
- 集合(Set)
- 有序集合(Sorted Set)
- 哈希 (Hash)
- 地理空间索引(Geospatial Index)
- 流(Stream)
- 1. 创建流并添加消息
- 2. 查看流中的消息数量
- 3. 读取流中的消息
- 4. 创建消费者组
- 5. 消费者从消费者组中读取消息
- 6. 确认消息已处理
- 范围查询(HyperLogLog)
- 1. 使用 PFADD 命令添加元素
- 2. 使用 PFCOUNT 命令估算唯一元素数量
- 3. 合并多个 HyperLogLog
- Redis全局命令
- AI给的建议
- 常见理论性问题
- 什么是缓存穿透
- 什么是缓存雪崩
- Redis 单线程为什么还能这么快
- Redis 的过期策略有哪些
- Redis 在项目中的使用场景有哪些
- 如何使用 Redis 实现分布式锁
- Redis 有哪些高可用方案
- Redis 集群的原理是什么
- Redis 持久化方式有哪些
- RDB 和 AOF 各有什么优缺点
Redis简介
Redis(Remote Dictionary Server,远程字典服务)
一个开源的高性能数据键值对存储数据库。为什么高性能,很好理解,一般关系型数据库存储数据的地方都是磁盘,但属于非关系型数据库的Redis存储数据的地方是内存。内存与磁盘的性能差异可想而知。
Redis下载与安装
Redis虽然是个开源软件,但是后面商业化了,Redis7版本后就有社区版与企业版的区别了。
微软维护的适用于windows的Redis版本比较老了,只在3就截止了,有一个第三方维护的Redis版本在5,相对来说新一点。
第三方维护地址
微软维护地址
无论是msi文件方式安装还是直接解压安装,都是开箱即用,无需配置任何东西。
双击运行Redis服务端
双击运行Redis的客户端
客户端会连接到刚才的服务端,并通过输入命令来对Redis数据库里的数据进行增删改查。
Redis图形化工具
与其他数据库一样,肯定有人开发了图形化工具(不止一个)给Redis使用,不会一直用黑窗口的。
目前我用的是RESP,适合新手过渡学习期。
从图片可以看出Redis默认有16个数据库,如果不指定用的就是第一个。
Redis数据存储类型
Redis的特点就是键值对存储,这让我们省心了不少,他的key值永远是字符串类型,Value要记的类型也不多。这里的Value与其说是存储类型,不如说是存储结构。
字符串(String)
字符串是Redis中最基本的数据类型,可以存储文本或二进制数据。
特点:
存储内容:可以存储任意类型的字符串,包括文本、数字、二进制数据等。
最大长度:单个字符串的最大长度为512MB。
操作:支持多种操作,如设置值、获取值、追加内容、对字符串进行位图操作等。
常见命令
键值过期时间这个概念后期要多注意一下
存放键值:set key value [EX seconds] [PX milliseconds] [NX|XX]
值递增:incr key、incrby key increment、incrbyfloat key increment
值递减:decr [其余与值递增相同]
批量存放键值:mset key value [key value …]
获取部分字符:getrange key start end
追加内容:append key value
删除键值:del key [key ...]
练习案例
127.0.0.1:6379> set name zhansan
OK
127.0.0.1:6379> get name
"zhansan"
127.0.0.1:6379> set age 16
OK
127.0.0.1:6379> incr age
(integer) 17
127.0.0.1:6379> decr age
(integer) 16
127.0.0.1:6379> append age 12
(integer) 4
127.0.0.1:6379> append name g
(integer) 8
127.0.0.1:6379> get name
"zhansang"
127.0.0.1:6379> get age
"1612"
127.0.0.1:6379> incr age
(integer) 1613
127.0.0.1:6379> getrange name 1 3
"han"
127.0.0.1:6379> set address shanghai EX 10
OK
127.0.0.1:6379> get address
"shanghai"
127.0.0.1:6379> get address
(nil)
127.0.0.1:6379> incrby age 10
(integer) 1623
127.0.0.1:6379> incrbyfloat name 0.5
(error) ERR value is not a valid float
127.0.0.1:6379> incrbyfloat age 1.05
"1624.04999999999995453"
127.0.0.1:6379> mset 1 haha 2 xixi 3 hehe
OK
127.0.0.1:6379> get 1
"haha"
127.0.0.1:6379> get 2
"xixi"
127.0.0.1:6379> get 3
"hehe"
列表(List)
列表是一个有序的字符串集合,支持从头部或尾部插入和删除元素。
特点
存储结构:列表是一个双向链表,支持从头部或尾部快速插入和删除元素。
操作:可以对列表进行插入、删除、获取元素等操作。
阻塞操作:支持阻塞式操作,如BLPOP
和BRPOP
,可以在列表为空时阻塞等待。
常见命令
- 在列表左侧插入值:
lpush key value [value …]
- 在列表右侧插入值:
rpush key value [value …]
- 移除并获取列表左侧元素:
lpop key
- 获取列表指定范围内的元素:
lrange key start stop
- 获取列表长度:
llen key
- 获取列表指定索引位置的元素:
lindex key index
练习案例
127.0.0.1:6379> lpush mylist zhansan lisi wanwu laoliu
(integer) 4
127.0.0.1:6379> rpush mylist zhaoqi
(integer) 5
127.0.0.1:6379> lrange mylist 0 4
1) "laoliu"
2) "wanwu"
3) "lisi"
4) "zhansan"
5) "zhaoqi"
127.0.0.1:6379> lindex mylist 4
"zhaoqi"
127.0.0.1:6379> lindex mylist 0
"laoliu"
127.0.0.1:6379> llen mylist
(integer) 5
127.0.0.1:6379> rpop mylist
"zhaoqi"
127.0.0.1:6379> lpop mylist
"laoliu"
127.0.0.1:6379> llen mylist
(integer) 3
集合(Set)
集合是一个无序的字符串集合,支持集合操作,如并集、交集、差集等。
特点
存储结构:集合中的元素是唯一的,不支持重复元素。
操作:支持集合的基本操作,如添加、删除、检查元素是否存在,以及集合的并集、交集、差集等操作。
性能:集合操作的时间复杂度通常为O(1)。
常见命令
存储值:sadd key member [member …]
获取所有元素:smembers key
随机获取元素:srandmember key [count]
判断集合是否存在元素:sismember key member
获取集合元素个数:scard key
删除集合元素:srem key member [member …]
集合间的运算:SDIFF key [key …](差集)、SINTER key [key …](交集)、SUNION key [key …](并集)
127.0.0.1:6379> sadd set1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> sadd set1 1
(integer) 0
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> srandmember set1 3
1) "2"
2) "1"
3) "3"
127.0.0.1:6379> sismember set1 1
(integer) 1
127.0.0.1:6379> scard set1
(integer) 5
127.0.0.1:6379> srem set1 5
(integer) 1
127.0.0.1:6379> sadd set2 2 3 4 5 6
(integer) 5
127.0.0.1:6379> sdiff set1 set2
1) "1"
127.0.0.1:6379> sinter set1 set2
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> sunion set1 set2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
有序集合(Sorted Set)
有序集合是一个有序的字符串集合,每个元素都有一个分数(score),元素按分数排序。
特点
存储结构:有序集合中的元素是唯一的,每个元素都有一个分数,元素按分数从小到大排序。
操作:支持对有序集合的插入、删除、获取元素等操作,还可以根据分数范围获取元素。
性能:插入和删除操作的时间复杂度为O(log N),获取操作的时间复杂度为O(1)。
常见命令
- 向有序集合添加成员:
zadd key score member [score member …]
- 获取有序集合指定范围内的成员:
zrange key start stop [WITHSCORES]
- 从有序集合移除成员:
zrem key member [member …]
- 获取有序集合中成员的分数:
zscore key member
- 获取元素的排名(正序):
zrank key member
- 获取元素的排名(倒序):
zrevrank key member
练习案例
127.0.0.1:6379> zadd sortedset 10 zhansan 20 lisi 30 wanwu 40 laoliu
(integer) 4
127.0.0.1:6379> zrange sortedset 0 3 withscores
1) "zhansan"
2) "10"
3) "lisi"
4) "20"
5) "wanwu"
6) "30"
7) "laoliu"
8) "40"
127.0.0.1:6379> zscore sortedset zhansan
"10"
127.0.0.1:6379> zrank sortedset zhansan
(integer) 0
127.0.0.1:6379> zrevrank sortedset zhansan
(integer) 3
哈希 (Hash)
哈希是一种键值对集合,每个键对应一个值,值可以是字符串、数字等。
特点
存储结构:哈希内部是一个字段-值(field-value)对的集合。
内存效率:如果存储的键值对数量较少,Redis会使用更紧凑的存储方式来节省内存。
操作:可以对哈希中的单个字段进行操作,如设置、获取、删除字段等。
常见命令
- 设置哈希表中字段的值:
hset key field value
- 获取哈希表中字段的值:
hget key field
- 删除哈希表中的字段:
hdel key field [field …]
- 获取哈希表中的所有字段和值:
hgetall key
- 检查哈希表中是否存在指定字段:
hexists key field
- 获取哈希表中所有的字段名:
hkeys key
- 获取哈希表中所有的字段值:
hvals key
- 获取哈希表中字段的数量:
hlen key
练习案例
127.0.0.1:6379> hset hashset name zhansan
(integer) 1
127.0.0.1:6379> hset hashset age 14
(integer) 1
127.0.0.1:6379> hget hashset name
"zhansan"
127.0.0.1:6379> hget hashset age
"14"
127.0.0.1:6379> hset hashset address beijing
(integer) 1
127.0.0.1:6379> hget hashset address
"beijing"
127.0.0.1:6379> hgetall hashset
1) "name"
2) "zhansan"
3) "age"
4) "14"
5) "address"
6) "beijing"
127.0.0.1:6379> hdel hashset address
(integer) 1
127.0.0.1:6379> hgetall hashset
1) "name"
2) "zhansan"
3) "age"
4) "14"
127.0.0.1:6379> hexists hashset name
(integer) 1
127.0.0.1:6379> hhkeys hashset
(error) ERR unknown command `hhkeys`, with args beginning with: `hashset`,
127.0.0.1:6379> hkeys hashset
1) "name"
2) "age"
127.0.0.1:6379> hvals hashset
1) "zhansan"
2) "14"
127.0.0.1:6379> hlen hashset
(integer) 2
上述五种存储类型为最常用的类型,接下来将介绍一些Redis相对来说冷门的存储类型
地理空间索引(Geospatial Index)
Redis支持地理空间索引,可以存储地理位置信息并进行查询。
特点
存储结构:可以存储地理位置信息,如经纬度。
操作:支持计算两点之间的距离、查找附近的地理位置等操作。
常见命令
GEOADD key longitude latitude member
:将地理位置信息添加到集合中。GEODIST key member1 member2
:计算两个地理位置之间的距离。GEOPOS key member
:获取地理位置的经纬度。GEORADIUS key longitude latitude radius
:查找指定范围内的地理位置。
练习案例
127.0.0.1:6379> GEOADD cities 116.4074 39.9042 Beijing
(integer) 1
127.0.0.1:6379> GEOADD cities 121.4737 31.2304 Shanghai
(integer) 1
127.0.0.1:6379> GEOADD cities 113.2644 23.1291 Guangzhou
(integer) 1
127.0.0.1:6379> GEODIST cities Beijing Shanghai km
"1067.6112"
127.0.0.1:6379> GEOPOS cities Guangzhou
1) 1) "113.26440006494522095"
2) "23.12910118670300363"
127.0.0.1:6379> GEORADIUS cities 116.4074 39.9042 1100 km
1) "Beijing"
2) "Shanghai"
流(Stream)
流是Redis 5.0引入的一种新的数据类型,用于实现高可用的消息队列。
特点
存储结构:流是一种日志结构,支持消息的持久化和多消费者组。
操作:支持消息的追加、读取、删除等操作,支持多消费者组的并发处理。
性能:流的性能非常高,适合高并发场景。
常见命令
XADD key ID field value
:向流中追加消息。XREAD key ID
:读取流中的消息。XACK key group ID
:确认消息已处理。XGROUP CREATE key group ID
:创建消费者组。XREADGROUP group consumer key ID
:从消费者组中读取消息。
1. 创建流并添加消息
使用 XADD
命令向流中添加消息,该命令格式为 XADD key ID field value [field value ...]
,其中 key
是流的名称,ID
可以使用 *
让 Redis 自动生成唯一的消息 ID。
# 向名为 mystream 的流中添加一条消息,消息包含两个字段:name 和 age
XADD mystream * name "Alice" age 25
执行上述命令后,Redis 会返回一个自动生成的消息 ID,例如 1698890000000-0
。
2. 查看流中的消息数量
使用 XLEN
命令查看指定流中的消息数量,格式为 XLEN key
。
XLEN mystream
3. 读取流中的消息
可以使用 XRANGE
命令按范围读取流中的消息,格式为 XRANGE key start end [COUNT count]
。
# 读取 mystream 流中所有消息
XRANGE mystream - +
其中 -
表示最小 ID,+
表示最大 ID。如果想限制返回的消息数量,可以添加 COUNT
参数,例如:
# 读取 mystream 流中前两条消息
XRANGE mystream - + COUNT 2
4. 创建消费者组
使用 XGROUP CREATE
命令创建一个消费者组,格式为 XGROUP CREATE key groupname id [MKSTREAM]
。
# 在 mystream 流上创建一个名为 mygroup 的消费者组,从第一条消息开始消费
XGROUP CREATE mystream mygroup $ MKSTREAM
这里的 $
表示从流的最后一条消息之后开始消费,MKSTREAM
选项表示如果流不存在则自动创建。
5. 消费者从消费者组中读取消息
使用 XREADGROUP
命令让消费者从消费者组中读取消息,格式为 XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
。
# 消费者名为 consumer1 从 mygroup 消费者组中读取 mystream 流中的消息
XREADGROUP GROUP mygroup consumer1 COUNT 1 BLOCK 0 STREAMS mystream >
COUNT 1
表示每次读取一条消息,BLOCK 0
表示阻塞模式,直到有新消息到来,>
表示从尚未被消费过的消息开始读取。
6. 确认消息已处理
使用 XACK
命令确认消息已被处理,格式为 XACK key group ID [ID ...]
。
# 假设之前读取到的消息 ID 是 1698890000000-0,确认该消息已处理
XACK mystream mygroup 1698890000000-0
范围查询(HyperLogLog)
HyperLogLog是一种用于统计集合中唯一元素数量的算法,占用内存非常小。
特点
存储结构:HyperLogLog使用近似算法来统计集合中唯一元素的数量,占用内存非常小。
操作:支持对多个HyperLogLog进行合并和交集操作。
精度:统计结果的误差通常在2%以内。
常见命令
PFADD key element
:将元素添加到HyperLogLog中。PFCOUNT key
:获取HyperLogLog中唯一元素的数量。PFMERGE destkey sourcekey1 sourcekey2
:将多个HyperLogLog合并到一个新的HyperLogLog中。
1. 使用 PFADD 命令添加元素
PFADD
命令用于向 HyperLogLog 结构中添加元素。如果 HyperLogLog 结构不存在,会自动创建。
# 向名为 my_hll 的 HyperLogLog 中添加元素
PFADD my_hll apple banana cherry
上述命令将 apple
、banana
和 cherry
三个元素添加到名为 my_hll
的 HyperLogLog 结构中。命令执行成功后,Redis 会返回 1
表示至少有一个新元素被添加;如果没有新元素添加,则返回 0
。
2. 使用 PFCOUNT 命令估算唯一元素数量
PFCOUNT
命令用于估算 HyperLogLog 结构中唯一元素的数量。
# 估算 my_hll 中唯一元素的数量
PFCOUNT my_hll
执行该命令后,Redis 会返回一个近似的唯一元素数量值。在这个例子中,因为添加了三个不同的元素,返回值大概率是 3
。
3. 合并多个 HyperLogLog
使用 PFMERGE
命令可以将多个 HyperLogLog 合并成一个新的 HyperLogLog。
# 再创建一个名为 my_hll2 的 HyperLogLog 并添加元素
PFADD my_hll2 cherry date elderberry
# 将 my_hll 和 my_hll2 合并到新的 my_hll_merged 中
PFMERGE my_hll_merged my_hll my_hll2
# 估算合并后 my_hll_merged 中唯一元素的数量
PFCOUNT my_hll_merged
操作首先创建了另一个 HyperLogLog my_hll2
并添加元素,然后使用 PFMERGE
命令将 my_hll
和 my_hll2
合并到 my_hll_merged
中,最后使用 PFCOUNT
估算合并后的唯一元素数量。由于 my_hll
和 my_hll2
中有重复元素 cherry
,所以合并后估算的唯一元素数量会小于或等于两个 HyperLogLog 元素数量之和。
Redis全局命令
- 服务器信息
INFO [section]
:获取服务器信息和统计。
PING
:测试连接是否正常,返回PONG。
TIME
:返回当前服务器时间。 - 配置管理
CONFIG GET parameter
:获取配置参数的值。
CONFIG SET parameter value
:设置配置参数的值。
CONFIG REWRITE
:将当前配置写入配置文件。 - 数据库操作
FLUSHDB
:清空当前数据库。
FLUSHALL
:清空所有数据库。 - 键管理
KEYS pattern
:查找匹配的键(慎用,可能阻塞)。
SCAN cursor [MATCH pattern] [COUNT count]
:增量式迭代键。 - 持久化
SAVE
:同步保存数据到磁盘(阻塞)。
BGSAVE
:异步保存数据到磁盘。
LASTSAVE
:返回上次成功保存的时间戳。 - 事务
MULTI
:开始事务。
EXEC
:执行事务。
DISCARD
:取消事务。
WATCH key [key ...]
:监视键,事务前值被改则失败。 - 其他
redis-server或redis-server [配置文件路径]
启动 Redis
redis-cli -h [主机地址] -p [端口号]
:连接 Redis
redis-cli shutdown或kill [redis-pid]
: 停止 Redis:
ECHO message
:打印消息。
QUIT
:关闭当前客户端连接。
AI给的建议
借用一段当前比较火的AI给的建议
Redis这个瑞士军刀确实好用,但新手容易把它当锤子使,看啥都像钉子。以下是给迷茫新手的生存指南:
- 缓存不是包治百病
- 别把MySQL查不动的慢SQL都甩给Redis擦屁股,先优化查询索引再说
- 缓存穿透比不缓存更可怕,空值缓存+布隆过滤器才是防空气请求的正确姿势
- 别把缓存层当垃圾场,TTL都不设,最后OOM教你做人
- 会话存储是经典场景
- 别再往Cookie塞用户数据了,JWT+Redis才是分布式会话的体面选择
- 但别把整个用户对象都往Redis里怼,存个ID回数据库查才是正道
- 排行榜别再用SQL硬刚
- 看到"TOP 10""实时排名"需求时,ZSET就是你的救命稻草
- 但别魔怔到用ZSET实现复杂推荐算法,那是算法工程师的饭碗
- 分布式锁不是银弹
- 用SETNX抢锁时记得设过期时间,别让死锁把系统拖垮
- 高并发场景还是交给RedLock,但真要用明白它的争议点
- 消息队列的备胎人生
- 紧急情况下可以用List当简单队列顶包,但记得有Kafka/RabbitMQ这些正宫
- 别用Pub/Sub做金融级消息,丢消息的时候别哭
- 地理围栏别硬算
- GEO类型处理附近的人比你自己写haversine公式优雅100倍
- 但别指望它能替代专业GIS系统
- 别当持久化存储用
- 虽然可以AOF/RDB,但数据丢了别怪Redis,重要数据记得回写数据库
- 大Value(超过100KB)塞进Redis前先照镜子问自己配吗
新手常见迷惑行为:
- 在Redis里实现复杂业务逻辑,最后变成祖传屎山代码
- 把所有配置都塞进Redis,启动时疯狂调接口取配置
- 用几十个DB做数据隔离,最后运维查数据时骂娘
- 监控都不加,内存爆了还说Redis不稳定
正确姿势:把Redis当临时便签纸,别当保险柜。用前先问:这数据能丢吗?要持久化吗?需要事务吗?结构复杂吗?想清楚再动手,你的系统能多活两年。
常见理论性问题
什么是缓存穿透
咱打个比方来说明缓存穿透,你就把缓存想象成是超市门口的寄存处,数据库就好比超市里面的仓库。
正常流程
一般情况下,顾客(用户请求)来超市买东西,会先到寄存处(缓存)看看自己想要的东西在不在那儿放着。要是在,就直接拿走(从缓存获取数据返回);要是不在,就去超市仓库(数据库)找,找到之后把东西拿出来,同时在寄存处也放一份(把数据存入缓存),方便下次有人再要这个东西时,能直接从寄存处拿。
缓存穿透的情况
缓存穿透
可要是有这么一个调皮捣蛋的人,他每次来都问一些奇奇怪怪、根本不存在的东西,比如要 “火星特产”。那寄存处肯定没有,他就去仓库找,仓库里自然也没有。而且他还一直这么问,每次都要从寄存处问到仓库,这就导致大量这样无效的请求,不断地绕过寄存处(缓存)直接冲向仓库(数据库),给仓库管理员(数据库)带来很大的压力,甚至可能把仓库搞垮。
这在计算机里,就是缓存穿透。一些恶意攻击者或者程序的错误,会让大量请求去查询缓存和数据库里都不存在的数据,这些请求就像穿透了缓存一样,直接打到数据库上,数据库要处理大量这种无效请求,性能就会受到严重影响,甚至可能崩溃。
什么是缓存雪崩
正常状态
在正常情况下,超市门口的寄存处(缓存)存放着很多顾客常用物品的副本,大家来超市买东西,大部分时候能直接从寄存处拿到自己想要的东西,只有少数情况需要去仓库(数据库)找。这样仓库的压力就比较小,能比较轻松地应对顾客的需求。
缓存雪崩的情况
缓存雪崩
假如有这么一天,超市的寄存处出大问题了,比如说突然着火了,里面存放的所有东西都被烧没了;或者是寄存处的系统故障,所有物品信息都丢失了。这时候,顾客再来超市买东西,发现寄存处啥都没有,那就只能一股脑地都去仓库找。仓库一下子涌入了大量的顾客,原本只能应对少量顾客的仓库,根本处理不过来这么多人的需求,仓库管理员(数据库)就会忙得晕头转向,甚至有可能因为承受不住这么大的压力而崩溃。
在计算机领域里,缓存雪崩就是这样。在某一个时刻,缓存中大量的 key 同时过期失效,或者缓存服务器突然宕机。原本这些请求是可以从缓存中获取数据的,现在缓存没数据了,大量的请求就会直接冲向数据库,数据库瞬间要处理比平时多很多倍的请求,就像超市仓库突然涌入大量顾客一样。数据库的处理能力是有限的,当这些请求超出了数据库的承受能力,就会导致数据库性能急剧下降,甚至直接崩溃,整个系统也就无法正常工作了。
Redis 单线程为什么还能这么快
- 纯内存操作,数据存放在内存中,读写速度快。
- 单线程避免了多线程的上下文切换开销以及锁竞争问题。
- 使用了高效的数据结构,如哈希表、跳表等。
- 采用了 I/O 多路复用机制,能同时监听多个客户端连接。
Redis 的过期策略有哪些
- 定时过期:每个设置过期时间的 key 都创建一个定时器,到期就立即删除。这种方式对内存友好,但会占用大量 CPU 资源。
- 惰性过期:只有当访问一个 key 时,才检查该 key 是否过期,若过期则删除。这种方式对 CPU 友好,但可能会导致内存占用过高。
- 定期过期:每隔一段时间,随机检查一部分 key,删除其中过期的 key。Redis 采用的是惰性过期和定期过期相结合的方式。
Redis 在项目中的使用场景有哪些
- 缓存:减少数据库压力,提高系统响应速度。
- 会话缓存:存储用户会话信息。
- 排行榜:使用有序集合实现各种排行榜。
- 分布式锁:保证分布式系统中数据的一致性。
- 消息队列:利用列表实现简单的消息队列。
如何使用 Redis 实现分布式锁
- 可以使用 SETNX(SET if Not eXists)命令,当 key 不存在时,设置成功返回 1,表示获取到锁;若 key 已存在,设置失败返回 0,表示未获取到锁。
为了避免死锁,需要给锁设置过期时间。在 Redis 2.6.12 及以后版本,可以使用 SET key value NX PX timeout 命令,原子性地完成设置值和过期时间的操作。
Redis 有哪些高可用方案
- 主从复制:一个主节点(Master)负责写操作,多个从节点(Slave)负责读操作,实现读写分离。
- 哨兵模式(Sentinel):在主从复制的基础上,引入哨兵节点,用于监控主从节点的状态,当主节点出现故障时,自动进行故障转移。
- 集群模式(Cluster):将数据分散存储在多个节点上,实现数据的分片和高可用。
Redis 集群的原理是什么
- Redis 集群采用哈希槽(Hash Slot)来实现数据的分片,共有 16384 个哈希槽。
每个节点负责一部分哈希槽,当客户端请求时,根据 key 的哈希值计算出对应的哈希槽,然后将请求路由到负责该哈希槽的节点上。 - 集群中的节点通过 Gossip 协议进行通信,交换节点状态信息。
Redis 持久化方式有哪些
- RDB(Redis Database):定期将内存中的数据快照保存到磁盘上。优点是恢复速度快,适合做冷备;缺点是可能会丢失部分数据。
- AOF(Append Only File):将 Redis 的写操作以日志的形式追加到文件末尾。优点是数据安全性高,最多丢失 1 秒的数据;缺点是文件体积较大,恢复速度相对较慢。
RDB 和 AOF 各有什么优缺点
- RDB 优点:文件紧凑,恢复速度快;缺点:可能会丢失最后一次快照之后的数据,且在进行快照时会消耗较多的 CPU 资源。
- AOF 优点:数据安全性高,可通过重写机制压缩文件;缺点:文件体积大,恢复速度慢,写操作性能相对较低。