Redis架构设计

一、前言

 
  Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
 
 

二、redis启动流程

 
1.初始化server变量,设置redis相关的默认值
2.读入配置文件,同时接收命令行中传入的参数,替换服务器设置的默认值
3.初始化服务器功能模块。在这一步初始化了包括进程信号处理、客户端链表、共享对象、初始化数据、初始化网络连接等
4.从RDB或AOF重载数据
5.网络监听服务启动前的准备工作
6.开启事件监听,开始接受客户端的请求
 
启动的部分过程通过查看下图,会更直观。
 
下面是针对启动过程中,对各个模块的详细理解。(目前只分析了后台线程系统与慢查询日志系统)
 

三、Redis数据持久化方案

 
  在使用redis时不少人都说一个问题,就是说redis宕机了怎么办?会不会数据丢失等等的问题。现在来看看Redis提供的数据持久化解决方案,并通过原理分析优缺点。最终能得出Redis适合使用的应用场景。

1.RDB持久化方案

  在Redis运行时,RDB程序将当前内存中的数据库快照保存到磁盘中,当Redis需要重启时,RDB程序会通过重载RDB文件来还原数据库。从上述描述可以看出,RDB主要包括两个功能:关于rdb的实现可以见src/rdb.c

a)保存(rdbSave)

  rdbSave负责将内存中的数据库数据以RDB格式保存到磁盘中,如果RDB文件已经存在将会替换已有的RDB文件。保存RDB文件期间会阻塞主进程,这段时间期间将不能处理新的客户端请求,直到保存完成为止。为避免主进程阻塞,Redis提供了rdbSaveBackground函数。在新建的子进程中调用rdbSave,保存完成后会向主进程发送信号,同时主进程可以继续处理新的客户端请求。

b)读取(rdbLoad)

  当Redis启动时,会根据配置的持久化模式,决定是否读取RDB文件,并将其中的对象保存到内存中。载入RDB过程中,每载入1000个键就处理一次已经等待处理的客户端请求,但是目前仅处理订阅功能的命令(PUBLISH 、 SUBSCRIBE 、 PSUBSCRIBE 、 UNSUBSCRIBE 、 PUNSUBSCRIBE),其他一律返回错误信息。因为发布订阅功能是不写入数据库的,也就是不保存在Redis数据库的。
 
RDB的缺点:再说RDB缺点时,需要提到的是RDB有保存点的概念。在默认的redis.conf中可以看到这样的默认配置:
#save <seconds> <changes>
save //如果15分钟内,有1个键被修改
save //如果6分钟内,有10个键被修改
save //如果60秒内有10000个键被修改
 
意思是当满足上面任意一个条件时,将会进行快照保存。为了保证IO读写性能不会成为Redis的瓶颈,一般都会创建一个比较大的值来作为保存点。
  1.此时如果保存点设置过大,就会导致宕机丢失的数据过多。保存点设置过小,又会造成IO瓶颈
  2.当对数据进行保存时,可能会由于数据集过大导致操作耗时,这会导致Redis可能在短时间内无法处理客户端请求。
 

2.AOF持久化方案

  以协议文本的方式,将所有对数据库进行的写入命令记录到AOF文件,达到记录数据库状态的目的。

a)保存

1.将客户端请求的命令转换为网络协议格式
2.将协议内容字符串追加到变量server.aof_buf中
3.当AOF系统达到设定的条件时,会调用aof_fsync(文件描述符号)将数据写入磁盘
 
其中第三步提到的设定条件,就是AOF性能的关键点。目前Redis支持三种保存条件机制:
1.AOF_FSYNC_NO:不保存
  此模式下,每执行一条客户端的命令,都会将协议字符串追加到server.aof_buf中,但不会执行写入磁盘。
写入只发生在:
  1.Redis被正常关闭;
  2.Aof功能关闭;
  3.系统写缓存已满,或后台定时保存操作被执行
