微服务设计原则第二弹!一文带你彻底吃透,尽情徜徉微服务世界

昨天咱们整理了微服务架构的一部分设计原则,朋友们反映还不错,今天,咱们继续更新,每天都会让朋友们学到新知识,咱们每天进步一点点!!!

设计原则之服务拆分

拆分粒度不应该过分追求细粒度,要考虑适中,不能过大或过小。按照单一职责原则和康威定律,在业务域、团队和技术上平衡粒度。拆分后的代码应该是易控制、易维护的,业务职责也是明确单一的。

AKF扩展立方体是一个叫AKF公司的技术专家抽象总结的应用扩展的三个维度。理论上按照这三个扩展模式,可以将一个单体系统进行无限扩展。AKF 扩展立方如下图所示。

x轴:水平复制,即在负载均衡服务器后增加多个Web服务器。

y轴:功能分解,将不同职能的模块分成不同的服务。从y轴方向扩展,才能将巨型应用分解为一组不同的服务,例如,订单管理中心、商品信息管理中心、库存管理中心等。

z轴:对数据库的扩展,即分库分表(分库是将关系紧密的表放在一台数据库服务器上,分表是因为一张表的数据太多,需要将一张表的数据通过Hash放在不同的数据库服务器上)。

三个维度的扩展对比如下图所示:

下面看一下AKF的拆分实践。

拆分应用

x轴:从单体系统或服务,水平克隆出许多系统,通过负载均衡平均分配请求。

y轴:面向服务分割,基于功能或者服务分割,例如,电商网站可以将登录、搜索、下单等服务进行y轴的拆分,每一组服务再进行x轴的扩展。

z轴:面向查找分割,基于用户、请求或者数据分割,例如,可以将不同产品的SKU分到不同的搜索服务,可以将用户哈希到不同的服务等。

拆分数据库

x轴:从单库水平克隆为多个库上读,一个库写,通过数据库的自我复制实现,要允许一定的读写时延。

y轴:根据不同的信息类型分割为不同的数据库,即分库,例如,产品库、用户库等。

z轴: 按照一定算法进行分片, 例如,将搜索按照MapReduce 的原理进行分片,把SKU的数据按照不同的哈希值进行分片存储,每个分片再进行x轴冗余。

要做好微服务的分层:梳理和抽取核心应用、公共应用,作为独立的服务下沉到核心和共能力层,逐渐形成稳定的服务中心,使前端应用能更快速地响应多变的市场需求。

对于服务的拆分,要使用迭代演进的方式,不能一次性 完成所有的服务的拆分,需要确保团队可接受,粒度适中,同时需要优先考虑API的版本兼容性。不能够单纯以代码量来对服务拆分的成果进行评估。

设计原则之前后端分离

在传统的Web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端。

由于前后端分离这个概念相对来说刚出现不久,很多人都是只闻其声,不见其形,所以可能会对它产生一些误解,误以为前后端分离只是一种Web应用开发模式,只要在Web应用的开发期进行了前后端开发工作的分工就是前后端分离。

其实前后端分离并不只是开发模式,而是Web应用的一种架构模式。 在开发阶段,前后端工程师约定好数据交互接口,实现并行开发和测试;在运行阶段前后端分离模式需要对Web应用进行分离部署,前后端之前使用HTTP或者其他协议进行交互请求。

前后端分离原则,简单来讲就是前端和后端的代码分离,也就是技术上做分离。推荐的模式是直接采用物理分离的方式部署,进一步进行更彻底的分离。不要继续使用以前的服务端模板技术,比如JSP,把Java JS HTML CSS都堆到一个页面里,稍复杂的页面就无法维护。

这种分离模式的方式有几个好处:

前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。

分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。

前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的WebUI/移动App等访问。

前后端分离意味着前后端之间使用JSON来交流,两个开发团队之间使用API作为契约进行交互。从此,后台选用的技术栈不影响前台。

前后端分离并非仅仅只是前后端开发的分工,而是在开发期进行代码存放分离、前后端开发职责分离,前后端能够独立进行开发测试;在运行期进行应用部署分离,前后端之间通过HTTP请求进行通信。前后端分离的开发模式与传统模式相比,能为我们提升开发效率、增强代码可维护性,让我们有规划地打造一个前后端并重的精益开发团队,更好地应对越来越复杂多变的Web应用开发需求。

前后端分离的核心:后台提供数据,前端负责显示。

设计原则之版本控制

在团队的内部,尤其是API设计优先的微服务架构中,接口的版本管理显得尤其重要。

