Smilingleo's Blog

为什么状态机在微服务架构下变得更重要

September 14, 2020

这个标题其实不是非常准确,应该说是为什么状态机在异步分布式微服务实践中变得更重要。因为如果你的微服务还只是将原来的本地方法调用替换为同步的API调用,那么恭喜你,你将原来的monolithic变成了distributed monolithic,并成功地给自己找了很多的麻烦。

self-contained service里提到的例子,如果所有的API调用都是同步的,那么你在开发的时候,你的关注重点会是API调用,异常处理,但是不会想到Order的状态问题。其实不是因为程序员没有这个思维,而是因为整个transaction在这个模式下是一个整体,人们的思维会自然地将其看做一个黑盒子,从这个角度考量整个API的成功与否,以及里面的实现细节(指令式思维),不会考虑Order的状态转换,考虑也没有用,因为这些转换是实现细节,是在黑盒子里面发生的,用户不可知。用户感知的仅仅是这个API是否成功,如果成功,那么这个Order自然应该是一个Created的状态,如果失败,那么整个transaction应该回滚,要么用户修改请求参数(4XX错误)并重发请求,要么直接重试(500错误).

Client -> OrderService: POST /orders
activate OrderService
OrderService -> AccountService: POST /accounts/:id/validate
AccountService --> OrderService: response

OrderService -> KitchenService: POST /tickets
KitchenService --> OrderService: response

OrderService -> PaymentService: ...
PaymentService --> OrderService: response

OrderService --> Client: response
deactivate OrderService

当你的实现方式变成异步的(Saga模式)之后,系统的交互就变成了下面的这种方式:

Client -> OrderService: POST /orders
activate OrderService
OrderService -> AccountService: validateAccount message
OrderService --> Client: response
deactivate OrderService

AccountService --> OrderService: reply message
activate OrderService
OrderService -> KitchenService: createTicket message
deactivate OrderService


KitchenService --> OrderService: reply message
activate OrderService
OrderService -> PaymentService: ...
deactivate OrderService

PaymentService --> OrderService: reply message

每个service都是一个独立(self-contained)系统,系统之间通过异步消息通讯。在这种架构模式下,原来的那种“黑盒子”思维就被打破了,你就被迫需要考虑更多的细节,比如Order的状态。

hide empty description
[*] -> Pending: sent msg to validate account
Pending --> TicketCreated: Kitchen replied successfully
TicketCreated --> PaymentCollected: Payment processed
PaymentCollected --> Created: Received payment processed msg
Pending --> Invalid: invalid account
Created --> [*]
Invalid --> [*]

因为从client的角度,POST /orders的response是一个异步的,带一个jobId, 用户之后每次查询order job信息,你都需要告知用户当前的order状态。

有了这些状态之后,对于设计者来说,会帮助你对系统有更加深入的思考。比如,在等待的过程中,如果用户想cancel订单怎么办? 有这个状态机就可以让你可以直观地和PM讨论,在什么情况下我们允许用户cancel订单,什么情况下不允许。

@startuml
hide empty description
skinparam state {
    BackgroundColor<<Focus>> LightBlue
}
state Canceled <<Focus>>

[*] -> Pending: sent msg to validate account
Pending --> TicketCreated: Kitchen replied successfully
TicketCreated --> PaymentCollected: Payment processed
PaymentCollected --> Created: Received payment processed msg
Pending --> Invalid: invalid account
Pending --> Canceled: received cancel request
Canceled --> [*]
Created --> [*]
Invalid --> [*]
@enduml

Prev: 一个安卓老用户换十三香之后的感受

Next: 如何打造一个serverless的微信小程序


Blog comments powered by Disqus.

© Wei Liu | 2024