分布式系统概述

168 阅读7分钟

什么是CAP理论?

假设一个服务需要server、redis、mysql三个部分,只要将它们分别部署到三个节点单机或集群)上,那我们这个服务就可以称之为分布式服务了。

需要注意的是server、redis、mysql各自分别都可以做成集群,它们合起来才可以称之为一个分布式系统。集群和分布式都是多机的概念,区别在于集群中的每个节点作用是相同的,分布式系统中的每个节点作用是不同的。而如果server分成更多可独立部署的节点,那么就可以称之为微服务架构的分布式系统了。

一致性 Consistency:所有节点访问相同的数据。

可用性 Availability:请求有回应,正确请求不会失败。

分区容错性 Partition-tolerance:某个网络分区的错误,不会影响整个系统的运行。

CAP理论的核心在于,C、A、P是不能同时满足的。

CA:为了保证CA,则不能有P,因为需要数据同步。

CP:为了保证CP,则不能有A,因为需要写入失败。

AP:为了保证AP,则不能有C,因为数据无法同步。

而对于分布式系统来说,网络是最大的问题,必须要保证P,需要在C和A中二选一。

什么是Base理论?

书接上文,CAP理论在保证分区容忍性下,强一致性和高可用性无法兼得,但事实上设计分布式系统时我们不能真的去做有你无我这样的选择。

在一致性和可用性上我们可以适当的妥协,两个100分做不到,100分 + 0分同样不可取,但是我们可以选择两个都做到60分,即Base理论的内容。

基本而用

例如电商平台购物节的时候访问量会很大,后台可以选择优先展示价格、商品名的重要信息,稍微不重要的且占用网络资源大的图片信息可以延迟显示。

购物付款时,又因为访问量很大,无法立即支付成功,会响应一个正在支付中的状态,随后再提示支付成功。

上述的两点都是在可用性上做妥协的常见案例,虽然降低了可用性,但是对用户来讲是处在可容忍的范围内。

弱一致性

假设后台服务由N个节点,我们在其中一个节点上写了一条数据,为了保证强一致性,我们需要等待该信息同步到N个节点上才会返回写入成功。

如果一个节点挂掉了,整个系统都会不可用,因此在对一致性要求不高的业务上,比如说关注某个店铺,我们没有必要追求强一致性,只有对于诸如支付订单的操作会对一致性有着较高的要求。

具体实现可以使用队列、定时任务等,只要保证一段时间后能够达到一致性即可。最终一致性对这段时间的要求更低,也属于弱一致性。

就要强一致怎么办?

书接上文,我们在电商平台下单等场景下的时候是需要强一致性的?比如A下一单,写节点1,商品库存减1恰好变为0。这时候B下一单,写节点2,发现库存还有1也减1变0。

这时候商家就没有货可以发了,这种其实还好,但是如果是转账操作,那导致的问题就更严重了。

WARO

那需要强一致的时候该怎么做呢?上文说到写某个节点的时候,等待这条写指令同步到所有节点后再返回写入成功,这种方式称为Write All Reay One,毫无疑问,从名字上就可以看出,这种策略是读优写差的。

还是那个问题,两个100分不可能,100分 + 0分不可取,两个60分则更优。

Quorum

假设一共有10个节点,写的时候我们要求其中6个节点都更新为最新的数据,读的时候我们要求读5个节点,取其中版本最新的数据(引入version字段)。

这样子就使得读写均衡了,也可以控制读写节点数量,来控制读写效率,这种策略被称之为Quorum

负载均衡策略

  1. 轮询法
  2. 加权轮询法
  3. 随机法
  4. 加权随机法
  5. 源地址哈希法
  6. 最小连接数法

分布式系统的设计目标

  1. 可扩展性
  2. 高可用
  3. 无状态
  4. 可管理
  5. 高可靠

分布式事务解决方案

一个sql操作两个db,或两个服务分别访问不同的db。

  1. XA协议,需要数据库支持这个协议(Innodb),两阶段、三阶段提交
  2. 基于事务补偿机制:TCC(Try Confirm Cancel)
  3. 本地消息表:本地数据库 + mq
  4. 基于事务消息:mq,执行过程中的sql写到mq,commit后,另一个服务再消费队列。

三阶段对比两阶段的改进?

  • 1阶段:prepare,所有事务执行sql,但不commit。
  • 2阶段:commit,所有事务一起commit,有fail的,所有一起rollback。

两阶段的问题:

  • 两阶段需要一个事务管理器去协调,一般和应用程序是一起的,因此有单点故障的问题。
  • 第二个阶段如果只给一部分发了commit后管理器就挂了,那么会数据不一致。
  • 响应时间长,sql执行快的需要等待sql执行慢的,等待过程中持有的锁不能释放。
  • 状态不确定,由第二条引起的。

三阶段解决了单点故障的问题。

  • 1阶段:canCommit,探测所有的数据库是否存活。
  • 2阶段:preCommit,所有事务执行sql,但不commit。
  • 3阶段:doCommit,所有事务一起commit,有fail的,所有一起rollback。

对比两阶段:

  • 一阶段提高了成功的概率,发现问题就不占用资源。
  • 引入超时机制,如果数据库一直收不到管理器的commit,那就自己执行commit。
  • 两阶段也有超时,只不过是对于管理器,一直收不到某个数据库提交成功,则所有一起rollback。

TCC事务模型

Try就是执行sql,Confirm就是commit,Cancel就是rollback。业务层面每个操作都需要实现这三个接口。

如何理解RPC?

中间件、微服务之间基于RPC通信,平常的通过http这种是属于远程调用,而rpc是本地调用远程服务,是通过类名::方法名这样去调用的。

  • 动态代理,封装调用细节。
  • 数据的序列化与反序列化。
  • 通信,可以是http或tcp、udp。
  • 异常处理等。

雪崩、穿透、击穿

缓存雪崩

缓存大面积失效。解决办法:①随机过期时间;②监控过期key,过期了更新;③缓存预热,刚启动时先加载一些数据到缓存;④分布式锁,只一个请求到db,拿到key后后面相同key请求就可以去缓存拿了。

缓存穿透

缓存和db都没有数据,常见于网络攻击。解决办法:①接口层做基本的校验。②缓存可以记key:null,过期时间可以设置的短一些;③使用布隆过滤器。

缓存击穿

缓存没有数据,db有数据,与雪崩的区别在于一条和多条。解决方案:①设置热点数据永不过期。②分布式锁。