微服务的一个主要优势是,允许服务独立地演变。考虑到微服务会调用其他服务,这种独立性需要引起高度注意,不能在API中制造破坏性更改。

接纳更改的最简单方法是绝不破坏API。如果遵循稳健性原则,而且两端都保守地发送数据,慷慨地接收数据,那么可能很长一段时间都不需要执行破坏性更改。当最终发生破坏性更改时,可以选择构建一个完全不同的服务并不断退役原始服务,原因可能是领域模型已进化,而且一种更好的抽象更有意义。

如果对现有服务执行破坏性的API更改,应决定如何管理这些更改:

该服务是否会处理API的所有版本?是否会维护服务的独立版本,以支持API的每个版本?服务是否仅支持API的最新版本,依靠其他适应层来与旧API来回转换?在确定了困难部分后,如何在API中反映该版本是更容易解决的问题。

通常可通过3种方式处理REST资源的版本控制。

将版本放入URI中

将版本添加到URI中,这是指定版本的最简单方法。它的优点是非常容易理解,容易在微服务应用构建服务时实现,与API浏览工具和命令行工具兼容。如果将版本放在URI中,版本应该会应用于整个应用程序,所以使用/api/vl/accounts而不是/api/accounts/v1。

使用自定义请求标头

可以添加自定义请求标头来表明API版本。在将流量路由到特定后端实例时,路由器和其他基础架构可能会考虑使用自定义标头。但是,此机制不容易使用,原因与Accept标头不容易使用相同。此外,它是一个仅适用于应用程序的自定义标头,这意味着使用者需要学习如何使用它。

将版本放在HTTPAccept标头中,并依靠内容协商

Accept标头是一个定义版本的明显位置,但它是最难测试的地方之一。URI 很容易指定和替换,但指定HTTP标头需要更详细的API和命令行调用。

设计原则之围绕业务构建

正所谓“不围绕业务构建的架构就是耍流氓"。

微服务应当聚焦于某一特定的业务功能,并且确保完成它。其实这给需求管理也带来了挑战,需求需要切分将更加精细,以满足系统业务的不断变化。在传统的方式中,一般是产品人员进行需求调研,然后经过整理后提交给开发团队,这种方式在微服务的环境下需要重新定义,即产品核实需求后,需要在提交给开发团队之前进行评审,评审需要开发团队的人员参与,确认无误后再提交给开发团队。

从技术上说,微服务不应该局限于某个技术栈或者后端存储,可以非常灵活,以便于解决业务问题。这一点在非微服务的系统设计时,可能导致我们做一些妥协。而微服务可以让你用你认为最合适的方式解决问题。这和上面的统一框架 并不冲突,统一是指构建团队的过程中,尽量保持统一.的架构,从而降低交互和沟通所带来的额外成本。

系统可以根据业务切分为不同的子系统,子系统又可以根据重要程度切分为核心和非核心子系统。切分的目的就是当出现问题时,保证核心业务模块正常运行,不影响业务的正常操作。同时解决各个模块子系统间的耦合、维护及拓展性。方便单独部署,确保当一个系统出现问题时,不会出现连锁反应而导致整个系统瘫痪。

各个系统间合理地使用消息队列,解决系统或模块间的异步通信,实现高可用、高性能的通信系统。

设计原则之 CAP

CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency (一致性)、Availability(可用性)和Partition tolerance (分区容错性),三者不可兼得。

下面对分布式系统中的三个特性进行了归纳。

一致性 (C):在分布式系统中的所有数据备份在同一时刻是否有同样的值。

可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。

分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

掌握CAP定理,尤其是能够正确理解C、A、P的含义,对于系统架构来说非常重要。因为对于分布式系统来说,网络故障在所难免,如何在出现网络故障时,维持系统按照正常的行为逻辑运行就显得尤为重要。可以结合实际的业务场景和具体需求来进行权衡。

例如,对于大多数互联网应用来说,因为机器数量庞大,部署节点分散,网络故障是常态,可用性是必须要保证的,所以只有舍弃一致性来保证服务的AP。而对于银行等需要确保一致性的场景,通常会权衡CA和CP模型,CA模型网络故障时完全不可用,CP模型具备部分可用性。所以,在设计微服务的时候一定要选择合适的模型。

CA (consistency + availability),这样的系统关注一致性和可用性, 它需要非常严格的全体一致的协议,比如“两阶段提交”(2PC)。CA系统不能容忍网络错误或节点错误,一旦出现这样的问题,整个系统就会拒绝写请求,因为它并不知道对面的那个结点是否挂掉了,还是只是网络问题。唯一安全的做法就是把自己变成只读的。

