宋增宽。腾讯project师。16年毕业增加腾讯,从事海量服务后台设计与研发工作,如今负责QQ群后台等项目。喜欢研究技术,并思考技术演变。专注于高并发业务架构的设计与性能优化。


阅读原文。本文由腾云阁授权公布,经社区同意后方可转载。

很多其它技术文章,请訪问腾云阁。


下半年利用空余时间研究和分析了部分Redis源代码。本文从网络模型、数据结构和内存管理、持久化和多机协作四个角度对redis的设计思路进行了分析。若有不对之处,希望各路大神指出。

Redis是业界普遍应用的缓存组件,研究一个组件框架。最直观的办法就是从应用方的角度出发,将每一个步骤的考虑一番,从这些步骤入手去研究往往可以最快的体会到一个组件框架的设计哲学。

以Redis为例,每当发起一条请求时,redis是怎样管理管理网络请求,收到请求后又是通过什么样的数据结构进行组织并操作内存,这些数据又是怎样dump到磁盘实现持久化,再到多机环境下怎样同步和保证一致性……本文就是从网络模型、数据结构设计与内存管理、持久化方法和多机四个角度简要描写叙述了redis的设计和自己的一点体会。

一.网络模型

Redis是典型的基于Reactor的事件驱动模型,单进程单线程,高效的框架总是相似的。网络模型与spp的异步模型差点儿一致。

Redis流程上总体分为接受请求处理器、响应处理器和应答处理器三个同步模块。每一个请求都是要经历这三个部分。

Redis集成了libevent/epoll/kqueue/select等多种事件管理机制,可以依据操作系统版本号自由选择合适的管理机制,当中libevent是最优选择的机制。

Redis的网络模型有着全部事件驱动模型的优点。高效低耗。

可是面对耗时较长的操作的时候,相同无法处理请求,仅仅能等到事件处理完成才干响应。之前在业务中也遇到过这种场景,删除redis中全量的key-value,整个操作时间较长,操作期间全部的请求都无法响应。

所以了解清楚网络模型有助于在业务中扬长避短,降低长耗时的请求,尽可能多一些简单的短耗时请求发挥异步模型的最大的威力。其实在Redis的设计中也多次体现这一点。

二.数据结构和内存管理

1.字符串

1.1 结构

Redis的字符串是对C语言原始字符串的二次封装。结构例如以下:

struct sdshdr {long len;long free;char buf[];
};

可以看出。每当定义一个字符串时,除了保存字符的空间。Redis还分配了额外的空间用于管理属性字段。

1.2 内存管理方式

动态内存管理方式,动态方式最大的优点就是可以较为充分的利用内存空间,降低内存碎片化,与此同一时候带来的劣势就是easy引起频繁的内存抖动,通常採用“空间预分配”和“惰性空间释放”两种优化策略来降低内存抖动,redis也不例外。

每次改动字符串内容时。首先检查内存空间是否符合要求。否则就扩大2倍或者按M增长;降低字符串内容时。内存并不会立马回收,而是按需回收。

关于内存管理的优化。最主要的出发点就是浪费一点空间还是牺牲一些时间的权衡,像STL、tcmalloc、protobuf3的arena机制等採用的核心思路都是“预分配迟回收”。Redis也是一样的。

1.3 二进制安全

推断字符串结束与否的标识是len字段,而不是C语言的’\0’,因此是二进制安全的。

放心的将pb序列化后的二进制字符串存入redis。

简而言之,通过redis的简单封装,redis的字符串的操作更加方便,性能更友好。而且屏蔽了C语言字符串的一些须要用户关心的问题。

2.字典(哈希)

字典的底层一定是hash。涉及到hash一定会涉及到hash算法、冲突的解决方法和hash表扩容和缩容。

2.1 hash算法

Redis使用的就是经常使用的Murmurhash2。Murmurhash算法可以给出在随意输入序列下的散列分布性。而且计算速度很快。之前做共享内存的Local-Cache的需求时也正是利用了Murmurhash的优势。攻克了原有结构的hash函数散列分布性差的问题。

2.2 hash冲突解决方法

链地址法解决hash冲突,通用解决方式没什么特殊的。多说一句。假设选用链地址解决冲突。那么势必要有一个散列性很好的hash函数。否则hash的性能将会大大折扣。Redis选用了Murmurhash,所以可以放心大胆的採用链地址方案。

2.3 hash扩容和缩容

维持hash表在一个合理的负载范围之内,简称为rehash过程。
rehash的过程也是一个权衡的过程。在做评估之前首先明白一点。无论中间採用什么样的rehash策略,rehash在宏观上看一定是:分配一个新的内存块。老数据搬到新的内存块上,释放旧内存块。

老数据何时搬?怎么搬?就变成了一个须要权衡的问题。
第一部分的网络模型上明白的指出Redis的事件驱动模型特点,不适合玩长耗时操作。假设一个hashtable很大。须要进行扩容就一次性把老数据copy过去。那就会很耗时,违背事件驱动的特点。

