服务的协做:服务间的消息传递——《微服务设计》读书笔记

不少开发者都表示他们基于HTTP的API是RESTful的。可是,如同Fielding在他的博客中所说,这些API可能并不都是RESTful的。Leonard Richardson为REST定义了一个成熟度模型,具体包含如下4个层次(摘自IBM):html

  • 第一个层次(Level 0)的 Web 服务只是使用 HTTP 做为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • 第二个层次(Level 1)的 Web 服务引入了资源的概念。每一个资源有对应的标识符和表达。
  • 第三个层次(Level 2)的 Web 服务使用不一样的 HTTP 方法来进行不一样的操做,而且使用 HTTP 状态码来表示不一样的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
  • 第四个层次(Level 3)的 Web 服务使用 HATEOAS。在资源的表达中包含了连接信息。客户端能够根据连接来发现能够执行的动做。


使用基于HTTP的协议有以下好处:

• HTTP很是简单而且你们都很熟悉。
• 可使用浏览器扩展(好比Postman)或者curl之类的命令行来测试API。
• 内置支持请求/响应模式的通讯。
• HTTP对防火墙友好的。
• 不须要中间代理,简化了系统架构。

不足之处包括:

• 只支持请求/响应模式交互。可使用HTTP通知,可是服务端必须一直发送HTTP响应才行。
• 由于客户端和服务端直接通讯(没有代理或者buffer机制),在交互期间必须都在线。
• 客户端必须知道每一个服务实例的URL。如以前那篇关于API Gateway的文章所述,这也是个烦人的问题。客户端必须使用服务实例发现机制。

开发者社区最近从新发现了RESTful API接口定义语言的价值。因而就有了一些RESTful风格的服务框架,包括RAMLSwagger。一些IDL,例如Swagger容许定义请求和响应消息的格式。其它的,例如RAML,须要使用另外的标识,例如JSON Schema。对于描述API,IDL通常都有工具来定义客户端和服务端骨架接口。

Thrift

Apache Thrift是一个颇有趣的REST的替代品。它是Facebook实现的一种高效的、支持多种编程语言的远程服务调用的框架。Thrift提供了一个C风格的IDL定义API。使用Thrift编译器能够生成客户端和服务器端代码框架。编译器能够生成多种语言的代码,包括C++、Java、Python、PHP、Ruby, Erlang和Node.js。

Thrift接口包括一个或者多个服务。服务定义相似于一个JAVA接口,是一组方法。Thrift方法能够返回响应,也能够被定义为单向的。返回值的方法其实就是请求/响应类型交互模式的实现。客户端等待响应,并可能抛出异常。单向方法对应于通知类型的交互模式,服务端并不返回响应。

Thrift支持多种消息格式:JSON、二进制和压缩二进制。二进制比JSON更高效,由于二进制解码更快。一样缘由,压缩二进制格式能够提供更高级别的压缩效率。JSON,是易读的。Thrift也能够在裸TCP和HTTP中间选择,裸TCP看起来比HTTP更加有效。然而,HTTP对防火墙,浏览器和人来讲更加友好。java

消息格式

了解完HTTP和Thrift后,咱们来看下消息格式方面的问题。若是使用消息系统或者REST,就能够选择消息格式。其它的IPC机制,例如Thrift可能只支持部分消息格式,也许只有一种。不管哪一种方式,咱们必须使用一个跨语言的消息格式,这很是重要。由于指不定哪天你会使用其它语言。

有两类消息格式:文本和二进制。文本格式的例子包括JSON和XML。这种格式的优势在于不只可读,并且是自描述的。在JSON中,一个对象就是一组键值对。相似的,在XML中,属性是由名字和值构成。消费者能够从中选择感兴趣的元素而忽略其它部分。同时,小幅度的格式修改能够很容器向后兼容。

XML文档结构是由XML schema定义的。随着时间发展,开发者社区意识到JSON也须要一个相似的机制。一个选择是使用JSON Schema,要么是独立的,要么是例如Swagger的IDL。

基于文本的消息格式最大的缺点是消息会变得冗长,特别是XML。由于消息是自描述的,因此每一个消息都包含属性和值。另一个缺点是解析文本的负担过大。因此,你可能须要考虑使用二进制格式。

