redis原理剖析
redis技术分享
大家知道redis的默认端口为什么是6379吗
而是由手机键盘字母「MERZ」的位置决定的。
「MERZ」在 Antirez 的朋友圈语言中是「愚蠢」的代名词,它源于意大利广告女郎
「Alessia Merz」在电视节目上说了一堆愚蠢的话 Antirez 今年已经四十岁了,依旧在孜孜不倦地写代码,为 Redis 的开源事业持续贡献力量
redis简介
Redis采用的是基于内存的单进程单线程模型的KV数据库,由C语言编写,官方提供的数据是可以达到100000+的
QPS(每秒内查询次数),他常被用作缓存和消息中间件
它支持多种类型的数据结构,如字符串(String),散列(Hash),列表(List),集合(Set),
有序集合(SortedSet或者是ZSet),Bitmaps,Hyperloglogs。其中常见的数据结构类型有:String、
List、Set、Hash、ZSet这5种。
**横轴为连接数,纵轴为响应次数
redis常用数据结构的底层实现
- 有序集合(SortedSet)
跳跃表是有序集合(Sorted Set)的底层实现,
- Hyperloglogs
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数,0.81%
redis持久化
为什么需要持久化?
redis里有10gb数据,突然停电或者意外宕机了,再启动的时候10gb都没了,所以需要
持久化,宕机后再通过持久化文件将数据恢复。
redis的两种持久化方式:RDB和AOF
- RDB
RDB有两种持久化方式:SAVE,BGSAVE
1.SAVE
它是同步阻塞持久化的,致命的问题,持久化的时候redis服务阻塞(准确的说会
阻塞当前执行save命令的线程,但是redis是单线程的,所以整个服务会阻塞),
不能继对外提供请求,GG!数据量小的话肯定影响不大,数据量大呢?每次复制需
要1小时,那就相当于停机一小时。
2.BGSAVE (background save)
异步非阻塞进行持久化的
他可以一边进行持久化,一边对外提供读写服务,互不影响,新写的数据对我持久化不会
造成数据影响,你持久化的过程中报错或者耗时太久都对我当前对外提供请求的服务不会
产生任何影响。持久化完会将新的rdb文件覆盖之前的。
BGSAVE原理:fork() + copyonwrite
fork:用于创建一个子进程,注意是子进程,不是子线程。fork()出来的进程共享其
父类的内存数据。仅仅是共享fork()出子进程的那一刻的内存数据,后期主进程修改数据
对子进程不可见,同理,子进程修改的数据对主进程也不可见。
copyonwrite:主进程fork()子进程之后,内核把主进程中所有的内存页的权限都设为read-
only,然后子进程的地址空间指向主进程。这也就是共享了主进程的内存,当其中某个进
程写内存时(这里肯定是主进程写,因为子进程只负责rdb文件持久化工作,不参与客户端
的请求),CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷
入内核的一个中断例程。
- AOF
它也是Redis持久化的重要手段之一,全称Append Only file 的缩写,叫只追加文件
也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等
时机开子进程去干这件事。
原理:是每次都在aof文件后面追加命令。他与主进程收到请求、处理请求是串行化的,而非异步并行的。图示如下
优点:
1.持久化的速度快,因为每次都只是追加,rdb每次都全量持久化
2.数据相对更可靠,丢失少,因可以配置每秒持久化、每个命令执行完就持久化
缺点:
1.灾难性恢复的时候过慢,因为aof每次都只追加原命令,导致aof文件过大,但是后面会
rewrite,但是相对于rdb也是慢的。
2.会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行
原子执行的。而非异步多线程执行的。Redis单线程!
redis可以做什么?
正常情况下就是用来做缓存,或者是分布式情况下
的布式锁(分布式锁下面会详解),还有很多情况下
用到redis,举几个栗子
1.缓存近期热帖内容 (帖子内容空间占用比较大),减少数据库压力
(hash)
2.uv的统计(Hyperloglogs)
3.记录帖子的标题、摘要、作者和封面信息,用于
列表页展示 (hash)
4.延时消息队列。如果对消息的可靠性不做要求的
话,可以通过list来实现延时消息队列,pop的时
候让线程sleep一段时间。
5.推荐去重、邮箱系统的垃圾邮件过滤(Bloom Filter)
6.统计用户的周活、月活(BitMap)
redis 的分布式锁
- 单实例实现的分布式锁(假设单实例足够可用)
使用命令SET key value NX PX 30000
但是仅仅这样做会存在风险,大家可以想一想为什么
因为线程A被阻塞了比较长时间,如果等它执行结束,然后释放锁,
此时的锁早就因为超时而被释放,在被释放的时候线程B获得了该锁,
那么如果A在释放锁的时候会把线程B获得的锁释放掉,就出现问题了
解决办法:把key设为全局唯一的随机值
- 多实例的分布式锁实现-redlock算法
原理
1.获取当前Unix时间,以毫秒为单位。
2.依次尝试从N个实例,使用相同的key和随机值获
取锁。在步骤2,当向Redis设置锁时,客户端应该设
置一个网络连接和响应超时时间,这个超时时间应
该小于锁的失效时间.例如你的锁自动失效时间为10
秒,则超时时间应该在5-50毫秒之间。这样可以避
免服务器端Redis已经挂掉的情况下,客户端还在死
死地等待响应结果。如果服务器端没有在规定时间
内响应,客户端应该尽快尝试另外一个Redis实例。
3.客户端使用当前时间减去开始获取锁时间(步骤1
记录的时间)就得到获取锁使用的时间。当且仅当
从大多数(这里是3个节点)的Redis节点都取到锁
,并且使用的时间小于锁失效时间时,锁才算获取
成功。
4.如果取到了锁,key的真正有效时间等于有效时间
减去获取锁所使用的时间(步骤3计算的结果)。
如果因为某些原因,获取锁失败(没有在至少N/2+1
个Redis实例取到锁或者取锁时间已经超过了有效时
间),客户端应该在所有的Redis实例上进行解锁(
即便某些Redis实例根本就没有加锁成功)。
redis的分布式搭建
- redis 一致性保证
redis 并不能保证数据的强一致性.这意味这在实中集群在特定的条件下
可能会丢失写操作.
第一个原因是因为集群是用了异步复制.写操作过程如下
1.客户端向主节点B写入一条命令
2.主节点B向客户端回复命令状态
3.主节点将写操作复制给他得从节点 B1, B2 和 B3
第二个原因是因为网络分区
举个例子 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, A1
、B1 、C1 为A,B,C的从节点, 还有一个客户端Z1
假设集群中发生网络分区,那么集群可能会分为
两方,大部分的一方包含节点 A 、C 、A1 、B1 和C1 ,
小部分的一方则包含节点 B 和客户端 Z1 .
Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常
运作,如果分区的时间足够让大部分的一方将B1选举
为新的master,那么Z1写入B中得数据便丢失了.
- redis的集群的数据分片
redis集群没有使用一致性hash, 而是引入了 哈希槽的概念
Redis 集群有16384个哈希槽,集群的最大节点数量也是 16384个 每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点哈希槽会被
平均分配,当一个节点不可用,则整个集群不可用,因为有一部分哈希槽被集群认为不可用,除非进行重分片
- redis的主从复制模型
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型.
在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那
么整个集群就会以为缺少5501-11000这个范围的槽而不可用.
然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,
那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选
举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了
不过当B和B1 都失败后,集群是不可用的.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异