分布式常见问题
Contents
CAP理论
consistency 强一致性
- 强一致性:分布式集群中所有节点的写操作具有原子性,一起写成功才反馈成功,可能会导致等待。这样的好处是,任意一个节点做了写操作,那么随后的访问查询,无论查询到哪个节点,得到的结果都是一样的。
- 最终一致性:在一段时间后,节点间的数据会最终达到一致状态
- 顺序一致性:先手发送A B请求,在集群中所有节点上A都要先于B
Availability 可用性
表示服务要么挂了返回失败、要么立马返回执行结果,不会因为网络延迟,等待数据同步而不可用
partition-tolerance 分区容错
表示隔离出来的节点(比如网络不好的节点)仍然可以正常运行,不会影响本身和其他节点的运行
分析
假设一个集群有 A B C 3个节点,现在A节点 和 BC节点之间的网络延迟很严重
如果保证 C A,既保持强一致性,又不会盲目等待,只有把网路信号差的节点A 剔除出去,这样系统仍然可以实现正常运行,但是不满足分区容错,不过现在这是主流的做法
如果保证 C P,那么系统只能选择等待,等待A的讯号通畅,这样就无法满足高可用了,挂一个,全瘫了
如果报错 A P,就是节点间不必保证一致性,这样会导致 A执行了写操作,但是 BC 不知道,查询的时候只有查A才能获得最新值,查询BC 还是老的值。可能需要人工干预来实现数据最终同步。
分布式ID
- 用UUID实现分布式系统中唯一ID,但是缺点就是ID无意义,且字符串太长作为索引使用索引效率低
- 利用NodeID+系统时间,例如server118520000,分布式流水号
- 利用中间件:redis的分布式ID生成器,或者数据库自增实现
https://www.zhihu.com/question/54895548/answer/147456159
秒杀业务
浏览器端时间,入口只有活动开启前才能获得
- 前台html提交订单的时候做js时间验证或者提交键置灰,可以防止普通小白用户在未开始提交
- 进入后台后仍然判断下单请求是否是在秒杀时间开始后才算有效下单
浏览器端防止重复提交和频繁读取
- 每次提交订单后,置灰提交按钮,直到ajax返回了结果之后再回复抢购按钮
- 查询订单的时候,直接读取redis缓存的结果,而不是查询数据库,没做一次查询再未返回查询结果前,置灰查询按钮
站点层请求拦截与页面缓存
即使伪造url请求,但是做N秒内查询的页面缓存,可以过滤一些重复的请求
服务器端优化
redis + 消息队列
- redis预先缓存秒杀商品的库存数量
- 判断count>0,则count –,把请求放入消息队列当中,等待异步回传的订单处理结果,处理成功则通知用户下单成功,异步处理失败则告知失败。如果Consumer是集群的话,可能需要数据库加锁来实现数据安全。并发的执行不冲突的操作,到了涉及线程安全的时候,加锁操作。
- 如果count<0, 则直接返回用户,下单失败
分布式事务解决方案
TCC事务补偿操作
类似于乐观锁策略:A服务器调用B服务器的写操作,checkB是否正确执行,失败则重试或者回滚A事务
本地消息表
A 、B 两个服务器的数据库 各有一个消息表, A 调用B操作会插入一条消息数据,B成功执行后,会修改A数据库中消息的状态, A 会定期的扫描消息表是否被确认过,如果未确认则做补偿事务回滚