前言

学习本文之前先问大家一个问题,为什么要学习redis?不知道如何回答的朋友,请继续往下看!

总共总结为三点的内容,大家仔细斟酌一下:

1.Redis应用广泛,它有卓越的性能、丰富的数据类型,简洁高效的设计理念。

2.Redis 5带来了很多不错的新特性:

  • 增加了新的流数据类型
  • 更新了定时器、集群和字典相关的API
  • 增加了新的有序集合命令

3.要想做好日常开发和运维工作,需要对Redis的底层原理和实现,尤其是命令实现有一定了解。

 

Redis已经是IT企业技术栈中重要的一环,与其相关的从业者数量也逐年增多,对大多数人来说Redis可谓既熟悉又神秘,只有不足4MB的源码却实现了一个功能丰富且健壮的数据库。

Redis 以其高速、轻量和丰富的数据结构与功能被越来越多的工程师所钟爱。然而,用Redis 的人很多,真正懂Redis的人很少,本文正是写给那些使用了Redis并希望进一步深入理解Redis的读者。作者及其团队通过对Redis最新版本(5.x)各部分源码的分析,庖丁解牛,深入浅出,带领读者一步步探索Redis的方方面面,让读者从原理层面真正懂得Redis。

本文不仅深入源码讲解了Redis.常用的底层数据结构和常用命令处理的实际过程,还细致入微地讲述了基数计数算法的演进和HyperLogLog算法在Redis 中的具体实现,这是非常有用且难得的;

本文从源码层面对Redis进行深入剖析,尤其是数据结构部分,其学习意义不限于Redis,强烈推荐大家来阅读。

那,今天咱们就从目录、主要内容和总结三部分给大家进行介绍,希望大家能够好好学习,也希望本文能够得到大家的喜欢!!!

目录

 

主要内容

本文将用22章的内容给大家展开讲解Redis5设计、数据结构、底层命令实现,以及持久化、主从复制、集群的实现;

第1章,引言;Redis是目前最流行的键值对( key-value)数据库,以出色的性能著称,官方提供的数据是可以支持100 000以上的+QPS。Redis具有高性能的主要原因如下。

1 ) Redis是基于内存的存储数据库,绝大部分的命令处理只是纯粹的内存操作,内存的读写速度非常快。

2) Redis是单进程线程的服务(实际上一个正在运行的Redis Server肯定不止一个线程,但只有一个线程来处理网络请求),避免了不必要的上下文切换,同时不存在加锁/释放锁等同步操作。

3 ) Redis使用多路I/O复用模型(select、poll、epoll),可以高效处理大量并发连接。

4 ) Redis中的数据结构是专门设计的,增、删、改、查等操作相对简单。

本章主要介绍Redis简介、Redis 5.0的新特性、Redis源代码概念、Redis安装与调试,希望对读者阅读和研究Redis 源码有一定的帮助。

 

第2章,简单动态字符串;简单动态字符串(Simple Dynamic Strings,SDS)是Redis的基本数据结构之一,用于存储字符串和整型数据。SDS兼容C语言标准字符串处理函数,且在此基础上保证了二进制安全。本章将详细讲解SDS的实现,为读者理解Redis的原理和各种命令的实现打下基础。

 

第3章,跳跃表;有序集合在生活中较常见,如根据成绩对学生进行排名、根据得分对游戏玩家进行排名等。对于有序集合的底层实现,我们可以使用数组、链表、平衡树等结构。数组不便于元素的插入和删除;链表的查询效率低,需要遍历所有元素;平衡树或者红黑树等结构虽然效率高但实现复杂。Redis采用了一种新型的数据结构—―跳跃表。跳跃表的效率堪比红黑树,然而其实现却远比红黑树简单。

 

第4章,压缩列表;压缩列表ziplist本质上就是一个字节数组,是Redis为了节约内存而设计的一种线性数据结构,可以包含多个元素,每个元素可以是一个字节数组或一个整数。

Redis 的有序集合、散列和列表都直接或者间接使用了压缩列表。当有序集合或散列表的元素个数比较少,且元素都是短字符串时,Redis便使用压缩列表作为其底层数据存储结构。列表使用快速链表( quicklist)数据结构存储,而快速链表就是双向链表与压缩列表的组合。

例如,使用如下命令创建一个散列键并查看其编码。

127.0.0.1:6379> hmset person name zhangsan gender 1 age 22   
OK
127.0.0.1:6379> object encoding person
" ziplist"

本章将从源码层次详细介绍压缩列表的存储结构及基本操作。

 

第5章,字典;本章讲解了字典的基本概念,并对其实现进行深入解读,字典在Redis数据库中起到了举足轻重的作用,想必读者读完这章之后,对字典的概念及Redis数据库底层是如何存储数据都会有一个较为清晰的了解。请思考,在5.2.1节中介绍字典的基本实现中为什么Hash表数组中存放的是每个dictEntry 的指针地址,而不是直接把dictEntry嵌入到Hash表数组中去?

 

