V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DreamSpace
V2EX  ›  Java

[求助]Spring 微服务该如何优雅的进行补偿/重试

  •  
  •   DreamSpace · 2020-06-19 12:07:56 +08:00 · 3738 次点击
    这是一个创建于 1378 天前的主题,其中的信息可能已经有所发展或是发生改变。

    [求助]Spring 微服务该如何优雅的进行补偿 /重试

    目前项目架构 spring-cloud-alibaba

    网上查了下,又找了些 demo 看,基本上方案如下图了

    字渣,见谅

    字渣,见谅

    现有两个方案

    • 在 A 服务的 RemoteService 中进行处理 线路 1
      • 优点:不同的调用方可以进行不同的补偿
      • 缺点:
        1. 补偿 /重试 只能通过调用 B 服务的接口进行 不够灵活
        2. 每个调用方都要写一次 RemoteService 麻烦
    • 在 B 服务 Controller 层切面中进行处理 线路 2
      • 优点:代码属于接口提供方,补偿方式更灵活
      • 缺点:永远返回 200,不知道执行成功还是失败了(可通过自定义 code 解决)
    • 在 B 服务 API 包中处理
      • 优点:不会影响浏览器直接对 B 服务的调用 线路 3
      • 缺点:API 包中会引入太多无关的依赖(可通过指定 scope=compile 缓解)

    提问环节

    1. 大家有啥更好的方式解决吗?
    2. 没有没有现成的框架?
    3. 补偿用定时任务还是 mq ?

    想听听大家的意见

    第 1 条附言  ·  2020-06-19 13:47:54 +08:00
    追加两个限制:
    - 重试的时候最好可以有一段逻辑用来写重试日志或者替换请求中的参数(比如 apikey )。
    - 重试次数到达后可以做降级。
    这种要求是不是有点过分,有什么现成的框架能做到的吗?是不是只能手搓一个了…
    13 条回复    2020-06-20 16:06:06 +08:00
    DreamSpace
        1
    DreamSpace  
    OP
       2020-06-19 12:35:16 +08:00 via Android
    自问自答一波 线路 2 有现成的框架 Spring Retry
    cs419
        2
    cs419  
       2020-06-19 12:48:45 +08:00
    dubbo 就有呀 重试调用 并行调用
    clusterInvoker 了解下
    DreamSpace
        3
    DreamSpace  
    OP
       2020-06-19 12:55:22 +08:00
    @cs419 感谢思路,主题正文说漏了,服务调用是 feign
    xuanbg
        4
    xuanbg  
       2020-06-19 13:01:12 +08:00
    在有必要重试的业务中处理。自己写一个专门处理重试业务的通用组件,有需要的时候调用一下就行了。或者和我的处理逻辑一样丢队列,专门处理重试的一个服务订阅队列里面的消息。
    DreamSpace
        5
    DreamSpace  
    OP
       2020-06-19 13:47:20 +08:00 via Android
    追加两个限制:
    - 重试的时候最好可以有一段逻辑用来写重试日志或者替换请求中的参数(比如 apikey )。
    - 重试次数到达后可以做降级。
    这种要求是不是有点过分,有什么现成的框架能做到的吗?是不是只能手搓一个了…
    DreamSpace
        6
    DreamSpace  
    OP
       2020-06-19 13:52:06 +08:00 via Android
    @xuanbg 感谢回答!
    hecz
        7
    hecz  
       2020-06-19 16:44:18 +08:00   ❤️ 1
    消息队列 或者流水任务
    CoderGeek
        8
    CoderGeek  
       2020-06-19 17:39:11 +08:00
    不知道这几个是否符合你大部分
    CoderGeek
        9
    CoderGeek  
       2020-06-19 17:39:19 +08:00
    Hystrix 、Resilience4j 、Sentinel
    gadsavesme
        10
    gadsavesme  
       2020-06-19 18:43:12 +08:00
    feign 默认使用的 ribbon 做负载均衡吧,ribbon 本身就带了服务的重试吧,至于能不能满足要求倒是不记得了,反正参数配置我记得挺多的
    lovelife1994
        11
    lovelife1994  
       2020-06-19 21:19:09 +08:00
    看业务的场景吧,你如果只是保证简单的调用某个服务最终是成功的,简单的重试就可以了,无论是同步还是异步,次数到了之后把上下文记下来事后处理就行了。退避间隔较短的话同步,否则就 mq 异步,因为要维护上下文较长时间,消息队列天然具有数据库的能力。如果是分布式事务的场景异步做补偿比较好,因为重试补偿的逻辑通常与业务强相关,坐在同步流程里太重了。
    jinzhongyuan
        12
    jinzhongyuan  
       2020-06-20 15:17:21 +08:00
    框架都做了,需要做的就是选择哪个框架
    hantsy
        13
    hantsy  
       2020-06-20 16:06:06 +08:00   ❤️ 2
    这种处理挺复杂的,大部分项目都是在业务不断优化过程中完成的。

    这不是一个教程能够教出来的东西,也不是看一本什么 Spring Cloud 内幕之内可以搞定的,长期的项目实践过程是必须的。

    传统的事务基本靠边站,Saga 模式几乎是必须的。JakartaEE/Microprofile 在起草一个 Long Running Action 规范。一些工作流,状态机项目也在做同样的事情,比如 Spring 下的 Statemachine 项目(支持 ZK ),每步执行结果状态决定下一步,提供正常路径和补偿回退处理方案。

    针对这种处理,Microservice 架构上设计归为分两种处理方式。
    1,每个服务管理自己的状态变更,触发下一步处理。比 Order Service 保存订单,触发一个**OrderPlaced**事情(通 MessageBroker ),Logistics Service 订阅这个消息,立即处理。回退一样在某个服务中通过发送一个失败事件,一步步回退。无中心化管理状态,开发上比较简单,自由,也有很多挑战(状态定义的变更向后兼容性的问题等)。
    2,状态的管理中心化,每个服务集中处理自己的业务,最后状态更新和决定下一步由管理调度角色决定。现在有很多类似工作流项目开始介入这种模式,充当一种调度者的角度。

    但话说回来,我在上海时候参与一些项目,接触到国内的一些人对 MS 的认识,什么补偿措施没有的项目一样跑的,用 了 Spring Cloud Netflix 就觉得自己在做微服务,这种看起来像 MS 的大把,实际上系统比单体程序脆弱得多。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1013 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:38 · PVG 03:38 · LAX 12:38 · JFK 15:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.