@Lenciel

采用事件驱动实施微服务架构

事件

我们在实践微服务架构的时候,根本目的是为了在“商业层面”拥有更加敏捷的系统:更容易响应需求变化,更容易添加、发布和尝试新功能,从而跑在竞争对手前面。

要做到敏捷,系统首先必须是自治的(autonomous)。自治性(autonomy)可以说是敏捷系统的一个先决条件:系统的各个部分相互之间如何沟通,当某个部分失败时如何处理和自动恢复等等,都需要自治性。自治性意味着系统的各个部分可以独立运作,对其他系统,团队和流程的依赖都可以shed:也就是说,对服务A的修改不应该影响到依赖它的服务B,A服务挂了,B服务也应该健在。

自治性的系统是微服务架构造就的吗?并不见得:真正成功实践了微服务架构的公司,真正重要的也不是这个技术而是组织架构上的先行。自治的系统,比如开源社区,城市,自由股票市场,甚至是一个迁徙中的鸟群,它们都不断地适应环境,响应变化,在失败案例中不断地学习。

这类被称为“复杂自适应系统(Complex Adaptive Systems)”的系统,是经过科学家专门研究,得出了很多结论的。其中很重要的一个就是,自治的系统会对“事件”作出“响应”。

当有事件发生时,一个自治的系统,不管是蚁群,人类组织,还是一个软件服务,会选择“做什么”或者“不做什么”,来进行响应。整个复杂的系统,都是这些事件在驱动的。这其实也很好理解,想想我们每天醒来,会根据温度穿衣;开车上班,会根据信号灯启停。我们人类的整个生活都是在对各种事件作出响应。

软件系统也可以被构造成这样:独立,自治,容错,可扩展。

从授权到自治,以及最终一致性

在很多分布式系统的实现里面,人们都通过创建一个单一地址空间来适应不稳定的网络环境。这是个从很多方面来看都错误的做法,但是它实现起来要简单一些:通过RPC调用,让remote的对象处理一些任务,或者请求一些数据。以电商里面结算购物车为例:购物车服务调用计价服务,计价服务可能会调用物流服务,根据发货地区和物流服务商等因素调整价格,同时购物车服务又会调用仓储服务来获取信息和更新货架。这就是所谓的“授权管理”模式:我们调用对数据有修改权限的服务,完成相应的操作。这种模式就意味着大量的全局状态和互斥锁,并且需要大量的事务。

并且,这种基于授权的设计也会导致瓶颈产生:一个服务挂掉,就容易雪崩;不同服务对数据需求不一样的时候,API越来越乱,或者产生一个大而全的统一API,提供给每个服务大量不需要的细节数据。

如果我们换个角度来看系统:不是依靠调用方对某个资源或者服务可以行使的权力来驱动系统,而是通过时间和时间轴上发生的事件来驱动系统,就像我们自己的实际生活一样。还是以电商的系统举例,我们的物流服务有没有可能知道目前顺丰在某个区域搞活动,使用顺丰有优惠,然后把这个数据保存在自己的数据库里面,这样每个订单产生时,这些区域的订单默认使用顺丰?如果我们的服务都这样来设计,它们的研发就不需要考虑太多依赖方当前的状态。

最终一致性?

通过事件驱动,而不是通过“just-in-time”的授权查询使得系统里各个服务能够更加自治,更好容错,更有弹性。但是影响复杂自适应系统的自治性的一个因素,也会影响自治的事件驱动系统,那就是时延“delays”。

如果你发现了某个事件已经发生,你立刻就可以做出反应。比如,有车强行变道进入你的车道,你会马上变道避让或者刹车。但是如果在“知道事件发生”这部分有时延,你的反应就没法那么迅速了,比如你正在训家里小朋友,结果没有发现有车变道进来了,就会“咣”…软件系统也一样。

么最终一致性指什么呢?再以购物为例。如果不是事件驱动的,那么如果你往购物车里面添加了某个商品,这时候仓储服务如果出了问题,你的查询没有返回,你就只好死等在那里。但是如果大家都使用事件驱动,你添加购物车的时候,发出了一个事件。这个时候仓储服务不在线,前端上看来,你还是把商品加入了购物车。当仓储系统恢复时,它收到之前那个事件,发现这个商品已经卖光了,这个时候它抛出一个“库存不足”的事件。购物车服务,计费服务等服务就根据当前用户的状态,去消费这个事件(如果没有结算就在结算的时候通知用户,如果已经结算就要退款或者补货等等)。这样让用户不被阻塞,并最终保持状态一致,就叫做最终一致性。

需要的技术

关于事件,延迟和一致性,再多说几句。事件只有在能够保证它们的时序的时候,才是可用的。也就是说,一组事件的时序,必须对于消费方来说是可信的。这涉及分布式系统里面的另外一个难题,对于构建“transactionality”也同样重要,以后再细说。但总的来说,如果事件乱序了,那么我们不做手工的修复就没有保持最终一致性。Martin Kleppmann管这个叫做“perpetual inconsistency”。时延,乱序,是分布式系统里面的两个难题。

Vhost threshold