第6章,整数集合;整数集合(intset)是一个有序的、存储整型数据的结构。我们知道Redis是一个内存数据库,所以必须考虑如何能够高效地利用内存。当Redis集合类型的元素都是整数并且都处在64位有符号整数范围之内时,使用该结构体存储。

 

第7章,quicklist的实现;quicklist是Redis底层最重要的数据结构之一,它是Redis对外提供的6种基本数据结构中List的底层实现,在Redis 3.2版本中引入。在引入quicklist之前,Redis采用压缩链表(ziplist)以及双向链表( adlist)作为List的底层实现。当元素个数比较少并且元素长度比较小时,Redis采用ziplist作为其底层存储;当任意一个条件不满足时,Redis采用adlist作为底层存储结构。这么做的主要原因是,当元素长度较小时,采用ziplist可以有效节省存储空间,但ziplist的存储空间是连续的,当元素个数比较多时,修改元素时,必须重新分配存储空间,这无疑会影响Redis的执行效率,故而采用一般的双向链表。

quicklist是综合考虑了时间效率与空间效率引入的新型数据结构,本章将对其具体实现细节为读者——展现。

 

第8章,Stream;消息队列是分布式系统中不可缺少的组件之一,主要有异步处理、应用解耦、限流削峰的功能。目前应用较为广泛的消息队列有RabbitMQ、RocketMQ、Kafka等。Redis在最新的5.0.0版本中也加入了消息队列的功能,这就是Stream。本章将详细介绍Redis Stream相关的底层数据结构,帮助读者探索Stream实现的秘密。

 

第9章,命令处理生命周期;第2~8章介绍了Redis 的基本数据结构,接下来主要讲解所有命令的源码实现。在讲解命令实现之前,需要先了解一下服务器处理客户端命令请求的整个流程,包括服务器启动监听,接收命令请求并解析,执行命令请求,返回命令回复等,这也是本章的主题“命令处理的生命周期”。

Redis服务器是典型的事件驱动程序,因此事件处理显得尤为重要,而Redis将事件分为两大类:文件事件与时间事件。文件事件即socket的读写事件,时间事件用于处理一些需要周期性执行的定时任务,本章将对这两种事件作详细介绍。

 

第10章,相关命令的实现;在前面的章节里,我们主要讲了Redis常用的底层数据结构以及命令处理的生命周期,本章将介绍键相关命令的源码实现。命令实现的过程中不是直接操作这些数据结构,我们将在10.1节讲解这两个结构。

在理解了redisDb和redisObject对象之后,我们按照查看键信息、设置键信息、查找和操作键将本章命令进行分类讲解,10.2节讲解查看键信息相关命令,其中 object和 type命令是获取redisObject对象相关属性的操作,过期时间读取和修改相关命令是对redisDb的expires字典的操作,除此之外本章的命令都是对redisDb的dict字典的操作。

 

第11章,字符串相关命令的实现;字符串命令是Redis最常见的命令,相对其他命令来说,字符串命令操作简单,参数较少。字符串命令虽然简单但作用强大,我们可以用字符串命令实现key-value的设置与获取,也可以实现计数器功能,甚至可以实现位操作。

 

第12章,散列表相关命令的实现;散列表是Redis数据组织的基本结构。针对key-value中的value,Redis提供了6种结构——字符串(string)、散列表(Hash)、数据流(stream)、列表(list)、集合(set)、有序集合(sortedset)。针对不同的value结构,Redis提供了不同的命令供用户使用。

当value为散列结构时,我们称之为散列相关命令。为了与Redis中的key-value散列做区分,我们称value的散列结构的键值对为field-value(域值对)。

 

第13章,列表相关命令的实现;Redis列表对象的底层数据结构是quicklist,我们在第7章已经详细讲述了quicklist的数据结构以及常见操作,本章我们主要讲解如何使用quicklist实现列表相关的命令。

 

第14章,集合相关命令的实现;Redis的set实现了无序集合,集合成员唯一。set底层基于dict和intset,在学习集合命令前,需要先了解dict和intset的结构,详见相关章节的介绍。

 

第15章,有序集合相关命令的实现;在第14章中,主要讲解了集合(Set)相关的命令,集合是无序的,而本章主要介绍有序集合(SortedSet)相关命令的实现,包括基本操作,比如zadd/zrem/zscan等,批量的操作(zrange/zremrange),以及集合相关的操作(交集zinterstore和并集zunionstore)。

有序集合中,用到的关键数据结构是ziplist以及 dict和skiplist,当服务器属性server.zset_max_ziplist_entries的值大于0且元素的member长度小于服务器属性server.zset_max_ziplist_value的值(默认为64)时,使用的是ziplist,否则使用的是dict和skiplist。对于这三种数据结构,请参考第3、4和5章。

 

