Redis入门
什么是Redis?
Redis
是一个开源的内存键值存储数据库,它可以用作数据库、缓存和消息中间件。Redis
支持多种数据结构,如字符串、哈希、列表、集合和有序集。它还提供了用于数据备份、恢复和复制的功能,使其成为许多应用程序的理想选择。
内存数据库的优缺点
内存数据库的优点和缺点
优点:
- 速度:内存数据库如
Redis
能够提供快速的读写能力,因为内存的访问速度远超过磁盘。 - 低延迟:数据存取的响应时间短,适合需要快速响应的应用。
- 灵活性:由于数据结构存储在内存中,
Redis
等内存数据库支持丰富的数据类型和操作。 - 简化的数据模型:键值存储方式简化了数据模型,便于开发和维护。
缺点:
- 成本:内存通常比磁盘更昂贵,大量的数据存储需要大量的内存,可能导致高成本。
- 数据持久性风险:如果没有合适的持久化策略,突然的系统崩溃可能导致数据丢失。
- 数据容量限制:由于依赖内存,数据的容量受到物理内存大小的限制。
安装Redis
1 | 获取redis最新版本 |
Redis命令
启动命令
1 | 启动服务端 |
KEY命令
命令 | 描述 |
---|---|
DEL | 用于删除 key |
DUMP | 序列化给定 key ,并返回被序列化的值 |
EXISTS | 检查给定 key 是否存在 |
EXPIRE | 为给定 key 设置过期时间 |
EXPIREAT | 用于为 key 设置过期时间,接受的时间参数是 UNIX 时间戳 |
PEXPIRE | 设置 key 的过期时间,以毫秒计 |
PEXPIREAT | 设置 key 过期时间的时间戳(unix timestamp),以毫秒计 |
KEYS | 查找所有符合给定模式的 key |
MOVE | 将当前数据库的 key 移动到给定的数据库中 |
PERSIST | 移除 key 的过期时间,key 将持久保持 |
PTTL | 以毫秒为单位返回 key 的剩余的过期时间 |
TTL | 以秒为单位,返回给定 key 的剩余生存时间( |
RANDOMKEY | 从当前数据库中随机返回一个 key |
RENAME | 修改 key 的名称 |
RENAMENX | 仅当 newkey 不存在时,将 key 改名为 newkey |
TYPE | 返回 key 所储存的值的类型 |
String字符串类型
Redis
的Strings
存储字节序列,包括文本、序列化对象和二进制数组。因此,字符串是最基本的Redis
数据类型。它们通常用于缓存,但它们支持额外的功能,让您也可以实现计数器并执行按位操作。
#获取和设置字符串
SET
存储一个字符串值。SETNX
仅当键不存在时才存储字符串值。用于实现锁。GET
检索字符串值。MGET
在单个操作中检索多个字符串值。
#管理计数器
INCRBY
以原子方式递增(并在传递负数时递减)存储在给定键处的计数器。- 浮点计数器存在另一个命令:
INCRBYFLOAT
。
List列表类型
Redis lists是字符串值的链表。Redis 列表经常用于:
- 实现堆栈和队列。
- 为后台工作系统构建队列管理。
基本命令
LPUSH
将一个新元素添加到列表的头部;RPUSH
添加到尾巴。LPOP
从列表的头部移除并返回一个元素;RPOP
做同样的事情,但来自列表的尾部。LLEN
返回列表的长度。LMOVE
原子地将元素从一个列表移动到另一个列表。LTRIM
将列表减少到指定的元素范围。
#阻塞命令
列表支持几个阻塞命令。例如:
BLPOP
从列表的头部删除并返回一个元素。如果列表为空,则命令会阻塞,直到元素可用或达到指定的超时。BLMOVE
原子地将元素从源列表移动到目标列表。如果源列表为空,则该命令将阻塞,直到有新元素可用。
Set集合类型
Redis Sets唯一字符串(成员)的无序集合。您可以使用 Redis 集高效地:
- 跟踪唯一项目(例如,跟踪访问给定博客文章的所有唯一 IP 地址)。
- 表示关系(例如,具有给定角色的所有用户的集合)。
- 执行常见的集合运算,例如交集、并集和差集。
基本命令
SADD
将新成员添加到集合中。SREM
从集合中删除指定的成员。SISMEMBER
测试一个字符串的集合成员资格。SINTER
返回两个或多个集合共有的成员集合(即交集)。SCARD
返回集合的大小(也称为基数)。
Hash哈希类型
Redis
Hash
是结构为字段值对集合的记录类型。您可以使用散列来表示基本对象并存储计数器分组等
基本命令
HSET
设置散列上一个或多个字段的值。HGET
返回给定字段的值。HMGET
返回一个或多个给定字段的值。HINCRBY
将给定字段的值增加提供的整数。
Zset有序集合类型
Redis 排序集是由相关分数排序的唯一字符串(成员)的集合。当多个字符串具有相同的分数时,这些字符串按字典顺序排列。排序集的一些用例包括:
- 排行榜。例如,您可以使用排序集轻松维护大型在线游戏中最高分的有序列表。
- 速率限制器。特别是,您可以使用排序集来构建滑动窗口速率限制器,以防止过多的 API 请求。
基本命令
ZADD
将新成员和相关分数添加到排序集中。如果成员已经存在,则更新分数。ZRANGE
返回在给定范围内排序的有序集合的成员。ZRANK
返回提供的成员的排名,假设排序是按升序排列的。ZREVRANK
返回提供的成员的排名,假设排序集是按降序排列的。
Geospatial地理位置详解
Redis Geospatial索引可让您存储坐标并搜索它们。此数据结构对于查找给定半径或边界框内的附近点很有用。
基本命令
GEOADD
将位置添加到给定的地理空间索引(请注意,使用此命令,经度位于纬度之前)。GEOSEARCH
返回具有给定半径或边界框的位置。
Hyperloglog基数统计
HyperLogLog
是一种估计集合基数的数据结构。作为一种概率数据结构,HyperLogLog
以完美的准确性换取了高效的空间利用。
Redis HyperLogLog
实现最多使用 12 KB,并提供 0.81% 的标准误差。
基本命令
PFADD
将项目添加到HyperLogLog
。PFCOUNT
返回集合中项目数的估计值。PFMERGE
将两个或多个HyperLogLog
合并为一个。
Bitmap位图
Redis Bitmaps
是字符串数据类型的扩展,可让您将字符串视为位向量。您还可以对一个或多个字符串执行按位运算。Bitmaps
用例的一些示例包括:
- 对于集合的成员对应于整数 0-N 的情况,有效的集合表示。
- 对象权限,每个位代表一个特定的权限,类似于文件系统存储权限的方式。
基本命令
SETBIT
将提供的偏移量设置为 0 或 1。GETBIT
返回给定偏移量的位值。BITOP
允许您对一个或多个字符串执行按位运算。
Redis持久化
什么是持久化?
将内存中的数据保存到硬盘或其他长期存储介质中,从而确保即使在系统崩溃、断电或其他突发事件中,数据也不会丢失。
RDB
什么是RDB?
RDB
持久化方式是Redis
将当前内存中的数据快照(snapshot)保存到硬盘的过程。换句话说,Redis
会创建一个代表某一时刻的数据集的磁盘文件。
RDB生成的流程图
触发机制
save
的规则满足的情况下,会自动触发rdb
规则- 执行
flushall
命令,也会触发rdb
规则 - 退出
redis
,也会触发rdb
规则
1 | redis 配置文件 save 指令设置: |
如何恢复rdb文件
只需要将
rdb
文件放在redis
启动目录即可,redis
启动的时候会自动检查dump.rdb
恢复其中的数据查看
dump.rdb
存在的位置1
config get dir
优点:
- 快速备份:
RDB
可以迅速为你创建一个数据的“快照”,这是一个备份文件,方便你存储或者迁移数据。 - 启动快:当
Redis
重新启动时,RDB
能帮助它更快速地加载数据,因为它直接读取一个完整的数据文件。 - 节省空间:与其他持久化方式相比,
RDB
的文件大小通常较小,因为它是经过压缩的。 - 适合大规模的数据恢复
- 对数据完整性要求不高
缺点:
- 需要一定的时间间隔进行操作。如果
redis
意外宕机,最后一次修改的数据就会丢失 fork
进程的时候,会占用一定的内存空间
AOF
什么是AOF
Redis
中的 AOF
持久化方式旨在持续地保存服务器上的所有修改操作。每当执行一个会改变数据的命令时,Redis
都会将该命令写入 AOF
文件中。这样,当 Redis
需要恢复数据时,只需执行 OF
文件中的命令就可以恢复到原来的状态。
AOF流程图
AOF
持久化的实现主要是以上三步:命令追加、文件写入、文件同步
- 命令追加: 将
redis
写操作命令追加到aof_buf
缓冲区 - 文件写入: 周期性地将
aof_buf
缓冲区的命令写入AOF
文件的内核缓冲区。 - 文件同步:根据配置同步策略,将
AOF
文件缓冲区的内容同步到磁盘。
什么是
AOF
重写
AOF
重写,可以看作是对AOF
文件进行的一次“精简”操作。它的目的是减少AOF
文件的大小,并去除那些冗余的、不再必要的命令,使得该文件只包含恢复当前数据集所需的最小命令集。
为什么需要
AOF
重写
节省磁盘空间:随着操作的积累,原始AOF
文件可能会变得非常大。通过重写,可以减少文件的大小。
加速恢复速度:一个更小、更简洁的AOF
文件意味着在Redis
重启时,数据的恢复过程会更快。
AOF
重写流程图
AOF
重写主要有以下四步:
redis
主进程fork
子进程来进行AOF
的重写,生成AOF
文件。- 在子进程进行
AOF
重写的同时,redis
主进程将新的写操作命令写入AOF
重写缓冲区 - 主进程将
AOF
重写缓冲区的内容写入到新的AOF
文件中 - 使用新的
AOF
文件替换旧的AOF
文件
AOF
文件错位了怎么办?
1 | # redis 提供了一个修复aof文件的工具 |
AOF
持久化的优缺点
优点:
不轻易丢数据:AOF
记录了所有的写操作,所以即使服务器突然断电,数据丢失的机会也很小。
易于理解:AOF
是一个文本文件,里面就是一系列的命令,你可以打开查看。
出问题也能救:如果AOF
文件最后有点损坏,Redis
也能够修复它,避免大量数据丢失。
缺点:
可能会慢一些:因为要不断写入操作,所以比RDB
要慢一点。
文件可能很大:AOF
会记录所有操作,所以文件可能迅速增大,占用更多空间。
恢复时间长:如果需要从 AOF
文件中恢复数据,由于文件可能很大,所以这个过程可能会比较慢。
1 | 修改配置文件redis.conf |
Redis发布订阅
发布/订阅模式是一种消息通信模式,其中消息的发送者称为发布者(Publisher),而消息的接收者称为订阅者(Subscriber)。发布者将消息发布到特定的频道(Channel),而订阅者则可以订阅一个或多个频道,以接收发布者发送的消息。
订阅端
1 | # 订阅一个频道 |
发布端
1 | # 发布者发布消息 |
使用场景
- 实时消息系统
- 实时聊天(频道当做聊天室)
- 订阅,关注系统
主从复制
什么是主从复制
主从复制,是指将一台Redis
服务器的数据,复制到其他的Redis
服务器。前者称为主节点(master/leader)
,后者称为从节点(slave/follower)
;数据的复制是单向的,只能由主节点到从节点。Master
以写为主,Slave
以读为主。
默认情况下,每台Redis
服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式,
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis
数据时应用连接主节点,读Redis
数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis
服务器的并发量。
4、高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis
高可用的基础。
一般来说,要将Redis
运用于工程项目中,只使用一台Redis
是万万不能的,原因如下:
1、从结构上,单个Redis
服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
2、从容量上,单个Redis
服务器内存容量有限,就算一台Redis
服务器内存容量为256G
,也不能将所有内存用作Redis
存储内存一般来说,单台Redis
最大使用内存不应该超过20G
。
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是”多读少写”。
一主二仆(从机只能读)
拷贝多份
redis.conf
配置文件,配置不同的端口使用不同的配置文件启动服务器
1 | # 查看服务器信息 |
1 | # 配置从机(临时) |
1 | # 配置从机 修改配置文件(永久) |
复制原理
Slave
启动成功连接到master
后会发送一个sync
同步命令Master
接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master
将传送整个数据文件到slave
,并完成一次完全同步。
全量复制:而slave
服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制 :Master
继续将新的所有收集到的修改命令依次传给slave
,完成同步
但是只要是重新连接master
,一次完全同步(全量复制)将被自动执行
哨兵模式
概述
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis
从2.8
开始正式提供了Sentinel
(哨兵)架构来解决这个问题。
谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊的模式,首先Redis
提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis
服务器响应,从而监控运行的多个Redis
实例。
哨兵的作用
通过发送命令,让
Redis
服务器返回监控其运行状态,包括主服务器和从服务器。当哨兵监测到
master
宕机,会自动将slave
切换成master
,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。然而一个哨兵进程对
Redis
服务器进行监控,可能会出现问题,为此,可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover
过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover
[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
配置哨兵配置文件
sentinel.conf
1
sentinel monitor master 127.0.0.1 6382 1
其中
master
为监控对象起的服务器名称,1
为至少有多少个哨兵同意迁移的数量。
设置为1
的话,只需要一个哨兵同意就可以切换,设置成2
则需要有两个哨兵都同意才进行切换(将从库转换为主库)启动哨兵
1
redis-sentinel /home/redis/sentinel.conf
延时复制
由于所有的写操作都是先在Master
上操作,然后同步更新到Slave
上,所以从Master
同步到Slave
机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave
机器数量的增加也会使这个问题更加严重。
故障恢复
优先级在redis.conf
中默认:slave-priority 100
,值越小优先级越高
哨兵模式的优缺点
优点
- 哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
- 主从可以切换,故障可以转移,系统的可用性就会更好
- 哨兵模式就是主从模式的升级,手动到自动,更加健壮!
缺点:
Redis
不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦!- 实现哨兵模式的配置其实是很麻烦的,里面有很多选择!
Redis缓存穿透和雪崩
缓存穿透(查不到)
缓存穿透的概念很简单,用户想要查询一个数据,发现redis
内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
缓存穿透的发生一般有这两种情况:
- 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
- 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;
解决缓存穿透
- 布隆滤波器
布隆滤波器是一种数据结构,对所有可能查询的参数以hash
形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。
- 缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
但是这种方法会存在两个问题:
- 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
- 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
缓存击穿(量太大,缓存过期)
缓存击穿,是指一个key
非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key
在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
当某个key
在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
解决缓存击穿
1.设置热点数据永不过期
- 加互斥锁
分布式锁:使用分布式锁,保证对于每个key
同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
缓存雪崩:是指在某一个时间段,缓存集中过期失效或者**Redis
故障宕机**!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
当大量缓存数据在同一时间过期(失效)或者 Redis
故障宕机时,这时大量的用户请求,就直接访问到数据库了,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而造成整个系统崩溃,这就是造成缓存雪崩的原因。
解决缓存雪崩
redis
高可用集群
这个思想的含义是,既然redis
有可能挂掉,那我多增设几台redis
,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)
- 限流降级
启动请求限流机制,只将少部分发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到Redis
恢复正常并把缓存预热完后,再解除请求限流的机制。
- 互斥锁
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key
只允许一个线程查询数据和写缓存,其他线程等待。
- 数据预热
数据加热的含义就是在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key
,设置不同的过期时间,让缓存失效的时间点尽量均匀。