二进制的格式也有不少。若是使用的是Thrift RPC,那可使用二进制Thrift。若是选择消息格式,经常使用的还包括Protocol BuffersApache Avro。它们都提供典型的IDL来定义消息架构。一个不一样点在于Protocol Buffers使用的是加标记(tag)的字段,而Avro消费者须要知道模式(schema)来解析消息。所以,使用前者,API更容易演进。这篇博客很好的比较了Thrift、Protocol Buffers、Avro三者的区别。
总结nginx

微服务必须使用进程间通讯机制来交互。当设计服务的通讯模式时,你须要考虑几个问题:服务如何交互,每一个服务如何标识API,如何升级API,以及如何处理部分失败。微服务架构有两类IPC机制可选,异步消息机制和同步请求/响应机制。在下一篇文章中,咱们将会讨论微服务架构中的服务发现问题。

原文连接:Building Microservices: Inter-Process Communication in a Microservices Architecture(翻译:杨峰 校对:李颖杰)apache

 

或许不少人会说 Spring Cloud 和 Dubbo 的对比有点不公平,Dubbo 只是实现了服务治理,而 Spring Cloud 下面有 17 个子项目(可能还会新增)分别覆盖了微服务架构下的方方面面,服务治理只是其中的一个方面,必定程度来讲,Dubbo 只是 Spring Cloud Netflix 中的一个子集。可是在选择框架上,方案完整度偏偏是一个须要重点关注的内容。编程

根据 Martin Fowler 对微服务架构的描述中,虽然该架构相较于单体架构有模块化解耦、可独立部署、技术多样性等诸多优势,可是因为分布式环境下解耦,也带出了很多测试与运维复杂度。json

根据微服务架构在各方面的要素,看看 Spring Cloud 和 Dubbo 都提供了哪些支持。api


以上列举了一些核心部件,大体能够理解为何以前说 Dubbo 只是相似 Netflix 的一个子集了吧。固然这里须要申明一点,Dubbo 对于上表中总结为“无”的组件不表明不能实现,而只是 Dubbo 框架自身不提供,须要另外整合以实现对应的功能,好比:浏览器

  • 分布式配置:可使用淘宝的 diamond、百度的 disconf 来实现分布式配置管理。可是 Spring Cloud 中的 Config 组件除了提供配置管理以外,因为其存储可使用 Git,所以它自然的实现了配置内容的版本管理,能够完美的与应用版本管理整合起来。
  • 服务跟踪:可使用京东开源的 Hydra
  • 批量任务:可使用当当开源的 Elastic-Job
  • ……

虽然,Dubbo 自身只是实现了服务治理的基础,其余为保证集群安全、可维护、可测试等特性方面都没有很好的实现,可是几乎大部分关键组件都能找到第三方开源来实现,这些组件主要来自于国内各家大型互联网企业的开源产品。安全

RPC vs REST

另外,因为 Dubbo 是基础框架,其实现的内容对于咱们实施微服务架构是否合理,也须要咱们根据自身需求去考虑是否要修改,好比 Dubbo 的服务调用是经过 RPC 实现的,可是若是仔细拜读过 Martin Fowler 的 microservices 一文,其定义的服务间通讯是 HTTP协议的 REST API。那么这两种有何区别呢?服务器

先来讲说,使用 Dubbo 的 RPC 来实现服务间调用的一些痛点:

  • 服务提供方与调用方接口依赖方式太强:咱们为每一个微服务定义了各自的 service 抽象接口,并经过持续集成发布到私有仓库中,调用方应用对微服务提供的抽象接口存在强依赖关系,所以不论开发、测试、集成环境都须要严格的管理版本依赖,才不会出现服务方与调用方的不一致致使应用没法编译成功等一系列问题,以及这也会直接影响本地开发的环境要求,每每一个依赖不少服务的上层应用,天天都要更新不少代码并 install 以后才能进行后续的开发。若没有严格的版本管理制度或开发一些自动化工具,这样的依赖关系会成为开发团队的一大噩梦。而 REST 接口相比 RPC 更为轻量化,服务提供方和调用方的依赖只是依靠一纸契约,不存在代码级别的强依赖,固然 REST 接口也有痛点,由于接口定义太轻,很容易致使定义文档与实际实现不一致致使服务集成时的问题,可是该问题很好解决,只须要经过每一个服务整合 swagger,让每一个服务的代码与文档一体化,就能解决。因此在分布式环境下,REST 方式的服务依赖要比 RPC 方式的依赖更为灵活。
  • 服务对平台敏感,难以简单复用:一般咱们在提供对外服务时,都会以 REST 的方式提供出去,这样能够实现跨平台的特色,任何一个语言的调用方均可以根据接口定义来实现。那么在 Dubbo 中咱们要提供 REST 接口时,不得不实现一层代理,用来将 RPC 接口转换成 REST 接口进行对外发布。若咱们每一个服务自己就以 REST 接口方式存在,当要对外提供服务时,主要在 API 网关中配置映射关系和权限控制就可实现服务的复用了。

