极客时间 Redis核心技术与实战 笔记(基础篇)
Redis 概览
Redis 知识全景图
Redis 问题画像图
基础篇
基本架构
数据结构
数据类型和底层数据结构映射关系
全局哈希表
链式哈希解决哈希冲突
渐进式 rehash
不同数据结构查找操作的时间复杂度
不同操作的复杂度
- 单元素操作是基础;
- 范围操作非常耗时;
- 统计操作通常高效;
- 例外情况只有几个。
第一,单元素操作,是指每一种集合类型对单个数据实现的增删改查操作。例如,Hash 类型的 HGET、HSET 和 HDEL,Set 类型的 SADD、SREM、SRANDMEMBER 等。这些操作的复杂度由集合采用的数据结构决定,例如,HGET、HSET 和 HDEL 是对哈希表做操作,所以它们的复杂度都是 O(1);Set 类型用哈希表作为底层数据结构时,它的 SADD、SREM、SRANDMEMBER 复杂度也是 O(1)。这里,有个地方你需要注意一下,集合类型支持同时对多个元素进行增删改查,例如 Hash 类型的 HMGET 和 HMSET,Set 类型的 SADD 也支持同时增加多个元素。此时,这些操作的复杂度,就是由单个元素操作复杂度和元素个数决定的。例如,HMSET 增加 M 个元素时,复杂度就从 O(1) 变成 O(M) 了。
第二,范围操作,是指集合类型中的遍历操作,可以返回集合中的所有数据,比如 Hash 类型的 HGETALL 和 Set 类型的 SMEMBERS,或者返回一个范围内的部分数据,比如 List 类型的 LRANGE 和 ZSet 类型的 ZRANGE。这类操作的复杂度一般是 O(N),比较耗时,我们应该尽量避免。
不过,Redis 从 2.8 版本开始提供了 SCAN 系列操作(包括 HSCAN,SSCAN 和 ZSCAN),这类操作实现了渐进式遍历,每次只返回有限数量的数据。这样一来,相比于 HGETALL、SMEMBERS 这类操作来说,就避免了一次性返回所有元素而导致的 Redis 阻塞。
第三,统计操作,是指集合类型对集合中所有元素个数的记录,例如 LLEN 和 SCARD。这类操作复杂度只有 O(1),这是因为当集合类型采用压缩列表、双向链表、整数数组这些数据结构时,这些结构中专门记录了元素的个数统计,因此可以高效地完成相关操作。
第四,例外情况,是指某些数据结构的特殊记录,例如压缩列表和双向链表都会记录表头和表尾的偏移量。这样一来,对于 List 类型的 LPOP、RPOP、LPUSH、RPUSH 这四个操作来说,它们是在列表的头尾增删元素,这就可以通过偏移量直接定位,所以它们的复杂度也只有 O(1),可以实现快速操作。
高性能IO模型
通常说,Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
Redis 为什么用单线程?
多线程存在开销
- 多线程编程模式面临共享资源的并发访问控制问题。
- 线程上下文切换的开销
单线程 Redis 为什么那么快?
多路复用机制
基本 IO 模型与阻塞点
在这里的网络 IO 操作中,有潜在的阻塞点,分别是 accept() 和 recv()。当 Redis 监听到一个客户端有连接请求,但一直未能成功建立起连接时,会阻塞在 accept() 函数这里,导致其他客户端无法和 Redis 建立连接。类似的,当 Redis 通过 recv() 从一个客户端读取数据时,如果数据一直没有到达,Redis 也会一直阻塞在 recv()。
这就导致 Redis 整个线程阻塞,无法处理其他客户端请求,效率很低。不过,幸运的是,socket 网络模型本身支持非阻塞模式。
非阻塞模式
在 socket 模型中,不同操作调用后会返回不同的套接字类型。socket() 方法会返回主动套接字,然后调用 listen() 方法,将主动套接字转化为监听套接字,此时,可以监听来自客户端的连接请求。最后,调用 accept() 方法接收到达的客户端连接,并返回已连接套接字。
针对监听套接字,我们可以设置非阻塞模式:当 Redis 调用 accept() 但一直未有连接请求到达时,Redis 线程可以返回处理其他操作,而不用一直等待。但是,你要注意的是,调用 accept() 时,已经存在监听套接字了。
虽然 Redis 线程可以不用继续等待,但是总得有机制继续在监听套接字上等待后续连接请求,并在有请求时通知 Redis。
类似的,我们也可以针对已连接套接字设置非阻塞模式:Redis 调用 recv() 后,如果已连接套接字上一直没有数据到达,Redis 线程同样可以返回处理其他操作。我们也需要有机制继续监听该已连接套接字,并在有数据达到时通知 Redis。
这样才能保证 Redis 线程,既不会像基本 IO 模型中一直在阻塞点等待,也不会导致 Redis 无法处理实际到达的连接请求或数据。
到此,Linux 中的 IO 多路复用机制就要登场了。
基于多路复用的高性能 I/O 模型
Linux 中的 IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听套接字和已连接套接字。
下图就是基于多路复用的 Redis IO 模型。图中的多个 FD 就是刚才所说的多个套接字。Redis 网络框架调用 epoll 机制,让内核监听这些套接字。此时,Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。
为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。
那么,回调机制是怎么工作的呢?其实,select/epoll 一旦监测到 FD 上有请求到达时,就会触发相应的事件。
这些事件会被放进一个事件队列,Redis 单线程对该事件队列不断进行处理。这样一来,Redis 无需一直轮询是否有请求实际发生,这就可以避免造成 CPU 资源浪费。同时,Redis 在对事件队列中的事件进行处理时,会调用相应的处理函数,这就实现了基于事件的回调。因为 Redis 一直在对事件队列进行处理,所以能及时响应客户端请求,提升 Redis 的响应性能。
持久化
参考:极客时间 Redis核心技术与实战 笔记(基础篇 AOF和RDB)
主从同步、哨兵机制、切片集群
参考:极客时间 Redis核心技术与实战 笔记(基础篇 集群)
极客时间 Redis核心技术与实战 笔记(基础篇)相关推荐
- 极客时间 Redis核心技术与实战 笔记(实践篇 集群)
Redis主从同步与故障切换,有哪些坑? 主从数据不一致 原因:主从库间的命令复制是异步进行的 从库会滞后执行同步命令的原因: 主从库间的网络可能会有传输延迟,所以从库不能及时地收到主库发送的命令,从 ...
- 《极客时间·每日一课》笔记
秒杀服务的限流策略 合法性限流 鉴定非法请求: 验证码(剔除机器人,使用户的请求时间随机分布) 非法IP限制 隐藏秒杀按钮入口 负载限流 负载均衡分发请求到每个服务器 多级(级联)负载,第二层MAC负 ...
- Elastic 极客时间 阮一鸣 学习笔记_入门
资料链接:https://github.com/MINCWANG/geektime-ELK 版本迭代 插件在线安装(中文ik分词器) 启停 Kibana 快捷键 documnet index ES m ...
- 用户体验地图的一个不错的例子(极客时间用户体验设计课笔记)
1 要根据用户不同的角色去划分用户体验地图 用户体验地图要和用户角色相对应 ,不仅要明确体验地图对应的目标用户,更要 明确目标用户下不同的用户角色,一个角色对应一份体验地图. 2 一个完整的例子:
- Linux CentOS 系统实战笔记-基础篇
CentOS 日常笔记 1.Linux基础命令1 2.Linux基础命令2 3.输入输出重定向 4.Linux下目录分类与作用 5.虚拟机与物理机时间同步 6. VIM 神之编辑器 7. Linux ...
- 【极客时间】《Java并发编程实战》学习笔记
目录: 开篇词 | 你为什么需要学习并发编程? 内容来源:开篇词 | 你为什么需要学习并发编程?-极客时间 例如,Java 里 synchronized.wait()/notify() 相关的知识很琐 ...
- 极客时间课程《Python核心技术与实战》课程练习实践
GitHub - zwdnet/PythonPractice: 极客时间课程<Python核心技术与实战>课程练习实践.极客时间课程<Python核心技术与实战>课程练习实践. ...
- 本人亲自整理的极客时间设计模式之美的硬核笔记
由于笔记内容过多,我把它放到语雀上了. 点击我 以下内容是为了让搜索引擎,检测到这篇文章.要阅读体验,请点击上面的连接"点击我",去我的语雀看.对了,我看到语雀那里有投诉的功能,请 ...
- Redis核心技术与实战-蒋德钧-课程笔记
一.Redis知识全景图 二.Redis问题画像图 参考资料: 极客时间<Redis核心技术与实战>课程
最新文章
- Python中matplotlib默认绘制的条形图比较胖?如何设置成体型匀称的条形图,达到最佳的可视化效果。
- 深入解析Android关机
- oracle里面有emp表么,Oracle自带表(EMP)SQL语句练习
- Multi Dimension 数据库设计
- memcpy后数据不对_详解Redis 的 5 种基本数据结构:
- [转载][总结]函数getopt(),getopt_long及其参数optind
- java文件解压文件_java 文件解压缩
- 习题6-2 使用函数求特殊a串数列和 (20 分)
- C#LeetCode刷题之#884-两句话中的不常见单词(Uncommon Words from Two Sentences)
- matlab帮助_【MATLAB】使用 APP DESIGNER 模块来帮助你做参数设计
- 募资补充粮草、成交额翻倍增长,想翻身的国美开始造势
- oc 经常用到弹出view的方法
- 活化脂修饰NOTA,NOTA-NHS ester,CAS:1338231-09-6
- 现代软件工程 第一章 【概论】练习与讨论 第10题 邓杰
- c语言最大乘积问题,利用C语言来求最大连续子序列乘积的方法
- Numpy:随机抽样
- “阿里/字节“大厂自动化测试面试题一般会问什么?以及技巧和答案
- 服务器查看系统盘位置,服务器上查看硬盘位置
- 计算机桌面都有说明,电脑桌面上所有图标都消失了的四种处理方法
- android 车载蓝牙模块,安卓APP通过蓝牙串口模块控制DSP车机收音机
热门文章
- 关于Android app正式版本和测试版本的切换
- CentOS下的服务器审计系统:script
- 「微信群合影2.3.0」- 新增高清头像
- 把照片唱给你听 | 腾讯AI Lab国际领先技术邀你「趣」体验
- mysql中如何分页查询_MySQL_mysql分页原理和高效率的mysql分页查询语句,以前我在mysql中分页都是用的 l - phpStudy...
- 微信中域名网站域名被封锁、被屏蔽、被和谐后的解决方法
- 连就连,你我相约定百年。谁若97岁死,奈何桥上等三年!
- java腾讯地图根据经纬度获取具体位置
- 如何设计一个混沌工程实验?
- 1-13 格式化输出