0
点赞
收藏
分享

微信扫一扫

Redis 从入门到放弃

Spinach菠菜 2022-02-19 阅读 90

文章目录

1. Redis

2. 基本数据类型

2.1 String

2.2 list

2.3 set

2.4 zset

2.5 hash

3. 特殊数据类型

3.1 Geospatial

3.2 Bitmaps

在这里插入图片描述

3.3 HyperLogLog

4. 发布订阅

# 一个客户端订阅 channel1
subscribe channel1
# 另一个客户端向 channel1 发生 helloworld
publish channel1 helloworld

5. redis 事务

# 开启事务 相当于 mysql 的 begin
multi

# 执行事务 
exec

# 取消本次事务组队
discard 
  • 要执行 exec 命令事务中包含的所有指令才开始执行
  • 组队阶段报错,所有操作会被取消 (比如一个指令是 set k1 没有指定value值)
  • 执行阶段报错,就会出现部分成功,部分失败 (比如一个指令是 incr k1,但是 k1 的value 不是数值类型,就会出现执行阶段报错,组队阶段不报错)
  • 执行不保证原子性,会出现部分指令执行成功,部分失败的情况。而且失败之后也不会回滚

redis 乐观锁实现

# 再开启事务之前执行 watch,监视某个key的值是否发生变化,如果发生了变化接下来事务的执行exec就会失败
watch key名称

redis 不能实现悲观锁

6. 持久化

6.1 RDB(Redis Database)

开启和关闭 RDB
Redis默认开启的就是RDB模式

通过在配置文件 redis.conf 配置 save 例如 save 10 2 表示10秒内有 2个key 发生修改就进行持久化

如果不开启就将 save 注释,或者配置空字符串 save ""

备份指令

# 备份命令
# 会阻塞主进程,期间redis不能正常使用
save
# 不会阻塞主进程,开启fork 子进程
bgsave

bgsave 备份过程
开启一个 fork 进程,将当前 redis 的数据快照写入到一个临时文件中,然后再去替换原有的 dump.rdb 持久化文件,这个过程叫做“写时复制”。过程是再后台异步执行的,不阻塞redis的正常请求

备份恢复
只需要将备份生成的 dump.rdb 文件放到redis启动目录下,然后重启redis就会自动读取

优点:

  • 适合大规模数据复制
  • 速度较快

缺点:

  • 因为需要写入一份临时文件中,所以对磁盘空间有一定的要求
  • 如果没有达到设置的规则,比如 10 秒内只有一个key 发生了变化,此时不会进行持久化操作,如果发生宕机这一部分修改就丢失了

6.2 AOF (Append Only File)

开启方式
配置文件中设置 appendonly yes

刷盘频率
当进行写入操作时,会先记录到 aof buffer 中,然后再以一定的频率刷新到磁盘文件中,可以配置以下三种级别

appendfsync always:始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好

appendfsync everysec:每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。

appendfsync no:redis不主动进行同步,把同步时机交给操作系统。

备份恢复
只需要将备份生成的 appendonly.aof 文件放到redis启动目录下,然后重启redis就会自动读取

优点:

  • 数据完整性更好,不容易丢失数据

缺点:

  • 备份恢复速度慢
  • 如果是每次写入都刷盘到文件中,会有一定的性能压力
  • 文件占用空间更大

建议

RDB 和 AOF 两者都开启

7. 主从复制

从服务器第一次和主服务器建立连接时会发送 sync 同步指令,此时主服务器会进行一次 rdb 持久化操作。然后将 dump.rdb 文件传给从服务器,实现数据同步。之后就是主服务发生了写入操作再主动同步给从服务器

7.1 一主二仆

在这里插入图片描述

  • 从节点只能读不能写
  • 主机宕机,从机还是从机
  • 主机重启还是主机

7.2 薪火相传

  • 减轻主服务器的压力
  • 从机可以作为其他从机的主机
  • 如果 从1 宕机会导致 从2 无法同步数据

7.3 反客为主

  • 需要再从机上手动执行 slaveof no one

7.4 哨兵模式

最少需要3个哨兵,因为只有1个哨兵宕机了就完犊子了。一主二从起步就是 6 个节点

在这里插入图片描述

选举新的主服务器规则
依照如下步骤,如果一样就进行下一步

  1. 配置文件的 replica-priority
  2. 选择偏移量最小的,也就是同步主服务器数据最多的
  3. 选择 runid 最小的,redis启动时会生成

8. Redis 集群

例如我们按照业务部署了两台 Redis ,一台负责用户相关的数据记录,另一台负责商品相关数据的记录。我们想要存储的商品信息,可以是先发送到用户的 Redis 服务,然后再由用户 Redis 转发到商品 Redis。这就是无中心化

这样也实现了 Redis 的水平扩容。将不同业务的数据分散到不同的 Redis 服务器上。

8.1 slot

每一个节点负责处理一部分插槽,例如下图
在这里插入图片描述
集群中的每一个节点都可以作为集群的入口。比如在节点A上,添加一个key,但是经过计算
这个 key 存储的插槽属于节点 B 的范围。这时会自动重定向到对应的节点上。

注意:
如果一条指令同时添加多个 key 需要保证这些key经过计算是属于同一个节点的插槽区域的,否则无法成功。当然也有解决办法就是在key后加上组id,比如 key1{group1}

9. 常见问题

9.1 缓存穿透

解决方案

  1. 对空值进行缓存,缺点就是存储大量空值的 key 浪费空间,也可能造成数据不一致,数据库中有值了但是缓存中确是空
  2. 使用布隆过滤器
  3. 设置可访问名单 bitmap

9.2 缓存击穿

解决方案

  1. 临时调整过期时间
  2. 增加分布式锁
  3. 预先将热点数据写入缓存中,比如双11预先将一些热门秒杀商品加载到缓存中

9.3 缓存雪崩

解决方案

  1. 设置过期时间的时候,增加一个随机的值,让key的过期时间产生差异
  2. 记录缓存过期的时间,提前进行一个提醒,再开启一个线程去增加过期时间
  3. 使用分布式锁或者队列
  4. 构建多级缓存

10. 分布式锁

# 加锁(最好设置过期时间,否则如果忘记释放锁就会造成问题)
setnx 

# 释放锁(就是删除key)
del 

一般流程就是先加锁,如果加锁失败就再一定时间之后再重试

10.1 误删锁问题

情况一:
由于设置了过期时间,就可能出现线程A拿到锁之后,中途可能出现了卡顿导致在锁的超时时间内没有执行完操作,锁自动过期了。这时线程B拿到了锁,开始进行操作。但是在线程B操作的过程中,线程A又恢复了正常,然后A执行完释放了锁。注意问题来了,A的锁早就过期了,他现在释放的是B的锁,就造成了问题

解决
设置key时,value可以设置一个 uuid。释放锁时,比较uuid是否一致,一致才能删除,保障了自己只能释放自己的锁

情况二
经过情况一的优化之后依然存在问题,在线程A比较完uuid一致之后,因为比较uuid和释放锁并不是原子操作,所以可能出现,比较完uuid之后,还没删除锁。过期时间就到了,自动释放,这时线程B拿到了锁准备执行,然后A删除了锁就把线程B的锁给误删了

解决
使用luo脚本,使得比较uuid和删除的操作变成原子操作

举报

相关推荐

0 条评论