什么是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。
负载均衡策略
- 轮询法
- 加权轮询法
- 随机法
- 加权随机法
- 源地址哈希法
- 最小连接数法
分布式系统的设计目标
- 可扩展性
- 高可用
- 无状态
- 可管理
- 高可靠
分布式事务解决方案
一个sql操作两个db,或两个服务分别访问不同的db。
- XA协议,需要数据库支持这个协议(Innodb),两阶段、三阶段提交
- 基于事务补偿机制:TCC(Try Confirm Cancel)
- 本地消息表:本地数据库 + mq
- 基于事务消息: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有数据,与雪崩的区别在于一条和多条。解决方案:①设置热点数据永不过期。②分布式锁。