Redis深度探险知识总结

1.数据结构

  • String:get/set,mget,incr,expire,setnx,setex
  • list: rpush/lpush,lpop/rpop,llen,lrange,ltrim
  • hash
  • set
  • hset
    高级数据结构
  • bitmaps
  • HyperLogLog
  • 布隆过滤器
  • GEO
  • PubSub
  • Stream

2. 分布式锁

并发保证数据原子性(操作不会被线程调度打断)
关键命令 setnx,del

死锁

触发条件:当del没有被调用
解决方案:

  1. setnx和expire可以一起执行(超时锁会过期,就释放了锁)
  2. 乐观锁(设置一个随机数)–>释放时校验随机数是否一致

3.延时队列

基于list数据结构(本质时linkedlist)

流程: 将操作放入list队列中,处理完成再获取消息

队列空了怎么办(陷入pop死循环)

  1. 线程睡一会(多个操作会导致反应过慢)
  2. 延迟队列(将请求放入延时队列,过一会再执行)
  3. 抛出异常,让用户等一会

4.限流

简单限流

使用zset的score值对时间戳进行排序
可以使用pipeline提高效率

漏斗限流

最常用的一种限流方式
Redis插件 Redis-Cell

解释:如漏斗一样,堵住会变满,放开就下流。漏嘴流水速率小于灌水的速率,漏斗会变满,需要暂停并腾空漏斗。

5.堵塞

这keys *堵塞

缺点

  1. 没有分页
  2. 时间复杂度为On,容易卡顿

SCAN

  1. 不会堵塞
  2. 可分页
  3. 提供匹配功能
  4. 有游标
  5. 结果会重复
  6. 结束游标值为0

遍历顺序:高位进位加法

定位大key(一般为hash结构)
命令: redis-cli -h 127.0.0.1 -p 7001 –bigkeys -i 0.1

6.IO模型

  1. 单线程
  2. 内存数据库
  3. 多路复用(读写事件多路处理)
  4. 非阻塞IO
    1. 套接字
    2. 指令队列(每个客户端套接字关联一个指令队列,顺序处理,先到先服务)
    3. 响应队列(每个客户端套接字关联一个响应队列,可以将结果返回,队列为空时弹出连接,证明客户端已经没有工作)
    4. 定时任务

7.RESP协议

  1. 字符串 +开头
  2. 多行字符串 $开头
  3. 整数 :: 开头
  4. 错误消息 – 开头
  5. 数组 * 开头

AOF持久化就是记录的是写操作 ,可进去查看

8.持久化

快照

原理:Redis单线程不仅需要负责线上请求还要负责IO操作,严重拖垮服务器性能,需要同时负责请求和IO操作,Redis使用COW(Copy on write)来实现
fork(多进程):
调用glib函数创建一个子进程负责IO操作,共享父进程内存中的代码段和数据段。父进程就负责请求和对内存的修改
为什么叫快照:
子进程看到的数据没有变化,所以叫快照,可以安心写入磁盘中

AOF原理

因为快照记录数据不完全
作用:只记录写操作,就可以重放数据到内存中

缺点:AOF日志越来越多,需要缩身
解决方案:提供bgrewriteaof指令 开辟了一个子进程将写操作序列化到新的AOF中,增量AOF会追加到新的AOF文件中

fsync:
问题:如果掉电导致宕机AOF没有来得及写入怎么办?
答案:提供fsync保证aof数据不丢失,但是很慢!
两种策略:1.永不fsync,不安全
2.fsync,生产环境一般不会使用

混合持久化

重启时,先加载rdb,再加载aof,提高效率

问题:为什么Redis只适合缓存
1.无法大量存储,不能保证数据安全
2.复杂数据不易存,不能存表关联关系
3.sfsnc使redis比mysql效率慢

8.管道

pipeline将多个指令操作押入管道中,客户端只请求一次到服务器中,提高效率,节省IO时间。指令越多效果越好。

