简介
服务间调用有三种状态:成功;失败;超时。前两个状态明确,但超时状态完全不知道是什么状态。
可能是请求没有到达,也可能是请求到达了,但返回结果没有到达。我们不知道下游系统是否收到了请求,而收到了请求是否处理了。
例如:
- 创建订单接口,第一次调用超时,然后client重试了一次,是否会多创建一笔订单?
- 用户付款时,服务端发生扣款行为,接口响应超时,调用方重试了一次,是否会多扣一次钱?
解决方案:
- 下游系统提供查询接口,上游系统在timout后去查询一次,并根据结果执行不同的策略
- 幂等处理。上游只管重试,下游系统保证一次和多次的请求结果是一样的。(推荐方式)
全局id
snowflake的结构如下(每部分用-分开):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
- 第一位为未使用
- 接下来的41位为毫秒级时间(41位的长度可以使用69年)
- 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点)
- 最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)
一共加起来刚好64位,为一个Long型。(转换成字符串后长度最多19)
snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。经测试snowflake每秒能够产生26万个ID。
本机测试,每秒产生约4W个id
处理流程
以交易为例,当收到交易请求时,先去查,有没有创建过?如果查到了就不做处理
一般可以采用乐观锁,基本CAS方式。
1 | update 订单表 set status="交易成功" where id=#orderId# and status="等待买家确认收货" |
或者
以论坛发贴为例,在表单中隐藏一个token,防止用户多次点击表单提交按钮。防重复。