本书以由浅入深、由原理到应用场景的方式介绍了Redis 这款NoSQL 数据库产品。书中不仅细致地讲解了Redis 中的数据结构及流行的使用模式,还针对Redis 键的设计和管理,以及内存管理提出了建设性的方案。同时,作者深入Redis 源码,将其内部构造通过源代码调试的方式进行呈现。
本书适合有一定NoSQL 经验的开发者或者架构师阅读。读者可以从书中找到许多应用场景和解决方案,例如Docker 部署、Redis 消息队列、基于Redis 的ETL 应用和基于Redis 的机器学习等。
面向DevOps的实用指南 基于3.2新版 ElasticSearch|MongoDB组合应用 Docker容器化范式 集群|Sentine扩展
译者序
对不少互联网企业来说,使用LNMP 架构可以快速搭建起一套系统,产品可以迅速迭代并尽早投放市场。但随着访问量的上升,那些使用传统关系型数据库(例如MySQL)的网站开始显现出性能方面的问题。此外,越来越挑剔的用户也要求网站不能仅专注于功能特性,同时也要追求极致的产品体验(即高性能和高可用)。
一方面,架构师会在数据库层面做以下一系列优化。
1.配置主从
例如。为MySQL 服务器配置主从。一台宕机,另一台可以顶上继续服务,以满足高可用的要求。
2.读写分离
配置一主多从。因为一般系统80%的请求都是读取操作,将这些操作分发到从服务器上可以有效地提升网站响应速度。
3.分库分表
随着数据量的增长,单库单表已经难以满足要求。一些诸如TDDL、Cobar、MyCAT等的MySQL 分布式数据库中间件应运而生。
另一方面,架构师也会通过系统化的分析,以安插缓存层的方式缓解数据库的压力。对应用系统来说,缓存都应在设计之初就纳入考虑的范畴,成为系统不可或缺的一部分。我曾供职的一家公司就采用Redis 作为缓存的实现方案。应用程序运行在两个同等的Tomcat容器里。Tomcat 之前则配置了一台Nginx 用于Load Balance。由于用户Session 存储在Redis中(通过Spring 和Shiro 的简单配置即可实现),应用的无状态性使得系统可以很方便地进行水平扩缩。另外,我们的业务要求用户每次浏览某个项目页面时进行访问计数(counting)。
为了避免频繁的数据库读写,我们将每个项目的浏览量的计算和读取交给了Redis。同时,为了避免意外导致的数据丢失,我们开启了Redis 的持久化功能,并启动定时任务,每隔一段时间就将项目浏览次数同步到数据库中。
至于为何选择Redis 而没有选择Memcached,当时考虑的主要原因是Redis 支持更为丰富的数据模型。像上述页面访问量计数的需求,可以直接通过Redis 的命令进行操作,而且利用Redis 的单线程模型,应用程序无须编写同步代码。当然,缓存只是Redis 的其中一个用途。一些典型的场景还包括排行榜、用户访问量统计、集合运算、消息队列等。国内外的一些大型互联网企业(例如京东、新浪、Pinterest 等)都对Redis 有不同程度的部署和应用。希望读者能够在本书中找到自己想要的答案。
每次翻译都带给我不同的体验,并为我的工作和生活带来改变。在此,我要感谢电子工业出版社的编辑张春雨和负责审校的同事,是你们的细心指导保证了本书的翻译质量。
同时,感谢我的父母和我的太太,在你们的陪伴和支持下,我得以专心工作。
由于时间仓促,文中难免有所疏漏,望不吝斧正。
汪佳南
前言
本书旨在从两方面为读者构建Redis 的基础知识。一方面,本书提供了Redis 及其技术背后的深层含义及理论;另一方面,拓展了Redis 日常实用技能。本书书名中的精通(Mastering)二字暗示了精通Redis 是一个持续的过程,而非最终目的地。激动人心的是Redis 持续开放地演进成为了时下强大的数据操作和存储技术。
Redis 背后的设计哲学
在整个项目的生命周期中,Salvatore Sanfilippo 对Redis 的发展方向与功能发表了独到的观点和见解。在2015 年1 月的一篇有关Redis 对比其他数据库的基准测试的博客中,
Sanfilippo 声明“我不想说服开发者们采用Redis。我们只是尽力提供一款合适的产品。如果人们能够使用这款产品完成工作,我们会感到非常开心。这就是我的营销理念。”
Sanfilippo 和他的Redis 核心开发团队遵循着成功的开源管理模型:“仁慈独裁者”(BDL)
模型。该模型中只能有单独一个人作为最终独裁者,来裁决哪些能被提交到Redis 代码库中。BDL 模型的成功已经被诸如Linux 内核开发和Python 编程语言等项目证明过了。作为主要开发者和维护者的Sanfilippo 成功地将BDL 模型复制到了Redis 中。
如果独裁者抛弃项目,或者更糟的是因病或者死亡而导致无法工作时,BDL 模型的失效将是灾难性的。Redis 浮现出来的另一个重大问题是当潜在的贡献者提交Pull Request 时,针对这些提交的行动会被延迟,或者更多时候是被忽略。说句公道话,那些必须经过检查、测试并合并到主代码库上的变更的数量非常巨大,需要激情和专门的看门人。作为Linux内核项目的初创者及当前的BDL,Linus Torvalds 已经看到自己的角色发生了转变,更多是在合并那些由其他开发者贡献的代码,同时相比亲自编写代码,他做的更多的是为Linux提供愿景和领导力。Sanfilippo 在Redis 主要的电子邮件通信上的一篇主题帖中确认了该问题,他给出了以下两大主要理由来继续Redis 当前的BDL 模型:
? 项目开发与未来方向的一致性视角
? 对任何新的或者出现的更改采取问责制
在Sanfilippo 看来,Redis 作为键值数据存储,其易于部署、内存占用少(就Redis 本身来说,而不是指它的数据集!)、安全可靠等特性一直是Redis 在开发者和组织中人气持续上升的关键因素。他的观点确实造成了紧张的关系,特别是当提出Redis 的新功能,例如使哈希中具体子值(sub-values)过期,或者为可选功能提供可加载模块时,这些特性都被拒之门外。Sanfilippo 对于保持Redis 的小巧并专注于使其成为内存数据库的渴望,推动发展,在2011 年的博客中,他用有关Redis 和Redis 开发过程的七条宣言阐明了他的观点,简述如下。
1.用于抽象数据类型的DSL。Redis 是一门领域特定语言(DSL),用于抽象数据结构的表达和使用。这些数据结构不仅包括了操作(Redis 命令),还包括了使用Redis 相关命令存储和操作这些数据结构的内存效率和时间复杂度。
2.内存存储是第一要务。通过将所有数据存储在计算机内存中,跨系统的Redis 的性能更为一致,用于实现这些数据结构的众多算法以更为可预测的方式运行,同时诸如有序集合这样的更为复杂的数据类型在内存数据库中更容易实现。
3.基础数据结构对应基础API。Redis 为基础数据结构实现了一套基础API。这套API由Redis 命令和对应的数据结构组成。它尝试清晰地反映API 从计算机内存中读取和写入的数据结构。Redis 遵循这一设计理念,通过更简单的数据结构操作来组合实现更为复杂的操作。
4.代码如诗。这是所有七条宣言之中最难以渗透的。Sanfilippo 将他的审美偏好融入到代码之中以契合Redis 这一长篇巨著。他认为Redis 的编码风格和方法能够帮助人们书写一段叙述。因此,是否包含第三方代码部分取决于它能否很好地契合Redis 的叙述和Redis的源代码。
5.我们反对复杂。避免代码复杂性。如果要在使用大量代码来实现小型功能与舍弃该功能之间做出选择的话,那么Redis 会选择后者,以舍弃额外的复杂性和向代码库中添加复杂性所带来的开销。
6.两层API。一套是API 的子集,以分布式的方式运行;另一套更大型、功能更为丰富,用来支持多键操作。这种分离设计支持像Redis 主从和Redis 集群操作模式这样重要的功能。
7.我们以优化为乐。通常对于开发者和技术运营者来说,这是一种情感诉求,也是一段非常聪明的声明。调优技术来解决疑难杂症所带来的刺激能够激起快乐的感觉及对Redis未来无限可能的兴奋。
本书涵盖内容
阅读本书时你会发现其贯穿着两大主题,以平行的方式展示了流行时尚的运营和过程的开发/运营二元论,即众所周知的DevOps。为了有助于读者更有针对性地学习章节中包含的内容,每个章节的主题会被归类为软件开发或者系统运营。由于两者之间的边界越来越模糊,对每个趋势中主题的深刻理解能够增强你和你团队的能力,以便快速高效地为项目开发和部署Redis 解决方案,或者将Redis 作为技术基础设施需求的一部分。
第1 章介绍了由Redis 之父和主要维护者Salvatore Sanfilippo 所阐明的Redis 开发哲学。
第2 章通过详细阐述和解释Redis 数据结构和键管理为读者构建起Redis 的基础知识,其中包括了如何为应用程序构造既有意义又有表达力的键模式这一重要主题。
第3 章讲解了Redis 提供的用来优化应用程序内存使用的各种选项,其中包括了Redis支持的基于最近较少使用(LRU)的各种缓存和Redis 中的键驱逐(evict)策略。
第4 章是有关应用程序编程的高级主题。本章从概述Redis 核心的C 语言实现开始,通过对精心挑选的C 代码片段进行深入地讲解来加深你对Redis 的理解。然后讲到了如何使用三种不同的Redis 客户端,并展示了分别使用Python、Node.js 和Haskell 的编程示例。第5 章是有关应用程序编程的高级主题。本章从概述Redis 服务器端Lua 脚本及如何在Redis 中更高效地使用Lua 开始讲起。之后,拓展讲解了一些流行的Redis 编程设计模式,列举了几个具体实例,描述了不同的个体和公司在运营操作中是如何使用这些模式的。本章最后从软件开发者的角度描述了Redis 是如何应用于典型的DevOps 场景中。
第6 章探索了两个最近添加到Redis 中的Redis 集群和Redis Sentinel。Redis Sentinel是一种特殊的高可用模式,用来监控主从服务器的健康状况,并能够在任意Redis 主从实例故障时进行切换。之前提到的Redis 集群现在可用于产品环境中了。对于那些太大而不能存入单台机器的大型数据来说,Redis 集群能够通过运行多个实例并将键进行分片的方式来完成存储。虽然这些主题更关注运营方面,但是在采用Redis 的工程解决方案时至少应该知道Redis 群集的好处和局限性。
第7 章一开始就承认了一件事,那就是对绝大多数组织来说,它们的信息技术栈包含了不同类型的数据和处理解决方案的异构混合。Redis 是一种用来扩展其他NoSQL 数据存储选项的理想方式。同时,在本章中,我们将看到Redis 是如何与MongoDB、ElasticSearch和Fedora Digital Repository 一起使用的。那些需要使用多种解决方案来开发并支持复杂业务需求的开发者和系统管理员会对本章的内容感兴趣。
第8 章介绍了如何通过在Docker 容器和镜像中使用Redis 的方式来简化管理并提升基于Redis 的解决方案的安全性和可靠性。Docker 是一种开源容器技术,正快速地被许多企业采用。在那之后我们将研究在最为流行的计算云供应商上使用Redis 所面临的具体挑战,这些供应商包括最大、最为成熟的Amazon Web Services、Google 的Compute Engine 和Microsoft Azure,并特别提到了其他云服务供应商,例如Rackspace 和Digital Ocean。本章最后会研究专门用于Redis 的云服务。这些云服务专注于托管和管理Redis 实例。
第9 章一开始深入探索了Redis 的发布/订阅命令。首先通过不同的示例展示了不同进程间、不同程序间、不同的Redis 客户端、不同的操作系统,以及远程计算机上的发布者和消费者是如何进行通信的。之后,将拓展Redis 的发布/订阅模式,并简要介绍将Redis用作企业计算生态中不同层之间的消息通信队列。本章最后会通过使用Redis 和Celery 作为任务管理和支持发布/订阅模式的消息通信队列这一详细示例总结提到的所有概念。
第10 章在前面章节的基础上展示了Redis 作为实时数据聚合器是如何将组织中来自各种技术系统的不同数据流聚合起来的。之后,将研究Redis 安全模型和最新Redis 版本新加入的安全特性。还有一款基于Web 的运营仪表板将采用我们关于Redis 客户端的知识,将输入到Redis 中的数据进行可视化。接下来,将展示如何将机器学习算法(如朴素贝叶斯)应用到这些基于Redis 的信息流,以提供更为丰富的概况,并加深你对组织或者部门内发生的操作的理解。
在附录的来源部分确认了章节中用到的摘录来源,并提供了链接以便读者进一步阅读。
获得精通Redis 开放式徽章
Mozilla 基金会是赞助Firefox 浏览器开发的开源组织,它启动了一项名为开放式徽章(Open Badges)的项目,允许组织创建并向个人颁发便携式和通用的徽章,以示其成就。在本书网站上,你可以通过一系列在线测试获得精通Redis 开放式徽章,并有机会向你当前或者将来的雇主传达你对Redis 日益增长的知识与技能。开放式徽章可以通过诸如Facebook、Twitter 或者LinkedIn 等流行的社交网站进行分享。
精通Redis 开放式徽章对于购买了本书的读者来说是免费的。而对于那些没有购买的读者来说,仍然可以在本书网站上支付一些象征性的费用来获得精通Redis 开放式徽章。
你有机会与其他徽章获得者建立联系,从他们的经验中学习Redis,同时可以分享自己的故事和知识,因此能够在阅读完本书之后的很长一段时间里鼓励你学习。我们希望本书能够马上帮助你理解Redis,你能够通过获得开放式徽章记录这项专业成就。
需要为本书准备什么
Redis 设计用于在(诸如拥有现代C++编译器)的Linux 或者Mac OX 等基于POSIX的环境下运行。当然,也有Microsoft Windows 版本的Redis,但是它并不受官方支持。更多信息请查看http://redis.io/download 上有关Windows 的这一节。本书中的示例使用了Python3.5,以及Redis 的Python 客户端(https://github.com/andymccurdy/redis-py)、Lua 和Node.js,以及Redis 的Node.js 客户端(https://github.com/NodeRedis/node_redis)。
目标读者
如果你是一位Web 开发者,对MEAN 栈有基本的理解,有过JavaScript 应用程序的开发经验,并且对NoSQL 数据库也有基本的使用经验,那么本书就是为你而写的。
排版约定
你会发现本书采用了多种文本样式来区分不同种类的信息。下面是这些样式的一些示例和对应含义解释。文本中的代码、数据库表名称、文件夹名称、文件名、文件扩展名、路径名、虚拟URL、用户输入和Twitter handle 如下所示:“首先,在对键使用EXPIRE 命令设置超时时,只有当删除或者替换该键时超时才会被清除。”