微服务设计阅读学习

微服务的概念网上都有,各种博客都有解释。但是自己没有上手写代码,没有做工程项目,实际上是很难体会的。 微服务与SOA(面向服务的架构)的区别主要在于微服务中每个服务是一个独立的进程,它能够被独立的部署。若该服务宕机,并不影响整个系统中其他服务的正常运行。

在开始尝试做一个新的系统时,若常用微服务的方式,则需要使用限界上下文划分微服务边界。限界上下文指的是一个由显式边界限定的特定职责。如果你想要从一个限界上下文中获取信息,或者向其发起请求,需要使用模型和它的显式边界进行通信。实际上寻找限界上下文边界就是将整个业务逻辑进行一个粗粒度的划分。对于一个新系统而言,过早划分很容易错误判断服务之间的边界,按照书中内容所说,很多时候,将一个已有的代码库划分成微服务,要比从头开始构建微服务简单得多。

当你在思考组织内的限界上下文时,不应该从共享数据的角度来考虑,而应该从这些上下文能够提供的功能来考虑。服务与服务之间如果能够做到低耦合,高内聚,那么这就是一个好的微服务系统。实际上,要做到低耦合,高内聚还是很困难的,在工程项目中很可能遇到一份代码需要多次拷贝使用,当遇到这种情况时,就需要注意DRY(don’t repeat yourself)。应该考虑使用更好的设计模式来避免这种情况,因为很容易出现,一个地方被修改了,但是另一个地方忘记修改的情况。

服务集成是微服务相关技术中最重要的一个问题,按照作者的话来说:做得好的话,你的微服务可以保持自治性,你也可以独立地修改和发布它们;但做得不好的话会带来灾难。在选择集成方式时,需要注意以下几个原则:1.避免破坏性修改 2. 保证API的技术无关系3.使你的服务易于消费方使用4.隐藏内部实现细节。服务之间的通信可以分为同步和异步两种:如果使用同步通信,发起一个远程服务调用后,调用方会阻塞自己并等待整个操作的完成。如果使用异步通信,调用方不需要等待操作完成就可以返回,甚至可能不需要关心这个操作完成与否。这两种不同的通信模式有着各自的协作风格,即请求/响应或者基于事件。对于请求/响应来说,客户端发起一个请求,然后等待响应。这种模式能够与同步通信模式很好地匹配,但异步通信也可以使用这种模式。我可以发起一个请求,然后注册一个回调,当服务端操作结束之后,会调用该回调。对于使用基于事件的协作方式来说,情况会颠倒过来。客户端不是发起请求,而是发布一个事件,然后期待其他的协作者接收到该消息,并且知道该怎么做。

服务与服务之间常见有两种常见的架构风格:编排与协同。

upload successful

对于上图用户注册这样一个业务逻辑,如果用编排的风格来设计服务,我们可以得到如下的架构图:

upload successful
很显然,若编排的架构使用的是同步通信的机制,即请求/响应的协作方式,那么我们能够得到每一个服务返回的结果。当然,编排的架构也能使用基于回调的异步通信。编排架构的缺点在于,客户服务承担了太多的职责,而剩下的三个服务按作者的话来说:会成为贫血的CRUD服务。

如果采用协同的架构风格,我们可以得到下面这个架构图:

upload successful

可以仅仅从客户服务中使用异步的方式触发一个事件,该事件名可以叫作“客户创建”。电子邮件服务、邮政服务及积分账户可以简单地订阅这些事件并且做相应处理,如上图所示,这种方法能够显著地消除耦合。使用协同的方式组织服务,很显然必定是异步的。使用这种发布-订阅的模式,是当前非常流行的一种通信模式,典型的就是消息队列,比如RabbitMQ。这种模式能够很大程度的在服务之间进行解耦,但是它的一个问题在于无法检测服务是否成功执行,比如电子邮件服务出现问题,无法发送邮件,此时整个系统是否能够检测到该问题,并进行处理。一个常见的解决方案是构建一个与业务逻辑流程图相匹配的监控系统。实际的监控活动是针对每个服务的,但最终需要把监控的结果映射到业务流程中。针对请求响应的协同方式,常用有两种技术:RPC和REST(表征性状态转移)风格的HTTP。针对基于事件的协同方式,一般采用消息队列来实现。

微服务的部署相对于单体应用来说,也是一个较为复杂的问题。CI/CD(持续集成/持续部署)是当前非常重要的一种思想。按照书中所说,判断你的项目是否CI,可以通过回答一下几个问题来判断:1.你是否每天签入代码到主线?2.你是否有一组测试来验证修改?3.当构建失败后,团队是否把修复CI当作第一优先级的事情来做?我个人感觉CI/CD应该是用来解决开发和运维之间的矛盾,应该需要一个DevOps系统来实现这种思想。