压力测试 redis-benchmark
指令:redis-benchmark -t set -q

9.事务

为确保原子性(事务全部成功或全部失败)
指令:multi/exec/discard,watch/unwatch
Redis没有原子性,只能保证隔离性

经验:和pipeline一起使用压缩io操作

watch监控一个变量
经验:若监控变量一旦被修改那么事务就会失败

问题:为什么redis不支持回滚?
1.只检查语法错误
2.不需要支持回滚,目的是简单高效

10.小对象压缩

Redis有两种bit编译,一种是32bit,第二种是64bit。使用32bit可以少一半内存,Redis的内存使用不超过4G。

小对象压缩存储ziplist
ziplist是一个紧凑的字节数据结构,为防止对象过大,conf里的限制条件
hash-max…
list-max…
zset-max…
set-max…

内存回收机制
Redis中数据是保存在内存中的,内存是由多个页组成
1.Redis存储key是分布到各个页中
2.简单删除key是将删除,但其他key还在页中,所以内存小不了
3.执行flushdb和flushall所有key被干掉,内存释放。

内存分配算法
两种

  1. jemalloc(Redis使用,性能稍好)
  2. tcmalloc

指令:info memory

11.主从同步

CAP
C-Consistent 一致性
A-Availability 可用性
P-Partition tolerance 分区容忍性
特点:一致性和可用性两难全
通常Redis集群满足可用性,单机主从满足一致性(指令AOF)

Redis支持主从同步和从从同步
增量同步(没懂):
Redis同步的是指令流

快照同步(besave)
增加从节点
无盘复制
Wait指令

12.哨兵模型Sentinel

哨兵模型单机使用保证一致性

不能保证消息不会丢失,可以限制延迟过大

  1. min-slaves-to-write 1 至少一个从节点
  2. min-slaves-max-lag 10 10s没有收到就断开

13.Codis

是Go语言开发,使用Redis协议对外提供服务。
Codis是无状态的转发代理中间件,可动态增加Redis实例实现扩容需求

分片原理(类似hashmap)

将所有的key划分为1024个槽,先对客户端传过来的key做crc32计算hash值,再对1024取模,余数就是key对应的槽位。
当Redis扩容时,对槽位进行调整,是通过SLOTSSCAN指令遍历slot所有key,然后挨个迁移到新节点上

特点:
自动均衡:每个Redis的slots数量平衡
缺点:

  1. 不支持事务
  2. key值不宜过大
  3. 增加proxy层,性能有所下降
  4. 增加zk的代价

优点:

  1. 简单
  2. 易调试

数据同步

是通过ZooKeeper实现同步持久化槽位关系,这里可以体现ZooKeeper的数据同步功能

14.Cluster

特点:

  1. 去中心化
  2. 精细,slots为16364
  3. 定位快
  4. 官方提供

槽位定位算法

key值使用crc32算法得到hash值,再对16384取模获取具体槽位

跳转

如何找到槽位
若发到一个错误节点,这个节点将返回一个正确节点信息,再从定向到正确节点

迁移

提供redis-trib手动调整
状态为migrating(源节点)–>importing(目标节点)–>删除内容(源节点)
过程为同步,会阻塞到key被成功删除

若key数据小,migrating快,很大容易卡顿,影响集群效率

访问流程

  1. 访问若两个槽都存在部分key数据,客户端先访问旧节点,若存在旧节点里正常处理。若不存在就有两种可能,不存在或者新节点里。
  2. 旧节点不知道,会返回一个-ASK targetNodeAddr的重定向指令。
  3. 客户端收到后,先去目标节点执行一个asking指令,然后执行原先操作。(asking指令是告诉目标指令下条指令需要处理)
    结论是:影响效率,一个指令在迁移过程中需要3个ttl,正常需要一个ttl

容错

主从替换
cluster-require-full-coverage 允许部分节点故障
cluster-node-timeout 超时时进行主从切换
cluster-slave-validity-factor 超时宽松容错松弛系数,0为不抗拒网络抖动

