读构建可扩展分布式系统:方法与实践12分布式数据库案例
1. Redis
1.1. 2009年首次发布
- 1.1.1. 更注重原始性能和简单性,而不是数据安全性和一致性
1.2. 主要吸引力在于它能够同时充当分布式缓存和数据存储
1.3. 维护一个内存中的数据存储,也称为数据结构存储(data structure store)
1.4. 配置Redis将每个命令记录到一个只能追加的文件(Append-Only File,AOF)中
1.5. 数据模型和API
-
1.5.1. Redis是一个键值存储
-
1.5.2. 提供了一小部分数据结构,应用程序可以使用它们来创建与唯一键关联的数据对象
-
1.5.3. 字符串
-
1.5.3.1. 能够存储最大长度为512 MB的文本和二进制数据
-
1.5.4. 链表
-
1.5.4.1. 链表(linked list)是字符串列表,允许操作列表头部、尾部和主体中的元素
-
1.5.5. 集合和有序集合
-
1.5.5.1. 集合(set)是一系列唯一的字符串类型元素的集合
-
1.5.5.2. 有序集合(scored set)将分数(score)值与每个元素相关联,并按分数升序维护字符串
-
1.5.6. 哈希
-
1.5.6.1. Redis哈希(hash)将字符串的键值映射到一个或多个字符串值
1.6. 数据分发和复制
-
1.6.1. 在初始版本中,Redis是一个单服务器的数据存储,这在一定程度上限制了它的可扩展性
-
1.6.2. 2015年,随着Redis Cluster发布,它支持跨多个节点对数据存储进行分区和复制
-
1.6.3. Redis Cluster为一个集群定义了16384个哈希槽
-
1.6.4. 客户端可以连接到集群中的任意节点,并提交命令来操作指定的键
-
1.6.5. Redis不具备对驻留在不同哈希槽和不同节点中的对象执行命令的能力
1.7. 优缺点分析
-
1.7.1. 性能
-
1.7.1.1. Redis专为低延迟响应和高吞吐量而设计
-
1.7.1.2. 主要的数据存储是内存,可实现快速数据对象访问
-
1.7.2. 数据安全性
-
1.7.2.1. Redis以数据安全性换取性能
-
1.7.2.2. 如果应用程序不能接受数据丢失,你可能不会使用Redis(或任何内存数据库)作为主要的数据存储
-
1.7.3. 可扩展性
-
1.7.3.1. Redis Cluster是Redis的主要扩展机制
-
1.7.3.2. 允许多达1000个节点来托管跨16384个哈希槽分布的分片数据库
-
1.7.4. 一致性
-
1.7.4.1. Redis的副本是异步复制的,提供了最终一致性
-
1.7.5. 可用性
-
1.7.5.1. Redis Cluster为单个数据库分片实现了一个久经考验的主副本架构
2. MongoDB
2.1. 2009年首次发布
-
2.1.1. 早期版本中的底层存储引擎,称为MMAPv1
-
2.1.2. 具有更丰富的功能集,适用于需要适应未来增长的广泛业务应用程序
-
2.1.3. 最初流行起来是因为它易于编程和使用
2.2. 在本质上协调数据库模型与对象模型,直接解决了众所周知的对象关系阻抗不匹配问题
2.3. 2015年前后,开发团队对MongoDB进行了重新设计,支持可插拔的存储引擎架构
-
2.3.1. 新的存储引擎WiredTiger成为MongoDB v3.2的默认引擎
-
2.3.2. WiredTiger解决了MMAPv1的许多问题
2.4. 数据模型和API
-
2.4.1. 文档基本上是JSON对象,带有一组在BSON(二进制JSON)规范中定义的扩展类型
-
2.4.2. 文档由名称-值对组成,其中字段的值可以是任何BSON数据类型
-
2.4.3. 文档还可以合并其他文档(称为嵌入文档或嵌套文档,以及值或文档的数组)
-
2.4.4. 从4.0版本开始,MongoDB支持ACID,实现了多文档事务
-
2.4.5. 事务采用二阶段提交算法,并利用底层WiredTiger存储引擎的快照隔离功能
2.5. 数据分发和复制
-
2.5.1. 使用哈希函数产生分片键的结果,并映射到相应分片
-
2.5.2. 存储键落在特定分片键范围内,由该范围的分片存储
-
2.5.3. 在每个分片中,MongoDB将文档存储在块(chunk)中
-
2.5.3.1. 默认情况下,一个块最大为64 MB
-
2.5.3.2. 块拆分是元数据更改,由插入或更新操作触发,不涉及任何数据移动
-
2.5.4. 随着集群中数据的增长,分片之间的数据分布可能会变得不平衡
-
2.5.5. 每个主分片可以有多个分片副本,分片副本统称为副本集
-
2.5.5.1. 副本集中的节点定期发送心跳消息,默认情况下每两秒发送一次,以确认成员可用性
-
2.5.6. 支持可调节一致性
2.6. 优缺点分析
-
2.6.1. 性能
-
2.6.1.1. 最初版本的MongoDB的写入性能不佳
-
2.6.1.2. WiredTiger存储层推动,得到了显著改善
-
2.6.2. 数据安全性
-
2.6.2.1. write concern的默认设置majority确保更新在副本集中的法定数节点上持久
-
2.6.3. 可扩展性
-
2.6.3.1. 使用分片和部署多个mongos查询路由器进程来水平扩展数据收集能力
-
2.6.4. 一致性
-
2.6.4.1. 跨多个分片集合的ACID事务为开发人员提供了事务一致性功能
-
2.6.5. 可用性
-
2.6.5.1. 副本集是保证数据可用性的主要机制
3. DynamoDB
3.1. Amazon的DynamoDB是AWS云中的核心服务产品
-
3.1.1. Dynamo是为使用Amazon网站而构建的
-
3.1.2. 需要根据使用的存储量和应用程序的DynamoDB使用量付费
-
3.1.3. 原则是你要求DynamoDB为你做得越多,支付的费用就越多
-
3.1.4. 如果你要将系统部署到AWS,DynamoDB可能是持久层的绝佳选择
-
3.1.5. DynamoDB的日益普及与AWS云的应用的日益增长相得益彰
3.2. 在2012年演变为公开可用的、完全托管的DynamoDB数据库服务
- 3.2.1. 是一种完全托管的服务,支持键值的低延迟查找
3.3. 作为一个完全托管的数据库,DynamoDB最大限度地减少了应用程序所需的数据库管理工作
-
3.3.1. DynamoDB利用其自适应容量功能来确保数据库部署能够满足性能和可扩展性要求
-
3.3.2. 还有许多可选功能,能让你更轻松地编写应用程序,并为你的应用程序提供更高级别的自动化管理
3.4. 数据模型和API
-
3.4.1. 单个项目的大小限制为400 KB
-
3.4.2. 项目的主键值充当分区键,它被散列并将每个项目映射到不同的数据库分区
-
3.4.3. 本地二级索引必须具有与基表相同的分区键和不同的排序键
-
3.4.4. 经典API使用4个核心操作(PutItem、GetItem、DeleteItem和UpdateItem操作)的变体来提供单项和多项的CRUD功能
-
3.4.5. DynamoDB最近提供替代API,称为PartiQL,是SQL的派生语言
-
3.4.5.1. 可以使用ExecuteStatement和BatchExecuteStatement API提交SQL语句
-
3.4.5.2. DynamoDB将你的SQL语句转换为经典API中定义的单个API调用
3.5. 数据分发和复制
-
3.5.1. DynamoDB对该键进行哈希处理并存储每个项目的三个副本
-
3.5.2. 每个分区都有一个领导者和两个追随者
-
3.5.3. 自适应容量功能自动重新分区数据,同时保持可用性的场景
-
3.5.3.1. 分区超过了分区大小限制,约为10 GB
-
3.5.3.2. 增加了表的预配置吞吐量容量,需要支持比现有分区更高的性能
-
3.5.3.3. 配置为使用按需容量的表遇到超出其能维持的吞吐量的请求峰值
3.6. 优缺点分析
-
3.6.1. 性能
-
3.6.1.1. DynamoDB API相对简单,可以以非常低的延迟执行
-
3.6.2. 数据安全性
-
3.6.2.1. 当领导者分区持久化修改后,更新被确认,并且表中的所有项目都被复制到本地区域的三个分区中
-
3.6.3. 可扩展性
-
3.6.3.1. DynamoDB的自适应容量旨在重新平衡大型数据库,以提供足够的分区来满足观察到的需求
-
3.6.3.2. 预配置容量是按表分配的,意味着如果你的应用程序有10个分区,每个分区将获得总表容量的十分之一
-
3.6.4. 一致性
-
3.6.4.1. 副本是最终一致的,因此从非领导者副本读取过时数据是可能的
-
3.6.4.2. 可以使用强一致读取来获取最新的副本值,但代价是额外的容量单位和延迟
-
3.6.5. 可用性
-
3.6.5.1. DynamoDB为用户提供服务级别协议(SLA)
-
3.6.5.2. 基本保证了全局表99.999%的可用性,单区域表99.99%的可用性