pull/1/head
595208882@qq.com 3 years ago
parent 572185a9cc
commit 1694f1dd34

@ -117,6 +117,47 @@ org.springframework.boot.env.YamlPropertySourceLoader
## 线程模型
Redis内部使用文件事件处理器`File Event Handler`这个文件事件处理器是单线程的所以Redis才叫做单线程的模型。它采用`I/O`多路复用机制同时监听多个`Socket`,将产生事件的`Socket`压入到内存队列中,事件分派器根据`Socket`上的事件类型来选择对应的事件处理器来进行处理。文件事件处理器包含5个部分
- **多个Socket**
- **I/O多路复用程序**
- **Scocket队列**
- **文件事件分派器**
- **事件处理器**(连接应答处理器、命令请求处理器、命令回复处理器)
客户端与redis的一次通信过程
![Redis请求过程](images/Middleware/Redis请求过程.png)
- **请求类型1**`客户端发起建立连接的请求`
- 服务端会产生一个`AE_READABLE`事件,`I/O`多路复用程序接收到`server socket`事件后,将该`socket`压入队列中
- 文件事件分派器从队列中获取`socket`,交给连接应答处理器,创建一个可以和客户端交流的`socket01`
- 将`socket01`的`AE_READABLE`事件与命令请求处理器关联
- **请求类型2**`客户端发起set key value请求`
- `socket01`产生`AE_READABLE`事件,`socket01`压入队列
- 将获取到的`socket01`与命令请求处理器关联
- 命令请求处理器读取`socket01`中的`key value`,并在内存中完成对应的设置
- 将`socket01`的`AE_WRITABLE`事件与命令回复处理器关联
- **请求类型3**`服务端返回结果`
- `Redis`中的`socket01`会产生一个`AE_WRITABLE`事件,压入到队列中
- 将获取到的`socket01`与命令回复处理器关联
- 回复处理器对`socket01`输入操作结果,如`ok`。之后解除`socket01`的`AE_WRITABLE`事件与命令回复处理器的关联
### 效率高
- `纯内存操作`数据存放在内存中内存的响应时间大约是100纳秒这是Redis每秒万亿级别访问的重要基础
- `非阻塞的I/O多路复用机制`Redis采用epoll做为I/O多路复用技术的实现再加上Redis自身的事件处理模型将epoll中的连接读写关闭都转换为了时间不在I/O上浪费过多的时间
- `C语言实现`:距离操作系统更近,执行速度会更快
- `单线程避免切换开销`:单线程避免了多线程上下文切换的时间开销,预防了多线程可能产生的竞争问题
## 数据类型
在 Redis 中,常用的 5 种数据类型和应用场景如下:
@ -477,7 +518,7 @@ Redis 整体就是一个 哈希表来保存所有的键值对,无论数据类
### zipList压缩列表
### zipList(压缩列表)
![ZipList压缩列表](images/Middleware/ZipList压缩列表.png)
@ -509,7 +550,7 @@ sorted set 类型的排序功能便是通过「跳跃列表」数据结构来实
### 整数数组intset
### intset(整数数组)
当一个集合只包含整数值元素并且这个集合的元素数量不多时Redis 就会使用整数集合作为集合键的底层实现,节省内存。结构如下:
@ -528,13 +569,29 @@ contents 数组是整数集合的底层实现:整数集合的每个元素都
## 持久化
## 持久化机制
### RDB机制(Redis DataBase)
RDBRedis DataBase持久化方式是指用数据集快照的方式半持久化模式记录 Redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
**优点**
- **适合大规模的数据恢复**
- **如果业务对数据完整性和一致性要求不高RDB是很好的选择**
**缺点**
- **数据的完整性和一致性不高因为RDB可能在最后一次备份时宕机**
- **备份时占用内存**。因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。所以要考虑到大概两倍的数据膨胀性
#### save触发方式
### RDB
`save` 命令同步数据到磁盘上是执行一个同步操作以RDB文件的方式保存所有数据的快照。该命令会阻塞当前Redis服务器执行save命令期间Redis不能处理其他命令直到RDB过程完成为止。具体流程如下
**① save命令 —— 同步数据到磁盘上**
`save` 命令执行一个同步操作以RDB文件的方式保存所有数据的快照。
![RDB-save命令](images/Middleware/RDB-save.jpg)
@ -542,9 +599,11 @@ contents 数组是整数集合的底层实现:整数集合的每个元素都
**② bgsave命令 —— 异步保存数据到磁盘上**
#### bgsave触发方式
`bgsave` 命令异步保存数据到磁盘上是执行一个异步操作以RDB文件的方式保存所有数据的快照。Redis会在后台异步进行快照操作快照同时还可以响应客户端请求。具体流程如下
`bgsave` 命令执行一个异步操作以RDB文件的方式保存所有数据的快照。
![RDB-gbsave](images/Middleware/RDB-gbsave.jpg)
@ -552,9 +611,9 @@ Redis使用Linux系统的`fock()`生成一个子进程来将DB数据保存到磁
**③ 自动生成RDB**
#### 自动触发方式
可以通过配置文件对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动进行数据集保存操作。比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动进行数据集保存操作:
可以通过配置文件对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动进行数据集保存操作:
```shell
# RDB自动持久化规则
@ -583,20 +642,9 @@ rdbchecksum yes
RDBRedis DataBase持久化方式是指用数据集快照的方式半持久化模式记录 Redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。
- 优点
- 只有一个文件 dump.rdb方便持久化。
- 容灾性好,一个文件可以保存到安全的磁盘。
- 性能最大化fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis的高性能。
- 相对于数据集大时,比 AOF 的启动效率更高。
- 缺点
- 数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 Redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
### AOF机制(Append Only File)
### AOF
AOFAppend-only file持久化方式是指所有的命令行记录以 Redis 命令请求协议的格式完全持久化存储保存为 aof 文件。
AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,因为这个模式是**只追加**的方式,所以没有任何磁盘寻址的开销,所以很快,有点像 Mysql 中的binlogAOF更适合做热备。
@ -662,13 +710,13 @@ AOF(Append-only file)持久化方式:是指所有的命令行记录以 Redis
### 定期过期
每隔一定的时间会扫描一定数量的数据库的expires字典中一定数量的key并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时可以在不同情况下使得CPU和内存资源**达到最优**的平衡效果。
每隔一定的时间会扫描一定数量的数据库的expires字典中一定数量的key并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时可以在不同情况下使得CPU和内存资源**达到最优**的平衡效果。expires字典会保存所有设置了过期时间的key的过期时间数据其中 key 是指向键空间中的某个键的指针value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。
expires字典会保存所有设置了过期时间的key的过期时间数据其中 key 是指向键空间中的某个键的指针value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。
## 淘汰策略
## 内存淘汰策略
Redis淘汰机制的存在是为了更好的使用内存用一定的缓存丢失来换取内存的使用效率。当Redis内存快耗尽时Redis会启动内存淘汰机制将部分key清掉以腾出内存。当达到内存使用上限超过`maxmemory`时,可在配置文件`redis.conf`中指定 `maxmemory-policy` 的清理缓存方式。
```properties
# 配置最大内存限制
@ -677,131 +725,37 @@ maxmemory 1000mb
maxmemory-policy volatile-lru
```
当达到内存使用上限超过`maxmemory`时,可在配置文件`redis.conf`中指定 `maxmemory-policy` 的清理缓存:
- `volatile-lru`:从已设置过期时间的数据集中挑选**最近最少使用**的数据淘汰(淘汰**最长时间**没有被使用)
- `volatile-lfu`:从已设置过期时间的数据集中挑选某段时间内**最近最不经常**的数据淘汰(淘汰一段时间内**使用次数**最少)
- `volatile-ttl`:从已设置过期时间的数据集中挑选**将要过期**的数据淘汰
- `volatile-random`:从已设置过期时间的数据集中**任意选择**数据淘汰
- `allkeys-lru`:从所有数据集中挑选**最近最少使用**的数据淘汰
- `allkeys-lfu`:从所有数据集中选择某段时间内内**最近最不经常**的数据淘汰
- `allkeys-random`:从所有数据集中**任意选择数**据淘汰
- `noenviction驱逐`:当达到最大内存时直接返回错误,不覆盖或逐出任何数据
**Redis为什么要有淘汰机制**
Redis淘汰机制的存在是为了更好的使用内存用一定的缓存丢失来换取内存的使用效率。
**Redis的过期策略?**
Redis有两种过期策略定期删除和惰性删除
- - **定期删除**Redis每个100ms随机抽取一些设置了过期时间的key检查其是否过期如果过期就删除。
- **惰性删除**在获取某个key的时候Redis检查一下如果该key设置了过期时间则判断该过期时间是否已经过期如果过期了就直接删掉并不返回任何东西。
**Redis的内存淘汰机制?**
当Redis内存快耗尽时Redis会启动内存淘汰机制将部分key清掉以腾出内存。
## 常见问题
https://mp.weixin.qq.com/s?__biz=MzIyODE5NjUwNQ==&mid=2653328521&idx=1&sn=97e4c97264a048ce13ba09fefa317b8c&chksm=f3879d7fc4f0146951090f16c267167cdcf584fe3caa885f9012ff2f8d4f1decbc8a5d8fb888&mpshare=1&scene=23&srcid=08175xQJR1aBzpGulVsfUIKO&sharer_sharetime=1629162636282&sharer_shareid=0f9991a2eb945ab493c13ed9bfb8bf4b&exportkey=A3IxBD6vssKPMBrFeRe474c%3D&pass_ticket=PR%2FK8afpsNEi%2BddqfJ7hs4AucApd5fjNtWZXpgb9L8YVYdX9SuEkeZYVHnTPPBgQ&wx_header=0#rd
### LRU(最近最少使用)
- `volatile-lru`从已设置过期时间的key中挑选**最近最少使用(最长时间没有使用)**的key进行淘汰
- `allkeys-lru`从所有key中挑选**最近最少使用**的数据淘汰
https://mp.weixin.qq.com/s?__biz=MzkyNjI0MTYwNQ==&mid=2247487592&idx=1&sn=9ea77048fbe5b4be4959245234b9e71e&chksm=c23b1642f54c9f54476bfd0b439b4be3c9746060bd5c32de312ab64b8638e3639655db6335f8&mpshare=1&scene=1&srcid=0817ypmJIVx2ocUwmiznff8K&sharer_sharetime=1629207327488&sharer_shareid=0f9991a2eb945ab493c13ed9bfb8bf4b&exportkey=A39xVeDz1JilVNbTG5kmJLw%3D&pass_ticket=PR%2FK8afpsNEi%2BddqfJ7hs4AucApd5fjNtWZXpgb9L8YVYdX9SuEkeZYVHnTPPBgQ&wx_header=0#rd
### LFU(最近最不经常使用)
**分析题目**保证Redis 中的 20w 数据都是热点数据 说明是 被频繁访问的数据并且要保证Redis的内存能够存放20w数据要计算出Redis内存的大小。
- **保留热点数据:**对于保留 Redis 热点数据来说,我们可以使用 Redis 的内存淘汰策略来实现,可以使用**allkeys-lru淘汰策略**该淘汰策略是从 Redis 的数据中挑选最近最少使用的数据删除,这样频繁被访问的数据就可以保留下来了
- **保证 Redis 只存20w的数据**1个中文占2个字节假如1条数据有100个中文则1条数据占200字节20w数据 乘以 200字节 等于 4000 字节大概等于38M;所以要保证能存20w数据Redis 需要38M的内存
**题目MySQL里有2000w数据redis中只存20w的数据如何保证redis中的数据都是热点数据?**
限定 Redis 占用的内存Redis 会根据自身数据淘汰策略,加载热数据到内存。所以,计算一下 20W 数据大约占用的内存,然后设置一下 Redis 内存限制即可。
**题目:假如 Redis 里面有 1 亿个 key其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?**
使用 keys 指令可以扫出指定模式的 key 列表。对方接着追问:如果这个 Redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?这个时候你要回答 Redis 关键的一个特性Redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令scan 指令可以无阻塞地提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
## 应用场景
- 缓存-键过期时间
- 把session会话存在redis,过期删除
- 缓存用户信息缓存Mysql部分数据用户先访问redisredis没有再访问mysql然后回写给redis
- 商城优惠卷过期时间
- 排行榜-列表&有序集合
- 热度/点击数排行榜
- 直播间礼物积分排行
- 计数器-天然支持计数器
- 帖子浏览数
- 视频播放数
- 评论数
- 点赞/踩
- 社交网络-集合
- 粉丝
- 共同好友
- 兴趣爱好
- 标签
- 消息队列-发布订阅
- 配合ELK缓存收集来的日志
## 主从复制
**概念定义**
- runID 服务器运行的ID
- offset 主服务器的复制偏移量和从服务器复制的偏移量
- replication backlog 主服务器的复制积压缓冲区
- `volatile-lfu`从已设置过期时间的key中挑选**最近最不经常使用(使用次数最少)**的key进行淘汰
- `allkeys-lfu`从所有key中选择某段时间内内**最近最不经常使用**的数据淘汰
在redis2.8之后使用psync命令代替sync命令来执行复制的同步操作psync命令具有完整重同步和部分重同步两种模式
- 其中完整同步用于处理初次复制情况完整重同步的执行步骤和sync命令执行步骤一致都是通过让主服务器创建并发送rdb文件以及向从服务器发送保存在缓冲区的写命令来进行同步
- 部分重同步是用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,主服务可以讲主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以讲数据库更新至主服务器当前所处的状态
### Random(随机淘汰)
- `volatile-random`从已设置过期时间的key中**任意选择**数据淘汰
- `allkeys-random`从所有key中**任意选择数**据淘汰
### 完整重同步
![Redis主从复制-完整重同步](images/Middleware/Redis主从复制-完整重同步.jpg)
1. slave发送psync给master由于是第一次发送不带上runid和offset
2. master接收到请求发送master的runid和offset给从节点
3. master生成保存rdb文件
4. master发送rdb文件给slave
5. 在发送rdb这个操作的同时写操作会复制到缓冲区replication backlog buffer中并从buffer区发送到slave
6. slave将rdb文件的数据装载并更新自身数据
### TTL(过期时间)
如果网络的抖动或者是短时间的断链也需要进行完整同步就会导致大量的开销这些开销包括了bgsave的时间rdb文件传输的时间slave重新加载rdb时间如果slave有aof还会导致aof重写。这些都是大量的开销所以在redis2.8之后也实现了部分重同步的机制。
- `volatile-ttl`从已设置过期时间的key中挑选**将要过期**的数据淘汰
- `allkeys-random`从所有key中**任意选择数**据淘汰
### 部分重同步
### No-Enviction(驱逐)
![Redis主从复制-部分重同步](images/Middleware/Redis主从复制-部分重同步.jpg)
- 网络发生错误master和slave失去连接
- master依然向buffer缓冲区写入数据
- slave重新连接上master
- slave向master发送自己目前的runid和offset
- master会判断slave发送给自己的offset是否存在buffer队列中如果存在则发送continue给slave如果不存在意味着可能错误了太多的数据缓冲区已经被清空这个时候就需要重新进行全量的复制
- master发送从offset偏移后的缓冲区数据给slave
- slave获取数据更新自身数据
- `noenviction驱逐`:当达到最大内存时直接返回错误,不覆盖或逐出任何数据
@ -815,8 +769,6 @@ https://mp.weixin.qq.com/s?__biz=MzkyNjI0MTYwNQ==&mid=2247487592&idx=1&sn=9ea770
- 高性价比:缓存使用时无需备用节点(单实例可用性可以用 supervisor 或 crontab 保证),当然为了满足业务的高可用性,也可以牺牲一个备用节点,但同时刻只有一个实例对外提供服务
- 高性能
**缺点**
- 不保证数据的可靠性
@ -1117,6 +1069,28 @@ cluster_stats_messages_received:3021
## 常见问题
**分析题目**保证Redis 中的 20w 数据都是热点数据 说明是 被频繁访问的数据并且要保证Redis的内存能够存放20w数据要计算出Redis内存的大小。
- **保留热点数据:**对于保留 Redis 热点数据来说,我们可以使用 Redis 的内存淘汰策略来实现,可以使用**allkeys-lru淘汰策略**该淘汰策略是从 Redis 的数据中挑选最近最少使用的数据删除,这样频繁被访问的数据就可以保留下来了
- **保证 Redis 只存20w的数据**1个中文占2个字节假如1条数据有100个中文则1条数据占200字节20w数据 乘以 200字节 等于 4000 字节大概等于38M;所以要保证能存20w数据Redis 需要38M的内存
**题目MySQL里有2000w数据redis中只存20w的数据如何保证redis中的数据都是热点数据?**
限定 Redis 占用的内存Redis 会根据自身数据淘汰策略,加载热数据到内存。所以,计算一下 20W 数据大约占用的内存,然后设置一下 Redis 内存限制即可。
**题目:假如 Redis 里面有 1 亿个 key其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?**
使用 keys 指令可以扫出指定模式的 key 列表。对方接着追问:如果这个 Redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?这个时候你要回答 Redis 关键的一个特性Redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令scan 指令可以无阻塞地提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
# Kafka

Loading…
Cancel
Save