投票机制
经过其他节点一起投票判断该节点是否下线,超过一半时就下线并主从替换

槽位感知和集群变更感知

15.Stream

5.0才出的数据结构,借鉴于kafka的设计
弥补Pub/Sub的缺点。

数据结构类似持久化得消息链表
分别是:

  1. 链表
  2. last_delivered_id(游标)
  3. 消费组
  4. 消息ID
  5. 消息内容

消费流程

Stream 提供了 xreadgroup 指令可以进行消费组的组内消费,需要提供消费组名称、消
费者名称和起始消息 ID。它同 xread 一样,也可以阻塞等待新消息。读到新消息后,对应
的消息 ID 就会进入消费者的 PEL(正在处理的消息) 结构里,客户端处理完毕后使用 xack
指令通知服务器,本条消息已经处理完毕,该消息 ID 就会从 PEL 中移除。

特点

  • 可持久化阻塞消费。
  • 通过ack保证消息的顺序性。
  • 可以控制消息的长度 PEL:保证消息至少消费一次,不会丢失

16.Info

通过强大的 Info 指令,你可以清晰地知道 Redis 内部一系列运行参数。

九大参数

 1、Server 服务器运行的环境参数
 2、Clients 客户端相关信息
 3、Memory 服务器运行内存统计数据
 4、Persistence 持久化信息
 5、Stats 通用统计数据
 6、Replication 主从复制相关信息
 7、CPU CPU 使用情况
 8、Cluster 集群信息
 9、KeySpace 键值对统计数量信息
# eg
# 获取所有信息
> info
# 获取内存相关信息
> info memory
# 获取复制相关信息
> info replication

17. 过期策略

过期集合

redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个
字典来删除到期的 key。

定时扫描策略

1、从过期字典中随机 20 个 key;
2、删除这 20 个 key 中已经过期的 key;
3、如果过期的 key 比率超过 1/4,那就重复步骤 1;

丛库过期策略

从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF
文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令来删除过期的
key。

LRU

  • noeviction 不会继续服务写请求 (DEL 请求可以继续服务),读请求可以继续进行。这样
    可以保证不会丢失数据,但是会让线上的业务不能持续进行。这是默认的淘汰策略。
  • volatile-lru 尝试淘汰设置了过期时间的 key,最少使用的 key 优先被淘汰。没有设置过 期时间的 key 不会被淘汰,这样可以保证需要持久化的数据不会突然丢失。
  • volatile-ttl 跟上面一样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
  • volatile-random 跟上面一样,不过淘汰的 key 是过期 key 集合中随机的 key。
  • allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不 只是过期的
    key 集合。这意味着没有设置过期时间的 key 也会被淘汰。
  • allkeys-random 跟上面一样,不过淘汰的策略是随机的 key。
  • volatile-xxx 策略只会针对带过期时间的 key 进行淘汰,allkeys-xxx 策略会对所有的 key
    进行淘汰。如果你只是拿 Redis 做缓存,那应该使用 allkeys-xxx,客户端写缓存时 不必携带过期时间。如果你还想同时使用Redis 的持久化功能,那就使用 volatile-xxx 策略,这样可以保留没有设置过期时间的 key,它们是永久的 key 不会被LRU 算法淘 汰。

懒惰删除

在 4.0 版本引入了 unlink 指令,它能对删除操作进行懒
处理,丢给后台线程来异步回收内存。flushdb 和 flushall 指令,用来清空数据库,这也是极其缓慢的操作。

1、slave-lazy-flush 从库接受完 rdb 文件后的 flush 操作
2、lazyfree-lazy-eviction 内存达到 maxmemory 时进行淘汰
3、lazyfree-lazy-expire key 过期删除
4、lazyfree-lazy-server-del rename 指令删除 destKey

18. 安全

  1. 指令安全
  2. 端口安全
  3. Lua安全
  4. SSL 代理

本文地址:https://blog.csdn.net/qq_43168682/article/details/110353124

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