1.3.6 Redis

Redis是NoSQL类型的内存数据库,最初是由意大利的Salvatore Sanfilippo在2006年用C语言编写,之后得到了VMware和Pivotal的资助。Redis是REmote DIctionary Server的缩写,正如其名字所示,Redis的主要用途是内存中的快速信息检索。Redis是最流行的键值数据库之一,在Stack Overflow网站的调查中,Redis在2017到2020年连续4年位居开发者最喜爱的数据库榜首。典型的Redis应用场景包括高性能数据缓存、游戏排行榜、消息发布和订阅、流式数据处理、实时数据分析、物联网高速数据摄入等。Redis提供免费的开源版本,也提供功能增强的商用版Redis Enterprise。Redis支持在本地部署,也可以在Azure、Google和AWS上以云服务形式提供。

和前面介绍的商用数据库不同,除了内存中运行的高性能外,Redis还支持丰富的数据类型和算法,如Strings、Hashes、Lists、Sets、Sorted Sets、Bitmaps和HyperLogLogs。这是Redis非常重要的特性,只有理解和选择适合的数据类型,才能设计出更好的应用。例如Strings类型除了可以表示整型、浮点型、字符串和位图外,还可以存放XML、JSON、HTML等文本。Lists可用来表示队列、堆栈和集合。HyperLogLogs作为一种常用的算法,可以估算出集合中唯一元素的数量,计算速度快,消耗内存少。这些算法和数据结构可以与互联网应用紧密结合,因此Redis也被称为数据结构服务器。在灵活的数据类型基础上,Redis也着力于将自身打造为多模数据库,以减少跨模式数据开发、集成和运维的成本。Redis通过动态添加模块的方式来支持这些新的模式,包括RediSearch对全文搜索的支持、RedisJSON存储和查询JSON文档、RedisGraph对Graph数据结构的支持、RedisTimeSeries对时序数据的支持,以及RedisAI对人工智能的支持。

Redis是单线程的,这点非常重要,在任何时候Redis只会执行一个命令,因此Redis在执行事务的中途是不可能同时执行其他事务的,这也保证了Redis事务的原子性和隔离性,不会出现并发访问冲突和数据一致性问题。

作为开源软件,Redis支持的开发语言比商业软件丰富,除了常用的C、C++、C#、Java,还支持Node.js、Ruby、Perl、R、Perl等近50种开发语言。从Redis 2.6版本开始,在服务器端也支持执行Lua脚本。

内存是临时的易失性存储,为防止数据丢失,Redis提供了两种持久化的方法:RDB(Redis DataBase)和AOF(Append-Only File),两种方法可独立或结合使用。RDB类似于SAP HANA的Savepoint或TimesTen的检查点文件,定期生成Redis实例的时间点快照,单个RDB文件即可用来恢复数据库。AOF采用类似于日志的机制,所有的操作都以追加的方式记录在日志文件中,在Redis重新加载时,通过重演这些日志即可实现数据库恢复。

RDB非常适合于备份,例如每小时、每天、每月一次的备份,然后可以按时间点恢复,RDB也支持压缩,可以方便地传输到远端或公有云上实现灾备。在数据量较大时,RDB的恢复速度比AOF更快。由于快照比较消耗资源,因此生成快照的频率不能过高,这也使得RDB不太适合于RPO(恢复点目标)较小的情形。AOF采用追加的方式记录日志,记日志的频度可以低至秒级,因此效率非常高,对系统影响小,并大大降低了数据丢失的可能性。AOF以原始格式记录了所有的操作,更易于理解和解析,不过对于同样的操作集,AOF文件通常比RDB要大。为保证Redis的最高可用性和最少数据丢失,最佳建议是结合使用RDB和AOF两种方式,以同时保证粗粒度和细粒度的数据恢复。

复制被广泛用于提高读扩展性,这样所有的副本可以处理读,而主数据库只需处理写。复制还可以通过数据冗余实现数据保护。如图1-8所示,Redis支持主从复制和双活复制。主从复制支持一个主数据库复制到多个从数据库,也支持从数据库的级联复制。Redis双活复制使用CRDT(无冲突复制数据类型)技术实现了地理分布的双活应用,使得两个站点都可以实现本地读写,并保持数据的最终一致性。

图1-8 Redis的复制与扩展

Redis最初被设计运行在单机上,但单机的内存和能力有限,可能无法容纳所有数据和应对更高的并发访问,此时可以通过分片来实现数据容量和处理能力的扩展。最初的分片方案是通过客户端或第三方的分片中间件来实现的,例如Twitter在2012年发布的工具twemproxy,也称为nutcracker,可以实现哈希等分片算法,并可以在增加节点时自动实现数据重新分片。2015年,Redis在3.0版本推出了服务器端的分片方案:Redis Cluster。Redis Cluster可以将数据自动分布到多个节点,同时通过为主节点配置1到多个从节点,可以提供一定程度的可用性保护。如图1-8中间部分,当服务器3故障时,服务器1上的从数据库S3升级为主数据库M3,保证了整个集群的数据完整和业务连续。Redis Cluster内部提供主从数据复制保护,但本质上还是一个用于线性扩展的数据分片方案。

Redis官方的高可用方案为Redis Sentinel,可实现Redis节点的故障自动切换。Redis Sentinel是一个分布式系统,目标是提供可靠的主从自动切换,在主节点失效时,可以自动将从节点升级为主节点,在Sentinel出现之前,这些都需要手工处理。但Sentinel不能分布数据,主节点必须具有所有数据,而其他都是副本。Sentinel是一个独立的进程,在指定的端口监听。Sentinel进程间相互保持通信,同时Sentinel可以监控所有的Redis实例。Sentinal相当于连接代理,监控后端Redis实例的健康状态,因此客户端需要首先连接到Sentinel进程,然后根据配置转发到相应Redis实例。


(1) http://www.intel.com/pressroom/archive/speeches/ag021500.htm.

(2) http://www.oracle.com/us/corporate/analystreports/forrester-imdb-wave-2017-3616348.pdf

(3) https://www.forrester.com/report/The+Forrester+Wave+InMemory+Data+Grids+Q3+2015/-/E-RES120420