CP (consistency + partition tolerance),这样的系统关注一致性和分区 容忍性。它关注的是系统里大多数人的一致性协议,比如Paxos算法(Quorum 类的算法)。这样的系统只需要保证大多数节点数据一致,而少数的节点会在没有同步到最新版本的数据时变成不可用的状态,这样能够提供一部分的可用性。

AP (availability + partition tolerance),这样的系统关心可用性和分区容忍性。因此,这样的系统不能达成一致性,需要给出数据冲突,给出数据冲突就需要维护数据版本,Dynamo 就是这样的系统。

设计原则之数据一致性

数据一致性分为以下几种情况。

强一致性

当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。这种是对用户最友好的,就是用户上一次写什么,下一次就保证能读到什么。根据CAP理论,这种实现需要牺牲可用性。

弱一致性

系统并不保证后续进程或者线程的访问都会返回最新的更新过的值。系统在数据写入成功之后,不承诺立即可以读到最新写入的值,也不会具体地承诺多久之后可以读到。

最终一致性

弱一致性的特定形式。系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值。在没有故障发生的前提下,不一致窗口的时间主要受通信延迟、系统负载和复制副本的个数影响。DNS是一个典型的最终一致性系统。

在工程实践上,为了保障系统的可用性,系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性来保证数据的最终一致性。

微服务架构下,完整交易跨越多个系统运行,事务一致性是-一个极具挑战的话题。依据CAP理论,必须在可用性(Avaliablitity) 和一致性(Consistency) 之间做出选择。我们认为在微服务架构下应选择可用性,然后保证数据的最终一致性。

在实践中有三种模式:可靠事件模式、业务补偿模式和TCC模式。

可靠事件模式:可靠事件模式属于事件驱动架构,当某件重要事情发生时,例如,更新一个业务实体,微服务会向消息代理发布一个事件,消息代理向订阅事件的微服务推送事件,当订阅这些事件的微服务接受此事件时,就可以完成自己的业务,可能会引发更多的事件发布。

业务补偿模式:补偿模式使用一个额外的协调服务来协调各个需要保证一致性的工作服务,协调服务按顺序调用各个工作服务,如果某个工作服务调用失败,则撤销之前所有已经完成的工作服务。要求需要保证一致性的工作服务提供补偿操作。

TCC模式:一个完整的TCC业务由一个主业务服务和若千个从业务服务组成,主业务服务发起并完成整个业务活动,TCC模式要求从服务提供三个接口——Try(负责资源检查)、Confrm (真正执行业务)和Cancel (释放Try阶段预留的资源)。

设计原则之设计模式

微服务的设计模式主要有以下几种:链式设计模式、聚合器设计模式、数据共享设计模式和异步消息控制模式。

链式设计模式

链式设计模式是常见的一种设计模式, 用于微服务之间的调用,应用请求通过网关到达第一个微服务,微服务经过基础业务处理,发现不能满足要求,继续调用第二个服务,然后将多个服务的结果统一返回到请求中。

聚合器设计模式

聚合器设计模式是将请求统一由网关路由到聚合器,聚合器向下路由到指定的微服务中获取结果,并且完成聚合,如下图所示。首页展现、分类搜索和个人中心等通常都使用这种设计。

数据共享模式

数据共享模式也是微服务设计模式的-种。应用通过网关调用多个微服务,微服务之间的数据共享通过同一个数据库,这样能够有效地减少请求次数,并且对于某些数据量小的情况非常适合,如下图。

异步消息设计模式

异步消息设计模式乍看起来跟聚合器的设计方式很像,唯一的区别就是网关和微服务之间的通信是通过消息队列而不是通过聚合器的方式来进行的,采用的是异步交互的方式。

以上就是小编整理的微服务常用的一些设计原则,通过这些原则的灵活运用,可以构建出一个高效的微服务系统。当然,微服务的构建是一个不断迭代、不断优化的过程,其最终目的是解决系统的性能瓶颈。也就是说,当发现系统出现瓶颈时,就需要考虑对系统基于一定的原则进行优化,提高系统的响应速度和可用性。

喜欢文章请多多点赞评论分享。让更多人看到获益,予人玫瑰,手留余香。

关注小编,后续会持续更新更丰富的Java架构学习内容。

你们的支持就是小编最大的创作动力哦~~~

你可能感兴趣的:(微服务设计原则第二弹!一文带你彻底吃透,尽情徜徉微服务世界)