使用消息系统集成和扩展微服务

  服务之间交互的风格有两种:同步和异步。 所谓同步交互,服务调用者会发出一个调用请求,并且堵塞等到操作完成得到响应,HTTP协议是一个很好的同步交互案例,通常是以请求/响应的同步风格为主;而异步交互风格,服务调用者发出一个请求,但是不会等待被调用的服务操作的完成,也就是不会等到接受到响应,而是只要请求一旦确认被接受,服务调用者就继续做其他事情,这种交互典型是发布/订阅(publish/subscribe)风格,服务调用者也就是消费者不再是直接调用另外一个服务的操作,而是产生了一个事件,希望赶兴趣的消费者能够响应react。

orchestration与choreography区别

这两种都是消息系统的不同风格,都属于异步方式的一种。

orchestration是一种类似管弦乐编曲一样的业务流程调用风格,也就是一个 服务A和一个服务B交互,如果服务A负责调用服务B,这就是orchestration;而如果是服务B只订阅了相关事件,这就是choreography,一种类似舞蹈编排的调用风格。

在服务orchestration中,会存在一个中央实体(如服务A自己),它会知道其他哪些服务被调用,而使用choreography方式,这种职责委托给独立的服务,它们只负责订阅感兴趣的事件就可以了。

 

orchestration业务流程风格

在微服务项目中,服务代码经常修改,orchestration方式的服务交互属于点对点的异步交互,这样微服务之间造成相互依赖,导致修改一个服务,影响一个业务流程上的其他服务调用。如下图:

微服务的业务流程法

这种方式在实现跨几个服务的业务事务时增加了很多复杂性。因为业务事务跨几个服务,处理失败变得非常小心,这个服务失败会对整个业务流程事务有影响吗?如果有,那么事务就得退出,返回一个有意义的错误给调用者,另外一方面,当系统从失败中恢复时,我们需要让这个业务事务继续成功处理完成。

orchestration在消息系统实现中是采取队列方式,虽然在业务上造成服务之间依赖,但是由于队列方式比较易于扩展,只要增加队列的消费服务的数量,队列会在这多个消费者之间做负载平衡。

队列

上图中Customer服务通过Email队列发送消息给Email服务,通过Loyalty Point队列发送给Loyalty Point服务,Email服务可以有多个,Loyalty Point服务也有多个实例,队列会在这些多个服务实例之间做负载平衡。

 

choreography的发布/订阅风格

choreography编舞风格能够限制业务事务的边界,上游服务发送事件,而下游服务订阅这些事件,这就提供足够的隔离,如下图通过这种事件流方式实现微服务集成:

订阅/发布

这种与orchestration不同在于:以客户注册过程来举例,在orchestration业务流程方式下,当一个新的客户注册,客户服务会实现整个客户的创建流程:保存新客户的细节资料,调用下游其他服务,这样客户会收到一个欢迎的电子邮件,获得他的第一个成员积分点。

而在基于事件的choreography风格下:新客户只是发出创建事件customer_created 给下游服务,如下:

app.post('/', function(req, res) {
  customers.push(req.body);
  var event = { 'type':'customer_created', 'data':req.body };
  publish(event);
  res.sendStatus(200);
});

客户创建的事务就局限在了客户服务中,只是简单地发布新的客户事件并让全世界都知道,任何下游服务能够订阅这个事件流,当这种事件一旦被发布,订阅者会异步收到通知,比如email服务:

http.listen(3001, function() {
  eventStore.subscribe('customer_created',
  function(customer) {
    sendWelcomeEmail(customer);
  });
  console.log('email service listening on *:3001');
});

Email服务订阅了客户创建的事件。

choreography风格在消息系统中使用topic实现发布/订阅模型,如下图:

topic

如果我们只是增加Loyalty Point服务实例,并不能扩展处理能力,因为这两个Loyalty Point服务会收到相同的事件。

所以,处理这种事件流的发布/订阅方式我们可以采取分布式日志如Apache Kafka来实现。

 

使用事件流扩展微服务

微服务专题