上面三种情况都会阻塞主进程,导致客户端请求失败。
 
2.AOF_FSYNC_EVERYSECS:每一秒保存一次
  由后台子进程调用写入保存,不会阻塞主进程。如果发生宕机,那么最大丢失数据会在2s以内的数据。这也是默认的设置选项。
 
3.AOF_FSYNC_ALWAYS:每执行一个命令都保存一次
  这种模式下,可以保证每一条客户端指令都被保存,保证数据不会丢失。但缺点就是性能大大下降,因为每一次操作都是独占性的,需要阻塞主进程。
 

b)读取

  AOF保存的是数据协议格式的数据,所以只要将AOF中的数据转换为命令,模拟客户端重新执行一遍,就可以还原所有数据库状态。
读取的过程是:
  1.创建模拟的客户端
  2.读取AOF保存的文本,还原数据为原命令和原参数。然后使用模拟的客户端发出这个命令请求。
  3.继续执行第二步,直到读取完AOF文件
 
AOF需要将所有的命令都保存到磁盘,那么这个文件会随着时间变得越来越大。读取也会变得很慢。Redis提供了AOF的重写机制,帮助减少文件的大小。
实现的思路是:
LPUSH list
LPOP list
LPOP list
LPUSH list

最初保存到AOF文件的将会是四条指令。但经过AOF重写后,会变成一条指令:

LPUSH list    
同时,考虑到为了在AOF重写时,不影响AOF的写入增加了AOF重写缓存的概念。也就是说Redis在开启AOF时,除了将命令格式数据写入到AOF文件,同时也会写入到AOF重写缓存。这样AOF的写入、重写就做到了隔离,保证了重写时不会阻塞写入。
 

c)AOF重写流程

1.AOF重写完成会向主进程发送一个完成的信号
2.会将AOF重写缓存中的数据全部写入到文件中
3.用新的AOF文件,覆盖原有的AOF文件。
 

d)AOF缺点

1.AOF文件通常会大于相同数据集的RDB文件
2.AOF模式下性能与RDB模式下性能高低,主要取决于AOF选用的fsync模式
 
下面给出客户端请求RedisServer时,server端持久化的部分操作图解。

四、Redis数据库的实现

 
  Redis是一个键值对数据库,称为键空间。实现这种KV形式的存储,Redis使用了两种数据结构类型:1、字典,Redis字典使用的是哈希表实现,原本不准备详细介绍Redis哈希表的实现。但发现Redis在实现哈希表时,提供了一个很好的rehash方案,这个方案思路很好,甚至可以衍生到其他各个应用中使用,方案的名称叫“渐进式Rehash”。
  实现哈希表的方法大同小异,但为何各个开源软件总是去开发自己独有的哈希数据结构呢?从研究PHP内核的哈希实现与Redis哈希实现,发现应用场景决定了必须定制才能更好的发挥性能。

a)PHP主要应用于WEB场景,在WEB场景针对单次请求数据之间是隔离的,并且哈希的数量是有限的,那么进行一次rehash也是很快的。所以PHP内核使用阻塞形式rehash,即rehash进行中将不能对当前哈希表进行任何操作。

 
b)在来看Redis,常驻进程,接收客户端请求处理各项事务,并且操作的数据是相关且数据量较大的,如果使用PHP内核的那种方式就会出现:对哈希表进行rehash时,此时将阻塞所有客户端请求,并发性能会大大下降。
 
初始化字典图解:
 
新增字典元素图解:
 
Rehash执行流程:
 
 
 
 

