如何设计高性能高可用存储架构
1、数据库架构模式
95%的业务都可以通过读写分离或分库分表来解决。
1.1、读写分离模式
复杂度问题分析
复制延迟的解决方案
写操作后的读操作指定发给数据库主服务器
读从机失败后再读一次主机
关键业务读写操作全部指向主机,非关键业务采用读写分离
任务分解的解决方案
程序代码封闭模式
中间件封装模式(是一种代理的模式)
1.2、分库分表模式
1.2.1、数据分库
join 问题的解决方案
小表冗余,比如字典表
代码实现 join
字段冗余
事务问题的解决方案
分布式事务
分布式事务的两种算法:
1)2PC(如 MySQL XA)
![](https://static001.geekbang.org/infoq/ec/ecbac1fc7a98c30535e2e48887aef2da.png)
阶段 1:单个参与者故障会导致整体事务失败
阶段 2:事务协调者故障会导致状态不一致,参与者一直等待事务协调者指令,可能需要人工修复
2)3PC(引入了超时机制)
![](https://static001.geekbang.org/infoq/90/9093beeb8c35ed4d1733edf6aaa89411.png)
虽然 3PC 更强大,但该算法比较复杂,且造成脑裂的问题,处理起来更复杂,所以 2PC 使用更广。
1.2.2、数据分表
拆分原则:
B+Tree 的层数:3 层大约是 2000 万条
Innodb buffer pool:2000 万数据,每条数据 100 字节,单表 2G
数据量持续增长的表
两种拆分方式
垂直拆分:按列拆分,优化单机处理性能,常见于 2B 领域超多列的表
水平拆分:按行拆分,提升系统处理性能,常见于 2C 领域超多行的表
![](https://static001.geekbang.org/infoq/bc/bcc8398028fee3bf7fd9c1cb2ef11c00.png)
水平拆分复杂度问题主要四个:路由问题、count 操作、join 操作、order by 操作,一般使用第三方中间件解决,如 Sharding-JDBC。
水平分表伸缩的瓶颈:1、每个应用需要连接所有的分片,当应用数据增多时后,数据库连接会逐渐成为瓶颈。以 MySQL 为例,默认 100 连接,实例 50~100 连接性能最高,超过 200 后会显著下降;2、单个 Sharding-JDBC 的聚合操作会有性能瓶颈。
2、存储架构模式
2.1、存储类问题处理框架图
![](https://static001.geekbang.org/infoq/08/088b4076598ebc03e3a04480b83ca269.png)
2.2、高可用存储的核心指标
RPO:恢复点目标,指“最大可接受的数据损失”,因为数据备份和复制是有时间限制的,不可能做到绝对的实时。
RTO:恢复时间目标,批“最大可接受的系统恢复所需时间”,因为定位、处理、恢复需要时间。
WRT:工作恢复时间,指“系统恢复正常后,恢复业务所需时间”,因为要进行各种业务检查、校验、修复。
MTD:最大可容忍宕机时间,等于 RTO+WRT。
2.3、备份架构
![](https://static001.geekbang.org/infoq/e5/e54ad35b0d06f9aa0c371f06978887be.png)
2.4、切换架构
可分为主备切换/主从切换
优点:可自动实现故障恢复,RTO 短
缺点:实现复杂,需要实现数据复制、状态检测、故障切换、数据冲突处理
应用:内部系统、管理系统
2.5、选举架构
优点:可以自动实现故障恢复,RTO 短,可用性更高
缺点:实现复杂,需要实现数据复制、状态检测、选举算法、故障切换、数据冲突处理
应用:通用,例如 Redis、MongoDB 等
2.6、最佳实践
双机切换和选举架构的最佳实践是基于 ZooKeeper 实现
优点:ZooKeeper 已经保证了自我的高可用;基于 ZooKeeper,切换或者选举过程实现比较
简单;ZooKeeper 可以有多用途
3、分片和分区架构
3.1、分片架构
设计目的:
解决主从复制架构中写性能和存储的瓶颈
分片规则:
选择基数大的键值;
保证分布均匀避免热点分片
Hash 分片:1)分布均匀,但不支持范围查询;2)扩容服务器需要做历史数据迁移
范围分片:1)分片可能不均匀,支持范围查询;2)方便扩容,无需迁移历史数据
路由规则:
静态路由
实现简单,但不灵活,无法动态扩容和平衡,如数据库分表
动态路由
实现复杂,支持动态扩容和平衡,如 Redis、MongoDB、Hbase;
实现方式有配置中心和路由转发,路由转发分为客户端重定向(Redis)和服务端请求转发(如 ES)两种实现方式。
高可用方案:
![](https://static001.geekbang.org/infoq/28/28afaefa991135aab3764ffa4de91807.png)
3.2、分区架构
设计目的:
解决分片架构中存在的城市级别的故障和超大用户量的场景(比如微信、淘宝)
全局路由:
DNS:标准协议、通用,但基本只能实现就近接入
GSLB:非标准,需要独立发开部署,功能非常强大,可以做状态监测、基于规则的定制路由
备份策略:
集中式
互备式
独立式
4、如何设计存储架构
4.1、设计思路
4.1.1、估算性能需求
用户量预估,方法:
规划:根据成本、预算、目标等确定
推算:基于已有数据推算
对比:跟已有标杆进行对比
用户行为建模
用户的典型行为
采取某种行为的用户数量
用户某种行为的频率
性能需求计算
数据量:需要存储的数据总量(G)
请求量:对数据的读写请求量(TPS/QPS),要计算平均值和峰值
预留量:预留的增长空间,评估要合理,一般预留 1.5 到 2 倍
4.1.2、选择存储系统
挑选应用场景和系统本质契合的系统
挑选熟悉的
可维护性、成本、成熟度等
![](https://static001.geekbang.org/infoq/6f/6f68afce91c33a4dc5bce5678fe7a406.png)
![](https://static001.geekbang.org/infoq/3e/3e748e37addbfa8de545c1e623e1cc98.png)
https://db-engines.com/en/ranking/relational+dbms
4.1.3、设计存储方案
设计数据结构
验证读写场景
评估读写性能
5、常见的存储系统分析
![](https://static001.geekbang.org/infoq/3e/3ec98936a2070ec35542f64790135bf7.png)
评论