相信这些痛点也是为何当当网在 dubbox(基于 Dubbo 的开源扩展)中增长了对 REST 支持的缘由之一。

小结:Dubbo 实现了服务治理的基础,可是要完成一个完备的微服务架构,还须要在各环节去扩展和完善以保证集群的健康,以减轻开发、测试以及运维各个环节上增长出来的压力,这样才能让各环节人员真正的专一于业务逻辑。而 Spring Cloud 依然发扬了 Spring Source 整合一切的做风,以标准化的姿态将一些微服务架构的成熟产品与框架揉为一体,并继承了 Spring Boot 简单配置、快速开发、轻松部署的特色,让本来复杂的架构工做变得相对容易上手一些(若是您读过我以前关于 Spring Cloud 的一些核心组件使用的文章,应该能体会这些让人兴奋而激动的特性,传送门)。因此,若是选择 Dubbo 请务必在各个环节作好整套解决方案的准备,否则极可能随着服务数量的增加,整个团队都将疲于应付各类架构上不足引发的困难。而若是选择 Spring Cloud,相对来讲每一个环节都已经有了对应的组件支持,可能有些也不必定能知足你全部的需求,可是其活跃的社区与高速的迭代进度也会是你能够依靠的强大后盾。

Round 4:文档质量

Dubbo 的文档能够说在国内开源框架中算是一流的,很是全,而且讲解的也很是深刻,因为版本已经稳定再也不更新,因此也不太会出现不一致的状况,另外提供了中文与英文两种版本,对于国内开发者来讲,阅读起来更加容易上手,这也是 Dubbo 在国内更火一些的缘由吧。

Spring Cloud 因为整合了大量组件,文档在体量上天然要比 dubbo 多不少,文档内容上还算简洁清楚,可是更多的是偏向整合,更深刻的使用方法仍是须要查看其整合组件的详细文档。另外因为 Spring Cloud 基于 Spring Boot,不少例子相较于传统 Spring 应用要简单不少(由于自动化配置,不少内容都成了约定的默认配置),这对于刚接触的开发者可能会有些不适应,比较建议了解和学习 Spring Boot 以后再使用 Spring Cloud,否则可能会出现不少只知其一;不知其二的状况。

小结:虽然 Spring Cloud 的文档量大,可是若是使用 Dubbo 去整合其余第三方组件,实际也是要去阅读大量第三方组件文档的,因此在文档量上,我以为区别不大。对于文档质量,因为 Spring Cloud 的迭代很快,不免会出现不一致的状况,因此在质量上我认为 Dubbo 更好一些。而对于文档语言上,Dubbo 天然对国内开发团队来讲更有优点。

总结

经过上面再几个环节上的分析,相信你们对 Dubbo 和 Spring Cloud 有了一个初步的了解。就我我的对这两个框架的使用经验和理解,打个不恰当的比喻:使用 Dubbo 构建的微服务架构就像组装电脑,各环节咱们的选择自由度很高,可是最终结果颇有可能由于一条内存质量不行就点不亮了,老是让人不怎么放心,可是若是你是一名高手,那这些都不是问题;而 Spring Cloud 就像品牌机,在 Spring Source 的整合下,作了大量的兼容性测试,保证了机器拥有更高的稳定性,可是若是要在使用非原装组件外的东西,就须要对其基础有足够的了解。

从目前 Spring Cloud 的被关注度和活跃度上来看,颇有可能未来会成为微服务架构的标准框架。因此,Spring Cloud 的系列文章,我会继续写下去。也欢迎各位朋友一块儿交流,共同进步。

原文连接: 微服务架构的基础框架选择:SpringCloud仍是Dubbo

 

 

如何将一个系统拆分红SCS(自包含系统)

在进行领域驱动设计(DDD)时,为了尽量下降SCS之间的耦合,每一个SCS应该实现一个 边界上下文 。每一个系统不仅拥有一个领域模型,事实上,一个系统能够包含多个不一样的领域模型。每个模型都有一个边界上下文。例如,在电子商务系统里搜索产品的当前价格时,产品的描述和数量是很重要的。而若是要向客户发货,则还须要其余的信息:产品的重量和客户的收货地址。将系统拆分红边界上下文是构建自包含系统最为有效的方式。

