今天阅读了两篇关于微服务的文章,总结一些笔记,不敢贸然翻译:一是由于水平不够,翻译的过程会丢掉做者的原意;二是由于技术翻译是一个略微吃力不讨好的活。前端
微服务(micro services)这个概念不是新概念,不少公司已经在实践了,例如亚马逊、Google、FaceBook,Alibaba。微服务架构模式(Microservices Architecture Pattern)的目的是将大型的、复杂的、长期运行的应用程序构建为一组相互配合的服务,每一个服务均可以很容易得局部改良。 Micro这个词意味着每一个服务都应该足够小,可是,这里的小不能用代码量来比较,而应该是从业务逻辑上比较——符合SRP原则的才叫微服务。web
暂且不讨论大小问题,读者朋友你首先要考虑的是如何解决目前技术团队遇到的开发问题、部署问题。正是在解决这些问题的过程当中,才渐渐总结提炼出了微服务架构模式的概念。docker
微服务跟SOA有什么区别呢,能够把微服务当作去除了ESB的SOA。ESB是SOA架构中的中心总线,设计图形应该是星形的,而微服务是去中心化的分布式软件架构。数据库
接下来会讨论如下几个话题:后端
web应用程序发展的早期,大部分web工程是将全部的功能模块(service side)打包到一块儿并放在一个web容器中运行,不少企业的Java应用程序打包为war包。其余语言(Ruby,Python或者C++)写的程序也有相似的问题。服务器
假设你正在构建一个在线商店系统:客户下订单、核对清单和信用卡额度,并将货物运输给客户。很快,大家团队必定能构造出以下图所示的系统。网络
这种将全部功能都部署在一个web容器中运行的系统就叫作巨石型应用。巨石型应用有不少好处:IDE都是为开发单个应用设计的、容易测试——在本地就能够启动完整的系统、容易部署——直接打包为一个完整的包,拷贝到web容器的某个目录下便可运行。架构
可是,上述的好处是有条件的:应用不那么复杂。对于大规模的复杂应用,巨石型应用会显得特别笨重:要修改一个地方就要将整个应用所有部署(PS:在不一样的场景下优点也变成了劣势);编译时间过长;回归测试周期过长;开发效率下降等。另外,巨石应用不利于更新技术框架,除非你愿意将系统所有重写(代价过高你愿意老板也不肯意)。并发
详细一个网站在业务大规模爬升时会发生什么事情?并发度不够?OK,加web服务器。数据库压力过大?OK,买更大更贵的数据库。数据库太贵了?将一个表的数据分开存储,俗称“分库分表”。这些都没有问题,good job。不过,老外的抽象能力比咱们强,看下图Fig2。app
这张图从三个维度归纳了一个系统的扩展过程:
(1)x轴,水平复制,即在负载均衡服务器后增长多个web服务器;
(2)z轴扩展,是对数据库的扩展,即分库分表(分库是将关系紧密的表放在一台数据库服务器上,分表是由于一张表的数据太多,须要将一张表的数据经过hash放在不一样的数据库服务器上);
(3)y轴扩展,是功能分解,将不一样职能的模块分红不一样的服务。从y轴这个方向扩展,才能将巨型应用分解为一组不一样的服务,例如订单管理中心、客户信息管理中心、商品管理中心等等。
将系统划分为不一样的服务有不少方法:
(1)按照用例划分,例如在线商店系统中会划分出一个checkout UI服务,这个服务实现了checkout这个用例;
(2)按照资源划分,例如能够划分出一个catlog服务来存储产品目录。
服务划分有两个原则要遵循:
(1)每一个服务应该尽量符合单一职责原则——Single Responsible Principle,即每一个服务只作一件事,并把这件事作好;
(2)参考Unix命令行工具的设计,Unix提供了大量的简单易用的工具,例如grep、cat和find。每一个工具都小而美。
最后还要强调:系统分解的目标并不只仅是搞出一堆很小的服务,这不是目标;真正的目标是解决巨石型应用在业务急剧增加时遇到的问题。
对于上面的例子,按照功能和资源划分后,就造成下面图3的架构图。分解后的微服务架构包含多个前端服务和后端服务。前端服务包括Catalog UI(用于商品搜索和浏览)、Checkout UI(用于实现购物车和下单操做);后端服务包括一些业务逻辑模块,咱们将在巨石应用中的每一个服务模块重构为一个单独的服务。这么作有什么问题呢?
《人月神话》中讲到:没有银弹,意思是只靠一把锤子是盖不起摩天大楼的,要根据业务场景选择设计思路和实现工具。咱们看下为了换回上面提到的好处,咱们付出(trade)了什么?
在巨石型架构下,客户端应用程序(web或者app)经过向服务端发送HTTP请求;可是,在微服务架构下,原来的巨石型服务器被一组微服务替代,这种状况下客户端如何发起请求呢?
如图4中所示,客户端能够向micro service发起RESTful HTTP请求,可是会有这种状况发生:客户端为了完成一个业务逻辑,须要发起多个HTTP请求,从而形成系统的吞吐率降低,再加上无线网络的延迟高,会严重影响客户端的用户体验。
为了解决这个问题,通常会在服务器集群前面再加一个角色:API gateway,由它负责与客户度对接,并将客户端的请求转化成对内部服务的一系列调用。这样作还有个好处是,服务升级不会影响到客户端,只须要修改API gateway便可。加了API gateway以后的系统架构图如图5所示。
内部服务之间的通讯方式有两种:基于HTTP协议的同步机制(REST、RPC);基于消息队列的异步消息处理机制(AMQP-based message broker)。
Dubbo是阿里巴巴开源的分布式服务框架,属于同步调用,当一个系统的服务太多时,须要一个注册中心来处理服务发现问题,例如使用ZooKeeper这类配置服务器进行服务的地址管理:服务的发布者要向ZooKeeper发送请求,将本身的服务地址和函数名称等信息记录在案;服务的调用者要知道服务的相关信息,具体的机器地址在ZooKeeper查询获得。这种同步的调用机制足够直观简单,只是没有“订阅——推送”机制。
AMQP-based的表明系统是kafka、RabbitMQ等。这类分布式消息处理系统将订阅者和消费者解耦合,消息的生产者不须要消费者一直在线;消息的生产者只须要把消息发送给消息代理,所以也不须要服务发现机制。
两种通讯机制都有各自的优势和缺点,实际中的系统常常包含两种通讯机制。例如,在分布式数据管理中,就须要同时用到同步HTTP机制和异步消息处理机制。
在线商店的客户帐户有限额,当客户试图下单时,系统必须判断总的订单金额是否超过他的信用卡额度。信用卡额度由CustomerService管理、下订单的操做由OrderService负责,所以Order Service要经过RPC调用向Customer Service请求数据;这种方法可以保证每次Order Service都获取到准确的额度,单缺点是多一次RPC调用、并且Customer Service必须保持在线。
还有一种处理方式是,在OrderService这边存放一份信用卡额度的副本,这样就不须要实时发起RPC请求,可是还须要一种机制保证——当Customer Service拥有的信用卡额度发生变化时,要及时更新存放在Order Service这边的副本。
当一份数据位于多个服务上时,必须保证数据的一致性。
在实际工做中,不多有机会参与一个全新的项目,须要处理的差很少都是存在这样那样问题的复杂、大型应用。这时候如何在维护老服务的同时,将系统渐渐重构为微服务架构呢?
关于重构,有篇文章推荐你们阅读——推倒重来的讲究,关于重构有不少能够写的,但愿我能快速进步,多写点总结与你们分享。
微服务并非治百病的良药,也不是什么新的技术,我从中学到的最大的一点就是scale cube,从这个坐标轴出发去考虑大规模系统的构建比较容易分析和实践。