Redis入门
Mzy 金丹

Redis入门

什么是Redis?

Redis是一个开源的内存键值存储数据库,它可以用作数据库、缓存和消息中间件。Redis支持多种数据结构,如字符串、哈希、列表、集合和有序集。它还提供了用于数据备份、恢复和复制的功能,使其成为许多应用程序的理想选择。

内存数据库的优缺点

内存数据库的优点和缺点

优点:

  • 速度:内存数据库如Redis能够提供快速的读写能力,因为内存的访问速度远超过磁盘。
  • 低延迟:数据存取的响应时间短,适合需要快速响应的应用。
  • 灵活性:由于数据结构存储在内存中,Redis等内存数据库支持丰富的数据类型和操作。
  • 简化的数据模型:键值存储方式简化了数据模型,便于开发和维护。

缺点:

  • 成本:内存通常比磁盘更昂贵,大量的数据存储需要大量的内存,可能导致高成本。
  • 数据持久性风险:如果没有合适的持久化策略,突然的系统崩溃可能导致数据丢失。
  • 数据容量限制:由于依赖内存,数据的容量受到物理内存大小的限制。

安装Redis

1
2
3
4
5
6
7
8
9
10
11
12
# 获取redis最新版本
wget http://download.redis.io/releases/redis-6.2.6.tar.gz
# 解压
tar -zxvf redis-6.2.6.tar.gz
# 编译
cd redis-6.2.6/
make
# 安装 指定安装的根目录
cd src
make install PREFIX=/usr/local/redis
# 测试
redis-server --version

Redis命令

启动命令

1
2
3
4
5
6
# 启动服务端
redis-server
# 启动客户端(本地)
redis-cli
# 远程连接服务端(-p 6379)
redis-cli -h host -p port -a passwd

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字符串类型

RedisStrings存储字节序列,包括文本、序列化对象和二进制数组。因此,字符串是最基本的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生成的流程图

preview

触发机制

  1. save的规则满足的情况下,会自动触发rdb规则
  2. 执行flushall命令,也会触发rdb规则
  3. 退出redis,也会触发rdb规则
1
2
3
4
redis 配置文件 save 指令设置: 
save 3600 1 # 3600秒内如果超过1个key被修改则生成 RDB
save 300 100 # 300秒内如果超过100个key被修改则生成 RDB
save 60 10000 # 60秒内如果超过10000个key被修改则生成 RDB

如何恢复rdb文件

  1. 只需要将rdb文件放在redis启动目录即可,redis启动的时候会自动检查dump.rdb恢复其中的数据

  2. 查看dump.rdb存在的位置

    1
    config get dir

优点:

  1. 快速备份RDB可以迅速为你创建一个数据的“快照”,这是一个备份文件,方便你存储或者迁移数据。
  2. 启动快:当Redis重新启动时,RDB能帮助它更快速地加载数据,因为它直接读取一个完整的数据文件。
  3. 节省空间:与其他持久化方式相比,RDB的文件大小通常较小,因为它是经过压缩的。
  4. 适合大规模的数据恢复
  5. 对数据完整性要求不高

缺点:

  1. 需要一定的时间间隔进行操作。如果redis意外宕机,最后一次修改的数据就会丢失
  2. fork进程的时候,会占用一定的内存空间

AOF

什么是AOF

Redis中的 AOF 持久化方式旨在持续地保存服务器上的所有修改操作。每当执行一个会改变数据的命令时,Redis 都会将该命令写入 AOF 文件中。这样,当 Redis需要恢复数据时,只需执行 OF 文件中的命令就可以恢复到原来的状态。

AOF流程图

img

AOF 持久化的实现主要是以上三步:命令追加、文件写入、文件同步

  • 命令追加: 将 redis 写操作命令追加到 aof_buf 缓冲区
  • 文件写入: 周期性地将 aof_buf 缓冲区的命令写入 AOF 文件的内核缓冲区。
  • 文件同步:根据配置同步策略,将 AOF 文件缓冲区的内容同步到磁盘。

什么是AOF重写

AOF 重写,可以看作是对AOF文件进行的一次“精简”操作。它的目的是减少AOF文件的大小,并去除那些冗余的、不再必要的命令,使得该文件只包含恢复当前数据集所需的最小命令集。

为什么需要AOF重写

节省磁盘空间:随着操作的积累,原始AOF文件可能会变得非常大。通过重写,可以减少文件的大小。

加速恢复速度:一个更小、更简洁的AOF文件意味着在Redis重启时,数据的恢复过程会更快。

AOF重写流程图

img

AOF 重写主要有以下四步:

  • redis 主进程 fork 子进程来进行 AOF 的重写,生成 AOF 文件。
  • 在子进程进行 AOF 重写的同时,redis 主进程将新的写操作命令写入 AOF重写缓冲区
  • 主进程将 AOF 重写缓冲区的内容写入到新的 AOF 文件中
  • 使用新的 AOF 文件替换旧的 AOF 文件