能够经过对用户故事进行分组来定义边界上下文。假设咱们经过全文检索来搜索产品,那么经过分类和推荐来搜索也应该属于相同的边界上下文。固然,有时候拆分并不会有很是清楚的界线,这要取决于搜索的复杂性。

在将系统拆分红SCS时也须要考虑到 用户体验 。用户体验描述了客户与系统之间的交互步骤,好比搜索产品、结帐或注册。每个步骤均可能成为一个SCS。这些步骤之间通常只有不多的依赖。这些步骤之间有承上启下的关系:购物车在结帐时就变成了一个订单,而后完成支付。

SCS不仅处理某种特定的领域对象。例如,使用一个SCS来处理全部的客户数据就没有多大意义:不少不一样的边界上下文都会用到客户数据。因此,为客户单首创建模型并在一个单独的SCS里实现是不可能的事情。若是真的这样子作了,那么每一个须要用到客户数据的系统都会依赖它。这也就是为何在将系统拆分红SCS时须要经过用户故事、边界上下文或用户体验来驱动,这种自上而下的方法会带来低耦合的系统。

虽然在后续有必要识别出公共部分,但这不该该成为关键点。公共逻辑能够被抽取到另外一个系统里,但这意味着SCS会对这个系统产生依赖,它们之间就产生了耦合。

 

     在微服务集成——《微服务设计》读书笔记文章中,咱们说过服务间的消息传递有几种方式,一种是请求/响应技术,另外一种是基于事件的机制。

RPC(远程过程调用)

      RPC是Remote Procedure Call的简称。

      这是请求/响应技术的一种,它使用本地调用的方式和远程进行交互,如SOAP、Thrift等,好比咱们常使用的WebService和Java RMI,就是这种类型。它先在本地生成桩代码,而后经过桩代码进行远程调用。

      RPC会带来一些问题,如Java RMI,其耦合性较紧,同时RPC会对调用进行大量的封装和解封装,同时修改接口时会形成服务的提供方和调用方都要修改。

 

REST

      REST是受Web启发而产生的一种架构风格,REST风格包含的内容不少,Richardson的成熟度模型(http://martinfowler.com/articles/richardsonMaturityModel.html),其中有对REST不一样风格的比较。

      REST自己并无提到底层应该使用什么协议,最经常使用的是HTTP,HTTP自己提供了不少功能,这些功能对于实现REST风格很是有用,好比HTTP的动词(GET、POST、PUT等)就能很好地和资源一块儿使用。

      在使用REST时,传输的数据格式是XML仍是JSON,这个没有一个定论。

基于HTTP的REST也有缺点:
1.它没法帮你生成桩代码(封装rest请求参数时须要)
2.在要求低延迟的场景下,每一个HTTP请求的封装开销多是个问题,使用TCP、UDP可能更合适。

 

基于事件的异步协做

       这种方式主要有两个部分须要考虑:微服务发布事件消费者接收事件机制。

      消息队列(如RabbitMQ)能够同进处理上述两方法的问题。生产者使用API向代理发布事件,代理能够向消费者提供订阅服务,而且在事件发生时通知消费者。这种代理甚至能够跟踪消费者的状态,如标记哪些消息是该消费者已经消费过的。这种系统一般具备较好的可伸缩性和弹性,但这么作会增长开发流程的复杂度,由于你须要一个额外的系统(即消息代理)才能开发及测试服务。

      另外一种方式是使用HTTP来传播事件,ATOM是一个符合REST规范的协议,能够经过它提供资源聚合的发布服务,当服务提供方发生改变时,只须要简单地向该聚合发布一个事件便可,消费者会轮询该聚合以查看变化。它的缺点是:HTTP不擅长处理低延迟的场景,并且使用ATOM的话,用户还须要本身追踪消息是否送达及管理轮询等工做。

      异步架构有其复杂性,好比,消息丢失了怎么办?消息重试失败了怎么办?消息重发了怎么办?消息请求崩溃了怎么办?咱们能够经过设置最大重试、黑名单、白名单等措施来解决这些问题。但这也意味着复杂性的增长。

 

参考

      《微服务设计》(Sam Newman 著 / 崔力强 张骏 译)

 

http://www.cnblogs.com/gudi/p/6624917.html