第16章,GEO相关命令;在生活中,位置信息十分重要,精确地对每个物体进行定位是我们进行其他相关操作的基础。Redis提供了一些命令来帮助我们有效地处理位置信息,比如计算两点间的距离,这类命令统称为GEO相关的命令,本节将详细介绍这类命令是如何实现的。

geohash算法在2008年公开,该算法可以把二维的经纬度信息降维到一维,并通过Base32编码将其转换为字符串。Ardb的作者提供了geohash-int的实现。Redis的核心开发者Matt借鉴Ardb的GEO功能,于2014年以module方式开发了Redis的GEO。2016年,在Redis 3.2中正式加入了GEO。本节主要学习geohash算法的实现,以及Redis中是如何使用该算法的。

 

第17章,HyperLogLog相关命令的实现;在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站PV (Page View,页面访问量)或者URL的访问次数,可以使用Redis提供的incr或incrby命令轻松实现,但像UV (Unique Visitor,独立访客)、独立IP数、搜索记录数等需要去重和计数的问题该如何解决呢?我们把这类求集合中不重复元素个数的问题称为基数计数。

解决基数计数有多种方法,简单来说,可以将数据存储在MySQL表中,使用distinctcount语句来计算不重复个数,也可以使用Redis提供的hash、set、bitmap等数据结构来处理,而且结果数据都非常精确,但是这些方法都会随着数据的不断增多,而导致占用的空间越来越大,对于非常大的数据集是不切实际的。那么是否能够降低一定的精度来平衡存储空间呢。有一类算法基于概率,仅使用常量和小量的内存来提供集合中唯一元素数量的近似值。

 

第18章,数据流相关命令的实现;Redis 5.0.0引入了Stream,本章主要介绍Stream相关命令的底层实现。

在Stream的实现中,用到的关键数据结构是rax、listpack。其中rax用于快速索引;listpack用于存储具体的消息,这些数据结构的详细介绍请参见第8章。

 

第19章,其他命令;该章节主要讲解事务命令、发布-订阅命令和Lua脚本命令3个部分。通过该章的学习,读者可以了解Redis中事务、发布–订阅的实现原理及其适用范围,以及Redis如何执行Lua脚本命令。

 

第20章,持久化;Redis是一个内存数据库,当机器重启之后内存中的数据都会丢失。所以对Redis来说,持久化显得尤为重要。Redis有两种持久化方式:一种为RDB方式,RDB保存某一个时间点之前的数据;另一种为AOF方式,AOF保存的是Redis 服务器端执行的每一条命令。两种方式各有优劣,在接下来的章节中会详细介绍。我们先通过在客户端输入info命令,查看Redis服务端记录的相关持久化状态信息,然后分别详细介绍RDB和AOF。

 

第21章,主从复制;Redis支持主从复制功能,用户可以通过执行slaveof命令或者在配置文件中设置slaveof选项来开启复制功能。例如,现在有两台服务器——127.0.0.1:6379和127.0.0.1:7000,向服务器127.0.0.1:6379发送下面命令:

127.0.0.1:6379>slaveof 127.0.0.1 7000
OK

此时服务器127.0.0.1:6379会成为服务器127.0.0.1:7000的从服务器(slaver),服务器127.0.0.1:7000会成为服务器127.0.0.1:6379的主服务器( master);通过复制功能,从服务器127.0.0.1:6379的数据可以和主服务器127.0.0.1:7000的数据保持同步。

本章将为读者详细介绍主从复制功能的源码实现。

 

第22章,哨兵和集群;哨兵是Redis 的高可用方案,可以在Redis Master发生故障时自动选择一个Redis Slave切换为Master,继续对外提供服务。集群提供数据自动分片到不同节点的功能,并且当部分节点失效后仍然可以使用。

本章首先介绍Redis哨兵的实现,然后介绍集群的实现。

 

这份【Redis5设计与源码分析】宝典总共有433页,需要完整版的朋友,可以转发此文关注小编,扫码来获取!!!

总结

本书讲了什么?

  • Redis架构与源码设计
  • Redis数据结构与命令实现
  • 业务所需关键实现解读

你能得到什么?

  • 吸收设计精髓,提升技术素养
  • 理解设计,获得更好的性能
  • 掌握源码,更好、更快排障
  • 更远一点,设计自己的分布式缓存数据库

本文从底层源码的角度,对Redis的数据结构以及持久化、主从复制、哨兵和集群等特性的实现原理进行了详尽的剖析,图文并茂。行文中也能看出作者团队在源码分析和系统编程方面的功力,我相信本文对于所有想要了解Redis及其内部实现的人来说都会有所帮助。

还有对技术有点追求的程序员一定不要错过本Redis5源码分析宝典,本文对Redis的内部实现分析得非常全面透彻,如果你觉得直接阅读源码有点吃力,试试让本文来带领你探索Redis 源码。

希望本文能够帮助到大家的学习,让大家得以提升自己的技术深度和宽度,让自己变得更加有价值,也希望本文能够得到大家的喜欢!!!