当前位置:首页 > 物联网 > 《物联网技术》杂志
[导读]摘 要:Redis是一款开源的、网络化的、基于内存的、可进行数据持久化的Key-Value存储系统。详细介绍了redis数据库底层数据结构、数据库的持久化方式、数据库事务特性以及隐藏在设计之中的一些考量。阐明了Redis高效性的原因在于其精简高效的底层数据结构设计以及对具有高消耗的功能进行分散处理。

引 言

随着互联网的发展以及Web 2.0 的兴起,超大规模以及高并发的纯动态型网站日渐成为主流,由于SNS 类网站在数据存取过程中有着实时性等刚性需求的原因,致使关系型数据库越来越不足以胜任,这使得目前 NoSQL 数据库慢慢成了人们所关注的焦点,并大有成为取代关系型数据库而成为未来主流数据存储模式的趋势。当前 NoSQL 数据库很多,大部分都是开源的,其中比较知名的有:MemcacheDB、Redis、Tokyo Cabinet、Flare、MongoDB、CouchDB、Cassandra、Voldemort 等。本文主要介绍 Redis,这是一款足以满足海量读写需求基于Key-Value 数据存储方式的高性能 NoSQL 数据库。

1 Redis简介

Redis 是一款开源的、网络化的、基于内存的、可进行数据持久化的Key-Value 存储系统。它的数据模型建立在外层,类似于其它结构化存储系统,是通过Key 映射Value 的方式来建立字典以保存数据,有别于其它结构化存储系统的是,它支持多类型存储,包括 String、List、Set、Sort set 和 Hash 等,你可以在这些数据类型上做很多原子性操作。

在操作方面,Redis 基于TCP 协议的特性使得它可以通过管道的方式进行数据操作,Redis 本身提供了一个可连接Server 的客户端,通过客户端,可方便地进行数据存取操作。

2 Redis底层数据结构中的两种 :字符串和字典

在Redis 的内部,数据结构类型值由高效的数据结构和算法进行支持,并且在 Redis 自身的构建当中,也大量用到了这些数据结构。

2.1 字符串

SDS(Simple Dynamic String, 简单动态字符串) 是Redis 底层所使用的字符串表示,几乎所有的Redis 模块中都用了SDS。用SDS 取代C 默认的char* 类型。

因为char* 类型的功能单一,抽象层次低,并且不能高效地支持一些Redis 常用的操作,所以在Redis 程序内部,绝大部分情况下都会使用SDS 而不是 char* 来表示字符串。

在C 语言中,字符串可以用一个 \0 结尾的char 数组来表示。但是,它并不能高效地支持长度计算和追加这两种操作:

(1) 计算字符串长度的复杂度为 θ(N)。

(2) 对字符串进行 N次追加,必定需要对字符串进行 N次内存重分配。

在Redis 内部,字符串的追加和长度计算很常见,这两个简单的操作不应该成为性能的瓶颈。

另外,Redis 除了处理 C 字符串之外,还需要处理单纯的字节数组,以及服务器协议等内容,所以为了方便起见, Redis 的字符串表示还应该是二进制安全的 :程序不应对字符串里面保存的数据做任何假设,数据可以是以\0 结尾的C 字符串,也可以是单纯的字节数组,或者其他格式的数据。

考虑到这两个原因,Redis 使用SDS 类型替换了C 语言的默认字符串表示 :SDS 既可高效地实现追加和长度计算, 同时是二进制安全的。

值得一提的是,在 Redis 最初的设计中就加入了统计信息: 

在设计 SDS 的时候,在内部使用了zmalloc 与zfree 来动态使用内存,并记录占有内存大小,方便计算 Redis 的性能。

2.2 字典

实现字典的方法有很多种 :为了兼顾高效和简单性, Redis 使用了哈希表。在实现哈希表时,有一个问题就是采用何种策略来解决碰撞问题。对于使用链地址法来解决碰撞问题的哈希表来说,哈希表的性能取决于哈希表大小与保存节点数量之间的比率:

(1) 哈希表的大小与节点数量,比率在 1 :1 时,哈希表的性能最好;

(2) 如果节点数量比哈希表的大小要大很多的话,那么哈希表就会退化成多个链表,哈希表本身的性能优势便不复存在;

Redis 保证当上述比率达到一定值时,会执行 rehash 操作,即对哈希表进行扩容或缩减。当扩容时,是以空间换取时间,当缩减时是以时间换空间。由此可以看出Redis 对时间和空间的高效利用率。当然,rehash 操作一般是渐进方式执行的。因为其中涉及到对整个哈希表的迁移,如果数据量很大, 那么势必会影响系统的性能。

Redis 使用了两种渐进式的rehash 方式:

(1) 每次执行一次添加、查找、删除操作,rehash都会被执行一次;

(2) 当Redis的服务器常规任务执行时,rehash会被执行。在规定的时间内,尽可能地对数据库字典中那些需要rehash 的字典进行 rehash,从而加速数据库字典的rehash 进程。

3 Redis的持久化方式 :RDB与AOF

在运行情况下,Redis 以数据结构的形式将数据维持在内存中,为了让这些数据在Redis 重启之后仍然可用,Redis 分别提供了RDB 和AOF 两种持久化模式。

RDB 将数据库的快照以二进制的方式保存到磁盘中。在Redis 运行时,RDB 程序将当前内存中的数据库快照保存到磁盘文件中, 在 Redis 重启动时,RDB 程序可以通过载入RDB 文件来还原数据库的状态。

AOF 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件,以此达到记录数据库状态的目的。AOF 更像是历史记录,记录所有运行过的命令。但是AOF 文件就会随着时间持续增长,进而占据整个磁盘。为此,Redis 设计了AOF 重写机制,通过开启新线程,扫描数据库数据,将其转化为Redis 命令,存入临时的AOF 文件。当扫描完后,用临时文件代替AOF 文件。这样一来,AOF 文件中记录的命令就是最简洁的,因而不会占据很多空间。

4 Redis事务

4.1 一致性

Redis 的一致性问题可以分为两部分来讨论 :入队错误、执行错误。

在命令入队的过程中,如果客户端向服务器发送了错误的命令,Redis 会拒绝执行事务,并返回失败信息。如果命令在事务执行的过程中发生错误,那么Redis 只会将错误包含在事务的结果中,这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响。

4.2 隔离性

Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。

4.3 原子性

在上述一致性的介绍中,可以看出在事务队列中,即使有命令执行错误,该事务也会执行完,符合原子性的要求。

4.4 持久性

因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由Redis 所使用的持久化模式决定:

在单纯的内存模式下,事务肯定是不持久的 ;

在RDB 模式下,服务器可能在事务执行之后、RDB 文件更新之前的这段时间失败,所以 RDB 模式下的Redis 事务也是不持久的;

在AOF 的“总是 SYNC”模式下,事务的每条命令在执行成功之后,都会立即调用 fsync 或 fdatasync 将事务数据写入到AOF 文件。但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的;

其他 AOF 模式也和“总是 SYNC”模式类似,所以它们都是不持久的;

综上所述,Redis 事务满足原子性、一致性、隔离性,不满足持久性。

结 语

本文详细介绍了 Redis 数据库数据结构、事务、持久化等特性,为读者深入理解 Redis 提供了帮助。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