所以Redis依然採用了一种惰性的方案:
新空间分配完成后,启动rehashidx标识符表明rehash过程的開始。之后全部增删改查涉及的操作时都会将数据迁移到新空间,直到老空间数据大小为0表明数据已经全部在新空间,将rehashidx禁用,表明rehash结束。
将一次性的集中问题分而治之,在Redis的设计哲学中体现的淋漓尽致,主要是为了避免大耗时操作,影响Redis响应客户请求。

3.整数集合

变长整数存储,整数分为16/32/64三个变长尺度。依据存入的数据所属的类型,进行规划。
每次插入新元素都有可能导致尺度升级(比如由16位涨到32位),因此插入整数的时间复杂度为O(n)。这里也是一个权衡,内存空间和时间的一个折中,尽可能节省内存。

4.跳跃表

Redis的skilplist和普通的skiplist没什么不同。都是冗余数据实现的从粗到细的多层次链表,Redis中应用跳表的地方不多。常见的就是有序集合。

Redis的跳表和普通skiplist没有什么特殊之处。

5.链表

Redis的链表是双向非循环链表。拥有表头和表尾指针。对于首尾的操作时间复杂度是O(1),查找时间复杂度O(n)。插入时间复杂度O(1)。
Redis的链表和普通链表没有什么特殊之处。

三.AOF和RDB持久化

AOF持久化日志。RDB持久化实体数据。AOF优先级大于RDB。

1.AOF持久化

机制:通过定时事件将aof缓冲区内的数据定时写到磁盘上。

2.AOF重写

为了降低AOF大小,Redis提供了AOF重写功能,这个重写功能做的工作就是创建一个新AOF文件取代老的AOF,而且这个新的AOF文件没有一条冗余指令。(比如对list先插入A/B/C,后删除B/C,再插入D共6条指令,终于状态为A/D。仅仅需1条指令就行)
实现原理就是读现有数据库的状态,依据状态反推指令,跟之前的AOF无关。相同。为了避免长时间耗时,重写工作放在子进程进行。

3.RDB持久化

SAVE和BGSAVE两个命令都是用于生成RDB文件,差别在于BGSAVE会fork出一个子进程单独进行。不影响Redis处理正常请求。
定时和定次数后进行持久化操作。
简而言之,RDB的过程其实是比較简单的,满足条件后直接去写RDB文件就结束了。

四.多机和集群

1.主从server

避免单点是全部服务的通用问题,Redis也不例外。解决单点就要有备机。有备机就要解决固有的数据同步问题。

1.1 sync——原始版主从同步

Redis最初的同步做法是sync指令,通过sync每次都会全量数据,显然每次都全量复制的设计比較消耗资源。改进思路也是常规逻辑,第一次全量。剩下的增量。这就是如今的psync指令的活。

1.2 psync

部分重同步实现的技术手段是“偏移序号+积压缓冲区”,详细做法例如以下:
(1)主从分别维护一个seq。主每次完成一个请求便seq+1,从每同步完后更新自己seq;
(2)从每次打算同步时都是携带着自己的seq到主,主将自身的seq与从做差结果与积压缓冲区大小比較,假设小于积压缓冲区大小,直接从积压缓冲区取对应的操作进行部分重同步;
(3)否则说明积压缓冲区不可以cover掉主从不一致的数据,进行全量同步。

本质做法用空间换时间,显然在这里牺牲部分空间换回高效的部分重同步,收益比很大。

2.Sentinel

本质:多主从server的Redis系统,多台主从上加了管理监控,以保证系统高可用性。

3.集群

Redis的官方版集群尚未在工业界普及起来,以下主要介绍一下集群的管理体系和运转体系。

2.1 slot-集群单位

集群的数据区由slot组成。每一个节点负责的slot是在集群启动时分配的。

2.2 客户请求

客户请求时假设对应数据hash后不属于请求节点所管理的slots,会给客户返回MOVED错误。并给出正确的slots。
从这个层面看,redis的集群还不够友好,集群内部的状态必须由客户感知。

2.3 容灾

主从server,从用于备份主。一旦主故障。从取代主。

通过Redis的研究,深刻体会到的一点就是:全部设计的过程都是权衡和割舍的过程。

相同放到日常的工作和开发中也是如此,一句代码写的好不好,一个模块设计的是否科学,就从速度和内存的角度去衡量看是否须要优化。并去评估每一种优化会收益到什么,同一时候会损失什么。收益远大于损失的就是好的优化,这样往往对于开发和提升更有针对性,更能提高效率。


相关推荐

memcached与redis实现的对照

阅读原文,本文由腾云阁授权公布,经社区同意后方可转载。

很多其它技术文章。请訪问腾云阁。