Redis --> Redis架构设计的更多相关文章

  1. Redis缓存项目应用架构设计二

    一.概述 由于架构设计一里面如果多平台公用相同Key的缓存更改配置后需要多平台上传最新的缓存配置文件来更新,比较麻烦,更新了架构设计二实现了缓存配置的集中管理,不过这样有有了过于中心化的问题,后续在看 ...

  2. 亿级流量场景下,大型缓存架构设计实现【1】---redis篇

    *****************开篇介绍**************** -------------------------------------------------------------- ...

  3. Redis架构设计

    高可用Redis服务架构分析与搭建 各种web开发业务中最为常用的key-value数据库了 应用: 在业务中用其存储用户登陆态(Session存储),加速一些热数据的查询(相比较mysql而言,速度 ...

  4. 细说分布式Redis架构设计和踩过的那些坑

    细说分布式Redis架构设计和踩过的那些坑_redis 分布式_ redis 分布式锁_分布式缓存redis 细说分布式Redis架构设计和踩过的那些坑

  5. Redis 高可用架构设计(转载)

    转载自:https://mp.weixin.qq.com/s?__biz=MzA3NDcyMTQyNQ==&mid=2649263292&idx=1&sn=b170390684 ...

  6. Redis的高并发、持久化、高可用架构设计

    就是如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,还有就是如何让Redis保证自己不是挂掉以后就直接死掉了,redis高可用 我这里会选用我之前讲解 ...

  7. 《【面试突击】— Redis篇》--Redis Cluster及缓存使用和架构设计的常见问题

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>--Redis Cluster及缓存使用和架构设计的 ...

  8. Redis初识、设计思想与一些学习资源推荐

    一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...

  9. Redis Cluster架构优化

    Redis Cluster架构优化 在<全面剖析Redis Cluster原理和应用>中,我们已经详细剖析了现阶段Redis Cluster的缺点: 无中心化架构 Gossip消息的开销 ...

随机推荐

  1. Linux分区和挂载(mount命令的学习)

    当Windows系统出现问题的时候,可能需要重装系统,这个时候我们往往会使用系统盘将系统重新安装在C盘上,其他盘上的文件都没有受到重装系统的影 响,这就是分区的好处之一.同样,在Linux中也需要分区 ...

  2. Hi3531 SDK v2.0.8.0 安装

    1.Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下,您可以看到一个 Hi3531_SDK_Vx.x.x.x.tgz ...

  3. WIN7 嵌入式系统安装教程 Windows Embedded Standard 2011 安装

    轻松构建你的第一个 Windows Embedded Standard 2011 镜像.通过本文你可以快速掌握如何使用Windows Embedded Standard 2011 CTP1 来构建一个 ...

  4. stm32开发之标准库的介绍

    1 STM32标准外设库概述 STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序.数据结构和宏组成,包括了微控制器所有外设的性能特征.该函数库还包括每一个外设的驱动描 ...

  5. R语言自动化报告格式——knitr

    R语言自动化报告格式--knitr 相关文献: R语言自动化报告格式--knitr 资讯 | R Notebooks 即将发布 ------------------------------------ ...

  6. 基于am3358的蜂鸣器测试

    #include <sys/ioctl.h> #include<stdio.h> #include <fcntl.h> #include <sys/types ...

  7. luogu【P3387】【模板】缩点

    原题入口 PS:这个题数据是由Hany01大大出出来的 %%% 这个题显然是一道强联通+DAGdp的题 (题目背景有= =) 缩点的原因就是:不缩会一直在一个地方绕圈圈 而且不能进行后面的DAPdp ...

  8. 【BZOJ1798】【AHOI2009】维护序列(线段树)

    题目链接 题解 这不就是luogu的线段树2的板子吗.... 没有任何的区别... 上代码吧... #include<iostream> #include<cstdio> #i ...

  9. 【Luogu3919】可持久化数组(主席树)

    题面戳我 题解 放一个板子在这里 用主席树维护一下每个版本就可以啦... #include<iostream> #include<cstdio> #include<cst ...

  10. 一个题目涉及到的50个Sql语句

    原博客地址 http://blog.csdn.net/maco_wang/article/details/6281484 Student(S#,Sname,Sage,Ssex) 学生表 Course( ...