六大陷阱
粒度太细
服务关系复杂
需求分析、方案设计、测试、部署。。。难度都会增加
例如:
- 分布式服务如何保证数据一致性
- 分析设计的时候需要考虑的影响点变多
团队效率低下
需求分析、方案设计、测试、部署。。。工作量都会增加
例如:
- 接口设计数量,1次请求由2个服务器处理,接口数量1个,5个服务处理,接口数量4个,接口设计、接口联调、接口测试等工作量都会大大增加
- 某个业务功能上线,需要升级的系统数量会增加
问题定位困难
故障扩散:单个微服务的故障,会导致多个微服务异常,监控系统一片红,到处都在告警,但是不知道根本原因
系统性能下降
调用链越长,单次请求耗时会更长
基础设施缺乏
无法快速交付
- 没有自动化测试支撑,每次测试都需要测试大量接口
- 没有自动化部署支撑,人工部署苦不堪言
- 没有自动化监控,每次故障定位都需要人工查询几十台机器上百个微服务的各种状态和各种日志文件
服务管理混乱
- 服务路由:假设某个微服务有60个节点,部署在20台机器上,那么其他依赖的微服务如何知道这个部署情况?
- 服务故障隔离:假设上述例子中的60个节点有5个节点发生故障了,依赖的微服务如何处理这种情况?
- 服务注册和发现:同样是上述的例子,现在我们决定从60个节点扩充到80个节点,或者将60个节点缩减为40个节点,如何让依赖的服务知道新增或者减少的节点呢?
四大挑战
数据分布
分布式事务
本地事务消息
- 如果“2.事务消息”丢失,A服务会不断重试
- 如果“4.处理响应”丢失,A服务会不断重试
- B服务重复收到“2.事务消息”,然后检查消息表是否已经处理过,已经处理过就直接返回处理结果,没有处理就正常处理(幂等)
消息队列事务消息(以RocketMQ举例)
- 发送Prepared消息时,会拿到消息的地址
- 执行本地事务
- 通过1拿到的地址去修改消息状态
- RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送者确认,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息
TCC
应用层面的2PC,事务协调器就是业务代码,Confirm接口和Cancel接口要实现幂等(全局ID+状态)
Try
1.服务A修改订单为“Paying”状态
2.服务B冻结库存2,剩余可用库存98
Confirm
3.服务A修改订单为“Paid”
4.服务B冻结库存为0,剩余可用库存98
Cancel
3.1服务A修改订单为“Canceled”
4.1服务B冻结库存为0,剩余可用库存100
全局幂等
幂等技术本质
分布式数据只能通过消息来实现最终一致性,而消息可能会丢失,因此需要重试,重试就需要保证幂等
幂等定义
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同
全局幂等
全局范围内的幂等,保证每个幂等操作都是全局唯一的
设计关键
- 全局唯一ID
- 状态机
设计示例
正常处理1
正常处理2
幂等处理
服务分布
接口兼容
问题
某个微服务的某些接口升级,依赖这些接口的微服务不一定能够全部同时升级
解决方案
- 接口多版本(推荐):直接拷贝一份旧接口代码,在旧接口代码上修改,接口URL加上 /v1 /v2这种标识
- 接口逻辑兼容(不推荐):同一份接口代码,兼容新旧逻辑,容易互相影响,且旧接口下线时又要修改代码
接口循环调用
问题
某次业务处理过程中,A调用B,B又过来调用A,A的处理又进入了之前的处理逻辑,导致循环调用,整个业务进入死循环
解决方案
几乎没有好的解决方案,尽量靠上线前的测试发现
举例
- 用户登录服务调用风控服务进行安全检查
- 风控服务又来调用登录服务获取用户登录地址信息
- 获取登录地信息的接口又依赖风控服务进行安全检查