Redis设计思路学习与总结相关推荐

  1. Redis入门指南(第2版) Redis设计思路学习与总结

    https://www.qcloud.com/community/article/222 宋增宽,腾讯工程师,16年毕业加入腾讯,从事海量服务后台设计与研发工作,现在负责QQ群后台等项目,喜欢研究技术 ...

  2. 自动化用例设计思路学习小记

  3. TF学习——Tensorflow框架之基础概念、设计思路、常用方法之详细攻略

    TF学习--tensorflow框架之基础概念.设计思路.常用方法之详细攻略 目录 Tensorflow框架基础概念 Tensorflow框架设计思路 Tensorflow框架常用方法 Tensorf ...

  4. DWZ富客户端框架设计思路与学习建议

    DWZ富客户端框架设计目标是简单实用.扩展方便灵活.快速开发.RIA思路.轻量级 设计思路 第一次打开页面时载入界面到客户端, 之后和服务器的交互只是数据交互, 不占用界面相关的网络流量. 支持HTM ...

  5. AQS与CLH相关论文学习系列(四)- AQS的设计思路

    本文是AQS与CLH相关论文学习系列第四篇. 系列其他文章链接如下 AQS与CLH相关论文学习系列(一)- 排队式自旋锁思想启蒙 AQS与CLH相关论文学习系列(二)- MCS 锁 AQS与CLH相关 ...

  6. 《Redis设计与实现》学习笔记

    Redis 本文会有一些Redis和Java容器对象的对比,一个是分布式数据库,一个是JVM内部数据容器,应用场景不同,仅仅是为了加深对Redis"数据库"的认识,加深对Redis ...

  7. 结合redis设计与实现的redis源码学习-2-SDS(简单动态字符串)

    上一次我们学习了redis的内存分配方式,今天我们来学习redis最基本的数据结构SDS,在redis的数据库里,包含字符产值的简直对在底层都是由SDS实现的. SDS的基本数据结构是sdshdr结构 ...

  8. HNU小学期计算机系统设计与创新基础训练——基于STC学习板的加密信息存储与游戏操作系统(第一部分设计思路+基础原理)

    HNU小学期计算机系统设计与创新基础训练--加密信息存储与游戏操作系统 一. 选题名称 二. 选题背景 三. 实现功能 1. 主要功能 2. 细节设计 四. 设计思路 五. 基本原理 1. 数码管与发 ...

  9. redis设计与实现学习笔记1

    文章目录 1.对象 1.1 类型 1.2 内存回收 1.3 对象共享 1.4 对象空转时长 2.单机数据库 2.1 RDB 2.2 AOF 2.3 事件 2.4客户端 2.5服务器 3.常用命令 参考 ...

  10. 消息中间件学习总结(5)——RocketMQ之Apache RocketMQ背后的设计思路与最佳实践

    摘要:为了更好地让开发者们更加深入了解阿里开源,阿里云云栖社区在3月1号了举办"阿里开源项目最佳实践"在线技术峰会,直播讲述了当前阿里新兴和经典开源项目实战经验以及背后的开发思路. ...

最新文章

  1. 交替最小二乘+ALS+推荐+Spark
  2. 《Netty权威指南》
  3. aws lambda_AWS Lambda事件源映射:使您的触发器混乱无序
  4. 借助波音公司打造优秀按单制造(MTO II)管理系统
  5. PHP两个匿名函数传递性,PHP让人不知道的匿名函数的几种写法(附代码)
  6. windows7卸载linux系统,win7下安全卸载linux系统
  7. c# string 转 datetime_利用swig封装C++的dll为C#方便使用
  8. jquery ajax select 二级联动
  9. OV7725学习(二)
  10. PHP抖音无水印解析视频代码+思路
  11. 【渝粤题库】陕西师范大学200091 东方文学专题研究 作业
  12. Java 定义一个 Employee类,定义方法输出Employee的名字,年龄,总收入。编写应用程序使用Employee
  13. CSS - 制作三角形
  14. 数据集加载的几种方法
  15. 洛谷 P1135 奇怪的电梯
  16. 介绍兴趣爱好的网页html,关于兴趣爱好的自我介绍
  17. 大数据晋级之路(5)Hadoop,Spark,Storm综合比较
  18. UnauthorizedAccessException:Access to the path “/xx/xx.xx“ is denied
  19. Python3网络爬虫,简单爬取网络小说并下载
  20. 智能聊天功能——天气情况篇

热门文章

  1. Atitit 艾提拉博士带来“深度?广度?高度 人员的职业发展之路 ”的主题分享。 目录 1.1. 技术团队气氛的区别 开发架构模式 2 1.2. 技术人员的职业发展有哪些路线? 3 1.3. 主
  2. Atitit. Api 设计 原则 ---归一化
  3. Atitit。Time base gc 垃圾 资源 收集的原理与设计
  4. paip.数据挖掘--导出词库 清理太长的iptcode
  5. paip.URL参数压缩64进制
  6. (转)ICO是区块链与生俱来的特性,是金融深化的终局
  7. Julia: 如何读出csv文件中的中文字符?
  8. 【图像融合】基于matlab高斯金字塔+拉普拉斯金字塔彩色水下图像融合【含Matlab源码 1629期】
  9. 毕设题目:Matlab图像融合
  10. 【TSP】基于matlab GUI混合粒子群算法求解旅行商问题【含Matlab源码 925期】