AOF文件错位了怎么办?

1
2
# redis 提供了一个修复aof文件的工具
redis-check-aof --fix appendonly.aof

AOF持久化的优缺点

优点

不轻易丢数据AOF记录了所有的写操作,所以即使服务器突然断电,数据丢失的机会也很小。

易于理解AOF是一个文本文件,里面就是一系列的命令,你可以打开查看。

出问题也能救:如果AOF文件最后有点损坏,Redis也能够修复它,避免大量数据丢失。

缺点

可能会慢一些:因为要不断写入操作,所以比RDB要慢一点。

文件可能很大AOF会记录所有操作,所以文件可能迅速增大,占用更多空间。

恢复时间长:如果需要从 AOF文件中恢复数据,由于文件可能很大,所以这个过程可能会比较慢。

1
2
3
4
5
# 修改配置文件redis.conf
appendonly yes
appendfilename "appendonly.aof"
# 设置文件存储路径
dir

Redis发布订阅

发布/订阅模式是一种消息通信模式,其中消息的发送者称为发布者(Publisher),而消息的接收者称为订阅者(Subscriber)。发布者将消息发布到特定的频道(Channel),而订阅者则可以订阅一个或多个频道,以接收发布者发送的消息。

image-20240521155708527

订阅端

1
2
3
4
5
6
# 订阅一个频道
SUBSCRIBE 频道
# 退订
UNSUBSCRIBE 频道
# 列出当前活跃的频道
PUBSUB CHANNELS

发布端

1
2
# 发布者发布消息
PUBLISH 频道 消息

使用场景

  1. 实时消息系统
  2. 实时聊天(频道当做聊天室)
  3. 订阅,关注系统

主从复制

什么是主从复制

主从复制,是指将一台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
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是”多读少写”。

一主二仆(从机只能读)

  1. 拷贝多份redis.conf配置文件,配置不同的端口

  2. 使用不同的配置文件启动服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看服务器信息
info replication

# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=140,lag=0
slave1:ip=127.0.0.1,port=6382,state=online,offset=140,lag=1
master_failover_state:no-failover
master_replid:18528cddafdd479f391e69679d5224e878387823
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:140
1
2
# 配置从机(临时)
SLAVEOF 127.0.0.1 6380
1
2
# 配置从机  修改配置文件(永久)
replication IP PORT

复制原理

Slave启动成功连接到master后会发送一个sync同步命令Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

增量复制 :Master 继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

哨兵模式

概述

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis2.8开始正式提供了Sentinel(哨兵)架构来解决这个问题。
谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例

image-20240521185210946

哨兵的作用

  • 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。

  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

    然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

image-20240521185533553

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线

  1. 配置哨兵配置文件sentinel.conf

    1
    sentinel monitor master 127.0.0.1 6382 1

    其中master为监控对象起的服务器名称,1至少有多少个哨兵同意迁移的数量。
    设置为1的话,只需要一个哨兵同意就可以切换,设置成2则需要有两个哨兵都同意才进行切换(将从库转换为主库)

  2. 启动哨兵

    1
    redis-sentinel /home/redis/sentinel.conf

延时复制

由于所有的写操作都是先在Master上操作,然后同步更新到Slave,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

故障恢复

image.png

优先级在redis.conf中默认:slave-priority 100,值越小优先级越高

哨兵模式的优缺点

优点

  1. 哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
  2. 主从可以切换,故障可以转移,系统的可用性就会更好
  3. 哨兵模式就是主从模式的升级,手动到自动,更加健壮!

缺点:

  1. Redis不好在线扩容的,集群容量一旦到达上限,在线扩容就十分麻烦!
  2. 实现哨兵模式的配置其实是很麻烦的,里面有很多选择!

Redis缓存穿透和雪崩

缓存穿透(查不到)

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

img

缓存穿透的发生一般有这两种情况:

  • 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
  • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;

解决缓存穿透

  1. 布隆滤波器

布隆滤波器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。

image-20240521193744409

  1. 缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

image-20240521193932036

但是这种方法会存在两个问题:

  1. 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
  2. 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

缓存击穿(量太大,缓存过期)

缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。

img

解决缓存击穿

1.设置热点数据永不过期

  1. 加互斥锁

分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

缓存雪崩

缓存雪崩:是指在某一个时间段,缓存集中过期失效或者**Redis 故障宕机**!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

img

当大量缓存数据在同一时间过期(失效)或者 Redis故障宕机时,这时大量的用户请求,就直接访问到数据库了,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而造成整个系统崩溃,这就是造成缓存雪崩的原因。

img

解决缓存雪崩

  1. redis高可用集群

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)

  1. 限流降级

启动请求限流机制,只将少部分发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到Redis恢复正常并把缓存预热完后,再解除请求限流的机制。

  1. 互斥锁

这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

  1. 数据预热

数据加热的含义就是在正式部署之前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

img

Powered by Hexo & Theme Keep
Unique Visitor Page View