搭个微服务(二)与错共舞

咦?panic啦

如果你是学院派,玩微服务必须dubbo,zookeeper不离手,业务保证100%可用,那本文就不是为你写的啦。

由于微服务间采用网络通讯,“错误”是难免的。在传统的进程中,除了太阳黑子爆发导致硬件寄存器出错(参见一个经典案例),调用函数几乎是不存在失败的。但微服务不同,产生“错误”主要有以下几种情况:

  1. 网络间发生抖动
  2. 某个服务发生异常,导致依赖它的服务异常
  3. 某个服务正在重启

重试一下

上文说到,所有的微服务都必须保证:内部一致,外部幂等。这是重试失败请求的保证。
在实践中遇到网络错误,如果是GET请求就可以毫不犹豫的重试,前提是:GET方法不能对持久数据有任何影响。

for i in range(5):
    # 重试5次,看你能不能成功
    try:
        ret = await fetch_json(url)
        ...
    except:
        await sleep(1)
        continue

像这样丑陋的代码,甚至可以直接写到fetch_json这样的底层工具上。大胆放心的用吧。

如果是post的请求失败,那情况就会复杂很多。此时,需要在服务设计之时就保证内部一致性和幂等性,也就是:

  1. 如果B服务接收到A服务的请求,那B服务就一定能执行完毕。
  2. 在一个session中,无论A调用多少次B服务的接口,B服务都只响应一次

保证一致性需要从业务具体分析,但保证幂等非常简单。引入flow_no流水号即可。

  1. a服务调用b服务,生成唯一流水号并传给b, flow_no=123
  2. b服务得到响应,将123设置为finished
  3. a服务网络错误,重试,使用相同的流水号 , flow_no=123
  4. b 响应前先查询流水号,发现123已被使用,返回“已完成”错误码(看需求,也可以返回之前计算结果)。

graceful killer

当服务A重启的时候,假如A还有任务尚未完成,那SIGTERM信号可能会直接打断这次任务。这会造成难以挽回的数据不一致。
大部分网络框架都提供了graceful killer的功能,让进程安全的退出。但必须警惕自己实现的“生产”“消费”模式。确保每个进程都能优雅的退出。类似这篇文章《python:优雅的退出程序或重启服务》
使用rabbitmq或redis等高速持久化队列,而不是将任务信息保存在内存队列中是一个比较好的做法。

recover与中间状态

微服务数据一致性的问题,总的来说是一个可信发布的问题。当上面简单的策略都无法完成业务的需求,那就只能启动容错。
比如完成操作A实质上需要进行B,C,D三个操作:

    -> B
A   -> C
    -> D

此时需要有一种机制,当B,C,D中任何一个操作没有完成,则将A操作标记为失败。同时启动容错机制

比如以下提现业务:

  1. 用户账号 Coin 扣除 500金币
  2. 调用第三方接口,给该用户打钱0.5元
  3. 插入一条提现日志到withdrawlog

此业务需要调用3个服务:coin,wetchat,withdraw。更何况支付服务是第三方的,根本无法控制。
所以,在进入提现流程前,需要对这个任务进行跟踪,并记录中间状态。具体上:

  1. 进入提现 创建 monitor_log , status = withdraw_pre_doing
  2. 锁定该用户的金币,此时用户不能再进行金币相关操作,确保第三方账户里有足够的钱。
  3. 用户账号 Coin 扣除 500金币 成功: status = withdraw_already_pay_coin
  4. 调用第三方接口,给该用户打钱0.5元 成功: status = withdraw_already_pay_wx
  5. 插入一条提现日志到withdrawlog 成功: status = withdraw_done

这种设计,实质上是基于消息的分布式事务,它可以保证最终一致性。实作中会每隔一段时间启动monitor的回滚,选取所有中间状态不为done的monitor。然后调用各服务对应的容错操作,在容错操作中,会读取monitor记录的信息,使用合适的方式使数据一致。并且,所有被标记为数据损坏的用户,在数据一致前都不能有进一步的操作。艰苦的过程就要来临。
注:要实现monitor,redis的天然原子操作和高性能绝对是不二之选。
注:由于保证服务内部的ACID,并且锁定了资源(coin和第三方账户)。容错操作很可能只是给失败的服务重新发送了一次请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值