1. 分布式架构设计概述
1.1. 概念和特点
硬件独立、软件统一(扩展升级容易,节点故障不会影响整体系统的可用性)
其他好处:处理器相互协调,加快了系统处理速度,同时低配置机器也你那个被重新纳入分布式系统中,降低成本。另外,任何一台主机宕机,都不影响整个系统都使用
分布式设计考虑的问题:
- 如何将系统拆分为子系统?
- 如何规划子系统间都通信?
- 如何考虑通信过程中都安全?
- 如何让子系统可以扩展?
- 如何保证子系统都可靠性?
- 如何实现数据的一致性?
分布式系统面临的挑战:
- 异构性:不同的网络、操作系统、计算机硬件、编程语言,必须使用通用的网络通信协议来屏蔽差异(中间件处理)
- 缺乏全球时钟:程序需要协作时,通过交换消息协调动作
- 一致性:数据分散
- 故障的独立性
- 并发:使用分布式系统的目的,是更好的共享资源,每个资源都必须设计成在并发环境中安全
- 透明性:任何组件的故障、主机的升级、迁移,对用户不可见
- 开放性:不同程序员编写不同组件,接口必须遵守统一的规定
- 安全性:网络间传递敏感信息
- 可扩展性:随着业务量的增加而相应的扩展
1.2. 关注的问题
- 消息处理
- 事务处理
- 容错性
- 一致性
- 安全性
- 高可扩展性
- 开放性
- 并发处理能力
- 透明性
- 数据持久化
- 热部署
1.3. 几大子系统体系
- 分布式作业调度(消息处理、事务处理)
- 分布式协调(一致性)
- 分布式缓存(一致性)
- 分布式存储(容错性)
- 分布式并行计算(并发处理能力)
- 分布式通信(消息处理、事务处理)
2. 分布式系统架构体系
2.1. 基于对象的体系架构
RPC(Remote Procudure Call)、RMI(Remote Method Invoke)
2.2. 面向服务的体系架构SOA
2.2.1. REST风格架构
使用REST API
2.2.2. 微服务架构(MSA)
非功能型需求:
- 事务
- 服务治理(注册、发现、负载、路由、认证授权、隔离)
- 监控(日志、性能监控、告警、调用链路)
- 部署
- 测试
2.2.3. Serverless架构
Cloud Native架构体系
3. 分布式架构设计关键因素
3.1. 分布式通信
3.1.1. RPC
隐藏分布式通信细节,增强访问透明性
rpc的特点:
- 调用api,会将参数打包成消息,通过本地存根,发送到服务端存根,然后解析参数,调用对象
- 对于引用的支持会非常复杂
- 通信协议通常需要支持多种,tcp、udp等,以针对客户不同需求
- 调用函数是幂等函数,可以多次执行,返回相同状态
- 性能会相对差
- 安全性:发送过程是否可信?远程机器是否可信?是否合法客户端请求?消息被嗅探?消息被拦截或修改?协议是否能防止重播攻击?如何防止消息被恶意损坏或截断?
- 同步特性:当前请求会阻塞
- 对远端的不确定性:远端机器不确定是否正在执行
- 大型分布式调用,网络会比较复杂,ACL管理也会非常复杂
rpc的实现:
- 名称服务操作:允许程序使用动态端口,注册和查找绑定端口、机器
- 绑定操作:使用适当协议建立通信
- 终端操作:API绑定注册
- 安全操作:相互验证
- 国际化操作:语言
- 封送处理/数据转换操作:参数序列化传输
- 存根内存管理和垃圾收集:引用传递时需要
- 程序标识操作:标识符接口集
- 对象和函数标识操作:引用传递
3.1.2. 消息队列中间件通信
消息队列特点:
- 通过将消息放入队列和取出队列进行通信,不直接和其他程序通信,避免网络通信的复杂性
3.2. 分布式容错性
需要通过可靠的系统实现来达到容错性,即使系统出错,依旧可用
可靠系统:
- 可用性:出现问题,依旧可用
- 可靠性:几个9,尽量不会出问题
- 安全性:偶然出现的故障不会造成灾难(雪崩就不行)
- 可维护性:发生故障,被恢复的难易程度
故障类别:
- 崩溃性故障:服务器停机,但在停机之前工作正常
- 遗漏性故障:服务器不能响应到来的请求(不能接收或不能发送)
- 定时性故障:服务器对请求响应过快或过慢
- 响应性故障:服务器对请求以错误对方式进行响应
- 任意性故障:任意时间产生任意类型故障,产生错误的输出,但是又不能检测出错误
使用冗余掩盖故障:
- 信息冗余:hamming码,主要是针对信息传输的位错误
- 时间冗余:重试
- 物理冗余:硬件或软件上,使用额外的装备或进程,容忍部分失效(TMR,三倍模块冗余)
3.3. 分布式存储一致性
分布式存储的两种主要方式:
- 副本(一致性问题)
- Set
3.3.1. 一致性模型
- 严格一致性:基本做不到,需要严格的全局时钟
- 持续一致性:部分副本未还未得到更新,同一时间段,允许有一定偏差
- 顺序一致性:读写操作,无论如何交叉,最终都保持同样的顺序
- 因果一致性:顺序一致性的子集,只保留有因果关系的读写的顺序一致性
- 入口一致性:共享数据的同步锁
3.4. 分布式原子性
3.4.1. 两阶段提交
第一阶段(准备阶段):
- 协调者节点向所有参与者节点询问是否可以执行提交操作,并等待各个参与者节点的响应
- 参与者节点执行所有事务操作,并将Undo信息和Redo信息写入日志
- 各参与者节点响应协调者节点发起的询问。事务操作实际成功,返回“同意”,失败返回“终止”
第二阶段(提交阶段):
- 协调者收到参与者的失败消息或超时,则直接给每个参与者发送回滚(rollback)消息;否则发送提交(commit)消息;参与者跟酒协调者的指令执行提交或回滚操作,释放所有事务处理过程中使用的锁资源
- 协调者收到所有节点的“同意”操作,向所有参与者节点发出“正式提交”的请求;参与者节点正式完成请求,并释放整个事务期间占用的资源;参与者节点向协调者节点发送“完成”消息
- 如果任一参与者返回“终止”,或协调者询问超时,协调者节点向所有参与者发出回滚操作;参与者利用Undo信息执行回滚,并释放资源;参与者发送“回滚完成”消息后
- 协调者收到所有参与者消息,完成事务
优点:原理简单,实现方便
缺点:
- 同步阻塞问题
- 单点故障:协调者
- 数据不一致:阶段二中的提交过程,如果部分受到请求,部分没有,就存在数据不一致
- 无法解决的问题:协调者发出commit后宕机,受到的参与者也宕机,事务状态就不确定了,没人知道是否已经被提交
3.4.2. 三阶段提交
CanCommit阶段:
- 事务询问:是否可以执行事务提交
- 响应反馈:返回yes或no
PreCommit阶段 - 所有都返回yes:
- 发送预提交请求
- 事务预提交:参与者执行事务操作,记录Undo和Redo信息
- 响应反馈:成功返回ACK
PreCommit阶段 - 部分返回no:
- 发送中断请求:协调者
- 中断事务:参与者收到中断请求,执行事务中断操作
doCommit阶段 - 执行提交(任何一步失败,协调者收不到ACK会超时,都会走到中断事务):
- 发送提交请求:协调者
- 事务提交:参与者
- 响应反馈:参与者
- 完成事务:协调者
doCommit阶段 - 中断事务:
- 发送中断请求:协调者
- 事务回滚:参与者利用Undo信息回滚,并释放资源
- 反馈结果:参与者
- 中断事务:协调者
依旧存在数据一致性问题
3.4.3. Paxos算法
高度容错的消息通信
四种角色:Proposer(提议者)、Acceptor(决策者)、Client(产生异议者)、Learner(最终决策学习者)
目标是要保证所有的提议者达成共识(提议者也可以是其他角色)
阶段1:
- Proposer:选择一个议案编号n,每个提议者都不一样,向所有Acceptor发送编号也为n的prepare请求(请求可能中断)
- Acceptor:总是与最新都提议者沟通(可能接受,可能拒绝)
阶段2:
- Proposer:n1如果收到过半数同意,则认为是ok的;n2如果还没有收到过半数同意,但是却收到了n1的提议,则尝试带着n1的建议,继续向所有Acceptor去问
- Acceptor:如果收到n2的结论,就会返回同意;n2收到过半数,则认为结论是如此
3.4.4. CAP理论
一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)
最多只能三选二,不能同时支持三个特性。
- CA模型(无法容错,集中管理,要死一起死):单站点数据库、集群数据库、LDAP、xFS文件系统【实现方式:两阶段提交、缓存验证协议】
- CP模型(出现分区错误,直接停止服务):分布式数据库、分布式锁定、绝大部分协议【实现方式:悲观锁、少数分区不可用】
- AP模型(容许出现不一致):Web缓存、DNS【实现方式:到期/租赁、解决冲突、乐观锁】
3.5. 分布式安全性
3.5.1. 安全威胁
- 窃听
- 中断
- 修改
- 伪造
3.5.2. 安全机制
- 加密
- 身份验证
- 授权
- 审计