Redis 原理
线程IO模型
Redis 是个单线程程序!(对外网络请求服务)
对于那些时间复杂度为 O(n) 级别的指令,一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。
使用缓冲区,事件轮询 API(Linux操作系统提供的select,poll,epoll),非阻塞 IO(能读多少读多少,能写多少写多少,读方法和写方法都会通过返回值来告知程序实际读写了多少字节)。
注:epoll无须遍历整个被侦听的描述符集(fd),只要遍历那些被内核IO事件异步唤醒的描述符集合,select与poll是全轮询。
通信协议
Redis 将所有数据都放在内存,用一个单线程对外提供服务,单个节点在跑满一个 CPU 核心的情况下可以达到大约 10w/s 的 QPS(每秒查询数)。
RESP(Redis Serialization Protocol)
RESP 是 Redis 序列化协议的简写。它是一种直观的文本协议,优势在于实现异常简单,解析性能极好。
Redis 协议将传输的结构数据分为 5 种最小单元类型,单元结束时统一加上回车换行符号\r\n
。
- 单行字符串 以
+
符号开头。 - 多行字符串 以
$
符号开头,后跟字符串长度。 - 整数值 以
:
符号开头,后跟整数的字符串形式。 - 错误消息 以
-
符号开头。 - 数组 以
*
号开头,后跟数组的长度。
持久化
Redis 的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的持久化机制。
Redis 的持久化机制有两种,第一种是快照,第二种是 AOF 日志。快照是一次全量备份,AOF 日志是连续的增量备份。
快照原理
Redis 在持久化时会调用 glibc 的函数fork
产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。
fork
函数会在父子进程同时返回,在父进程里返回子进程的 pid,在子进程里返回零。如果操作系统内存资源不足,pid 就会是负数,表示fork
失败。
这个时候就会使用操作系统的 COW (copy on write)机制来进行数据段页面的分离。数据段是由很多操作系统的页面(一个页面4k)组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
AOF原理
AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。 假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。
Redis 在长期运行的过程中,AOF 的日志会越变越长。如果实例宕机重启,重放整个 AOF 日志会非常耗时,导致长时间 Redis 无法对外提供服务。所以需要对 AOF 日志重写瘦身。
AOF 日志一般先暂存在内存缓存中,然后内核会异步将日志数据刷回磁盘,如果机器突然宕机,AOF 日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。
Linux 的glibc提供了fsync(int fd)函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 aof 日志不丢失。但是 fsync 是一个磁盘 IO 操作,它很慢!如果 Redis 执行一条指令就要 fsync 一次,那么 Redis 高性能的地位就不保了。 所以在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作,周期 1s 是可以配置的。这是在数据安全性和性能之间做了一个折中,在保持高性能的同时,尽可能使得数据少丢失。
通常 Redis 的主节点是不会进行持久化操作,持久化操作主要在从节点进行。从节点是备份节点,没有来自客户端请求的压力,它的操作系统资源往往比较充沛。
Redis 4.0 混合持久化
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。
Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
管道
本质节省的是网络响应的时间开销,客户端一次发送多条命令,服务端照常一条一条处理,不过客户端等待响应的时间少了。
之所以能节省网络响应的时间开销,在于客户端写读的本质,是和本地操作系统内核打交道,写几乎不耗时,读需要等待响应耗时。
事务
Redis 的事务没有满足原子性,只满足了事务的隔离性。指令:multi,discard,exec。
所以通常 Redis 的客户端在执行事务时都会结合 pipeline 一起使用,这样可以将多次 IO 操作压缩为单次 IO 操作。
Redis是先执行指令然后做日志,所以不支持回滚。
分布式锁是一种悲观锁,可以通过 watch 的机制实现乐观锁。
— —总结自:《Redis深度历险》
Redis 原理的更多相关文章
- Redis原理与实践总结
Redis原理与实践总结 本文主要对Redis的设计和实现原理做了一个介绍很总结,有些东西我也介绍的不是很详细准确,尽量在自己的理解范围内把一些知识点和关键性技术做一个描述.如有错误,还望见谅,欢迎指 ...
- Redis原理篇
Redis原理篇 1.发布 订阅模式 1.1列表 的局限 前面我们说通过队列的 rpush 和 lpop 可以实现消息队列(队尾进队头出),但是消费者需要不停地调用 lpop 查看 List 中是 ...
- Redis 系列(04-2)Redis原理 - 内存回收
目录 Redis 系列(04-2)Redis原理 - 内存回收 Redis 系列目录 1. 过期策略 1.1 定时过期(主动淘汰) 1.2 惰性过期(被动淘汰) 1.3 定期过期 2. 淘汰策略 2. ...
- Redis原理详解
Redis原理详解 数据类型 Redis最为常用的数据类型主要有以下五种: String Hash List Set Sorted set 在具体描述这几种数据类型之前,我们先通过一张图了解下Redi ...
- 面试被吊打系列 - Redis原理
小张兴冲冲去面试,结果被面试官吊打! 小张: 面试官,你好.我是来参加面试的. 面试官: 你好,小张.我看了你的简历,熟练掌握Redis,那么我就随便问你几个Redis相关的问题吧.首先我的问题是,R ...
- redis原理分析
基本全是参考http://blog.csdn.net/a600423444/article/details/8944601 redis的使用大家都很熟悉,可能除了watch 锁,pipelin ...
- Redis原理及使用
一:原理介绍 1:什么是redis? Redis 是一个基于内存的高性能key-value数据库. 2:Reids的特点Redis本质上是一个Key-Value类型的内存数据库,很像memcache ...
- Redis详细讲解(Redis原理,Redis安装,Redis配置,Redis使用,Redis命令)
一.Redis介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发 ...
- redis原理及实现
1 什么是redis redis是nosql(也是个巨大的map) 单线程,但是可处理1秒10w的并发(数据都在内存中) 使用java对redis进行操作类似jdbc接口标准对mysql,有各类实现他 ...
- Redis原理及集群相关知识
读书笔记 <Redis开发与运维 > Redis使用场景 作为缓存层 减少对Mysql的压力 计数功能 比如使用原子命令incr 共享Session 设置过期时间 可以限制短信接口等调用 ...
随机推荐
- Tensorflow学习教程------tfrecords数据格式生成与读取
首先是生成tfrecords格式的数据,具体代码如下: #coding:utf-8 import os import tensorflow as tf from PIL import Image cw ...
- mysql 不停机 短时间锁表 备份 主备同步 新增备份机器
刷新数据 [root@localhost ~]# mysql -e 'flush tables with read lock;' 锁表刷新表数据 [root@localhost ~]# mys ...
- vue wangeditor3封装
<script src="wangEditor/3.1.1/wangEditor.min.js"></script> Vue.component('my ...
- 新年在家学java之基础篇-高级类的特性
继承 extends 子类的共性代码都是继承自父类的,每个子类只要写自己特有的代码 class 子类 extends 父类 继承提高了代码的复用性,提供了多态的前提,但是不要为了某个功能去继承 子类不 ...
- Opencv笔记(十六)——认识轮廓
什么是轮廓? 轮廓可以简单认为成连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度.轮廓在形状分析和物体的检测和识别中很有用.谈起轮廓不免想到边缘,它们确实很像.简单的说,轮廓是连续的,边缘并 ...
- C++ for循环遍历几种写法
最近写for循环,发现以前用过的方法都忘记了,这里整理下几种方法,欢迎大佬补充: 1. for(itnt n =1;n<5;n++) { } 2. for (auto it = list.beg ...
- hibernate 持久化对象 save
hibernate 持久化对象 save new出来的user对象是游离状态的对象,执行session.save()方法保存后,user对象就变为持久化了,持久化的对象跟数据库表双向绑定的意思, 对象 ...
- vue中的路由传参及跨组件传参
路由跳转 this.$router.push('/course'); this.$router.push({name: course}); this.$router.go(-1); this.$r ...
- java通过免费接口获取ip地址的服务商信息
今天分享一个免费在线的小工具的开发代码就是通过淘宝提供的接口获取服务商信息,工具地址:http://www.yzcopen.com/seo/ipadress 代码如下: public class Yz ...
- android课程表控件、悬浮窗、Todo应用、MVP框架、Kotlin完整项目源码
Android精选源码 Android游戏2048 MVP Kotlin项目(RxJava+Rerotfit+OkHttp+Glide) Android基于自定义Span的富文本编辑器 android ...