当前位置: 首页 > 科技观察

Java程序员必知——基于微服务的软件架构模式

时间:2023-03-12 01:34:20 科技观察

microservices(微服务)的概念并不是一个新概念,已经有很多公司在实践,比如Amazon、Google、FaceBook、Alibaba。微服务架构模式的目的是将大型、复杂、长时间运行的应用程序构建成一组协作服务,每个服务都可以在本地轻松改进。微这个词意味着每个服务都应该足够小。但是,这里的小不能用代码量来比较,而应该从业务逻辑的角度来比较——只有符合SRP原则的才叫微服务。大小问题暂且不谈。各位读者,首先要考虑的是如何解决当前技术团队遇到的开发部署问题。正是在解决这些问题的过程中,逐渐总结和提炼出微服务架构模型的概念。微服务和SOA有什么区别?微服务可以看作是没有ESB的SOA。ESB是SOA架构中的中心总线,设计图应该是星型的,而微服务是去中心化的分布式软件架构。接下来将讨论以下主题:应用微服务的动机、微服务与传统单体应用相比的优缺点、应用微服务架构设计时可能遇到的关键问题(内部服务通信、分布式数据管理)1早期的monolithweb应用开发,大部分的web项目都是将所有的功能模块(服务端)打包在一起,运行在一个web容器中。许多企业Java应用程序被打包为war包。用其他语言(Ruby、Python或C++)编写的程序也有类似的问题。假设您正在构建一个在线商店系统:客户下订单,检查清单和信用卡限额,然后将货物运送给客户。很快,您的团队将能够构建如下图所示的系统。图1-单体架构这种将所有功能部署在一个Web容器中运行的系统称为单体应用程序。单体应用有很多优点:IDE是为开发单体应用而设计的,易于测试——一个完整的系统可以在本地启动,易于部署——直接打包成一个完整的包,复制到web容器的某个目录下运行。然而,上述好处是有条件的:应用程序不那么复杂。对于大型复杂应用,巨石型应用会显得特别笨重:修改一个地方,必须部署整个应用(PS:不同场景下优势变成了劣势);编译时间过长;回归测试周期太长;开发效率降低等。另外,单体应用不利于技术框架的更新,除非你愿意完全重写系统(成本太高,甘心不甘做老大)。2.应用拆分细则一个网站业务大规模上量后会怎样?并发度不够?好的,添加一个网络服务器。数据库压力太大?好的,买一个更大更贵的数据库。数据库太贵?单独存储一张表的数据,俗称“分库分表”。这些都没有问题,干得好。不过老外的抽象能力比我们强,见下图2。图2——尺度立方体本图从三个维度概括了一个系统的膨胀过程:①.X轴,水平复制,即在负载均衡服务器后面增加多个web服务器;②.Z轴扩容,是对数据库进行扩容,即分库分表(分库是把关系密切的表放在一个数据库服务器上,分表是因为一个表的数据太多了,并且需要将一张表的数据通过hash放到不同数据库的服务器上);③.y轴展开是功能分解,将不同功能的模块划分为不同的服务。只有向y轴方向扩展,才能将这个庞大的应用分解成一组不同的服务,比如订单管理中心、客户信息管理中心、商品管理中心等等。将系统划分为不同服务的方法有很多种:①.根据用例,例如在网店系统中会划分一个结账UI服务,实现结账用例;②.按照资源划分,比如catlog可以划分service来存放产品目录。服务划分有两个原则:①.每个服务都应该尽可能的符合单一职责原则——SingleResponsibilityPrinciple,即每个服务只做一件事,并且把它做好;②.参考Unix命令行工具的设计,Unix提供了大量简单易用的工具,如grep、cat和find。每个工具都小巧而美观。最后我想强调一下:系统分解的目的不仅仅是创建一堆小服务,这不是目的;真正的目标是解决单体应用在业务快速增长时遇到的问题。对于上面的例子,按照功能和资源进行划分后,形成了下图3的架构图。分解后的微服务架构包含多个前端服务和后端服务。前端服务包括CatalogUI(用于商品搜索和浏览)、CheckoutUI(用于实现购物车和下单操作);后端服务包含了一些业务逻辑模块,我们将重构聚石应用中的各个服务模块,做一个单独的服务。这样做有什么问题?图3-微服务架构三、微服务架构的优缺点1.优点每个服务足够内聚,足够小,代码容易理解,提高开发效率;服务可以独立部署,微服务架构让持续部署成为可能;每个服务都可以独立扩展x和z,每个服务都可以根据自己的需要部署在合适的硬件服务器上;易于扩展开发团队,可以针对每个服务(service)组件开发团队;提高故障隔离性,一个服务的内存泄漏不会导致整个系统瘫痪;系统不会长期局限于某个技术栈。2.缺点《人月神话》提到:没有银弹,也就是说摩天大楼不能只用锤子建造,必须根据业务场景选择设计思路和实现工具。我们来看看我们付出(交易)了什么,换来了上面所说的好处?开发人员必须处理分布式系统的复杂性;开发人员必须设计服务之间的通信机制,对于那些需要多个后端服务的用例,没有分布式事务很难实现代码;涉及多个服务的直接自动化测试也相当具有挑战性;服务管理的复杂性,在生产环境中,需要管理多个不同的服务例如,这意味着开发团队需要统筹规划(PS:docker的出现适合解决这个问题)如何把握时机应用微服务架构?业务还没有明确,业务数据和处理能力还没有开始爆发式增长,创业公司不需要考虑微服务架构模型。这个时候最重要的就是快速开发、快速部署、快速试错。4.微服务架构的关键问题1.微服务架构的通信机制(1)客户端与服务器的通信在巨石架构下,客户端应用程序(web或app)向服务器端发送HTTP请求;但是在微服务架构下,原来的单体服务器被一组微服务所取代。在这种情况下,客户端如何发起请求呢?如图4所示,客户端可以向微服务发起RESTfulHTTP请求,但是会出现这种情况:为了完成一个业务逻辑,客户端需要发起多次HTTP请求,导致系统吞吐量下降,加上加上无线网络的高延迟,会严重影响客户端的用户体验。Fig4-直接调用服务为了解决这个问题,一般会在服务端集群前面加一个角色:API网关,负责与客户端连接,将客户端的请求转化为对内部服务的一系列调用。这样做的另一个好处是服务升级不会影响客户端,只需要修改API网关即可。添加API网关后的系统架构图如图5所示。图5-API网关内部服务之间的通信(2)内部服务之间的通信方式有两种:基于HTTP协议的同步机制(REST、RPC);基于消息队列的异步消息处理机制(AMQP-basedmessagebroker)。Dubbo是阿里巴巴开源的分布式服务框架,属于同步调用。当一个系统的服务过多时,需要一个注册中心来处理服务发现。例如,使用ZooKeeper这样的配置服务器来管理服务的地址:服务的发布者向ZooKeeper发送请求,记录你的服务地址、函数名等信息;服务的调用者需要知道服务的相关信息,具体的机器地址可以通过查询ZooKeeper获得。这种同步调用机制足够直观和简单,但是没有“订阅-推送”机制。代表性的基于AMQP的系统有kafka、RabbitMQ等,这类分布式消息处理系统将订阅者和消费者解耦。消息的生产者不需要消费者一直在线;消息的生产者只需要将消息发送给消息代理,因此不需要服务发现机制。两种通信机制各有优缺点,实际系统中往往包含两种通信机制。例如在分布式数据管理中,既需要使用同步HTTP机制,又需要使用异步消息处理机制。2.分布式数据管理(1)处理读取请求在线商店的客户帐户有一个限制。当客户尝试下订单时,系统必须确定总订单金额是否超过其信用卡限额。信用卡额度由CustomerService管理,OrderService负责下单操作。因此OrderService需要通过RPC调用向CustomerService请求数据;这种方式可以保证OrderService每次都能获得准确的积分。唯一的缺点是多了一个RPC调用,而且客服必须保持在线。另一种处理方式是在OrderService端存储一份信用卡额度,这样就不需要实时发起RPC请求,但是需要一种机制来保证当信用卡额度拥有时由客户服务更改,必须及时更新存储在订单服务端的副本。(2)处理更新请求当一条数据位于多个服务上时,必须保证数据的一致性。分布式事务(Distributedtransactions)使用分布式事务很直观,就是在CustomerService上更新信用卡额度,必须同时更新其他服务上的副本。这些操作要么全有,要么全无。使用分布式事务可以保证数据的强一致性,但是会降低系统的可用性——所有相关服务必须始终在线;而且,很多现代技术栈都不支持事务,比如REST、NoSQL数据库等。经纪人(消息经纪人)”;其他订阅该事件的服务在收到提示后更新数据。事件流程如图6所示。图6-使用事件复制信用额度5.重构单体应用在实际工作中,很少有机会参与到一个全新的项目中,而且几乎都是复杂而庞大的需要处理的规模化应用存在各种问题。这时候,如何在维护老服务的同时,逐步将系统重构为微服务架构呢?不要让事情变得更糟。当新的需求来了,如果能独立开发一个服务,单独开发,然后服务老服务,直接用新服务写胶水代码(GlueCode)——这个过程并不容易,但这是分解的第一步巨型服务,如图7所示;作为独立服务的模块,一般适合独立模块,具有以下特点:两个模块的资源需求有冲突(一个是CPU密集型,一个是IO密集型);授权认证层也适合单独分离一个服务。每分离出一个服务,都需要编写相应的胶水代码,与剩下的服务进行通信。这样,在逐步演进的过程中,完成了整个系统的架构更新。关于重构,有一篇文章推荐大家阅读——强调推倒重来。有很多关于重构的文章。希望自己能进步快点,多写总结分享给大家。综上所述,微服务不是包治百病,也不是什么新技术。我从中学到的最大的东西就是刻度立方体。从这个轴考虑构建大型系统时更容易分析和实践。