关于微服务架构,你需要关注的那些点

2018-10-24 10:22:50 浏览数 (1)

来自:开源中国 https://www.oschina.net/question/2720166_2283418

今天谈到系统架构模式,很难不联想起微服务架构。企业或组织在系统架构的实践过程中,从最初的单体架构,之后走向 SOA,逐渐分布式之后,最终产生了微服务架构。

微服务架构的出现,为应对快速变化的业务需求、冗长的开发周期提供了一种新的解决方案,它以模块化的思维应对快速变化的业务需求,解耦系统之间各个子系统、业务、数据库,甚至开发团队,使用如自动化部署、自动化业务监控预警、调用链监控、容器化,以及敏捷开发等思想加快软件的开发周期,实现更快速、更高质量的交付,成为当下最流行的架构风格之一。

微服务架构如此火热,开发者想要了解其相关知识点,可以通过看书、学习各个公司的实践经验,或者请教有经验的专家,要不就去听技术会议分享,同时网上也有很多相关理论与实践总结可以查看。

而我们之前通过网站上“高手问答”这一栏目,为大家提供了一个集中式向专家提问的机会,让更多人能够直接面对专家,提升微服务架构相关能力。当期观众提问与专家的回答有许多精彩之处,故整理出此文,以飨读者。

Q:微服务架构和传统的 SOA 架构有什么区别?

面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样系统中的服务可以以一种统一和通用的方式进行交互。

都是做服务化,那么微服务与 SOA 的异同有哪些呢?

相同点

  • 需要 Registry,实现动态的服务注册发现机制。
  • 需要考虑分布式下面的事务一致性,CAP 原则下,两段式提交不能保证性能,事务补偿机制需要考虑。
  • 同步调用还是异步消息传递,如何保证消息可靠性?SOA 由 ESB 来集成所有的消息。
  • 都需要统一的 Gateway 来汇聚、编排接口,实现统一认证机制,对外提供 APP 使用的 RESTful 接口。
  • 同样要关注如何再分布式下定位系统问题,如何做日志跟踪?就像电信领域做了十几年的信令跟踪的功能。

差异点

  • 是持续集成、持续部署?对于 CI、CD(持续集成、持续部署),这本身和敏捷、DevOps 是交织在一起的,所以更倾向于软件工程的领域而不是微服务技术本身。
  • 使用不同的通信协议是不是区别?微服务的标杆通信协议是 RESTful,而传统的 SOA 一般是 SOAP,不过目前来说采用轻量级的 RPC 框架(Dubbo、Thrift、gRPC)非常多,在 Spring Cloud 中也有 Feign 框架将标准 RESTful 转为代码的 API 这种仿 RPC 的行为,这些通信协议不应该是区分微服务架构和 SOA 的核心差别。
  • 是流行的基于容器的框架还是虚拟机为主?Docker 虚拟机和物理机都是架构实现的一种方式,不是核心区别。

SOA 和微服务的一个主要不同点就是自动化程度上的不同。大部分的 SOA 实现只达到服务级别的抽象,而微服务达到了对实现和运行环境的抽象级别。

在一个规范的微服务中,每个微服务应该被构建成胖 JAR(fat JAR),其中内置了所有的依赖,然后作为一个单独的 Java 进程存在。

Q:微服务业务层如何进行分层?业务系统如何定级,标准为什么?

一般微服务的分层需要根据公司的自身情况。

同一公司使用统一应用分层,以减少开发维护学习成本。应用分层看起来很简单,但每个程序员都有自己的一套方法,哪怕是初学者,所以想实施起来并非那么容易。

最早接触的分层架构应该是我们最熟悉的 MVC(Model-View-Controller)架构,其将应用分成了模型、视图和控制层,可以说引导了绝大多数开发者。而现在的应用(包括框架)中非常多架构设计都使用此模式。之后又演化出了 MVP(Model-View-Presenter)和 MVVM(Model-View-ViewModel)。这些可以说都是随着技术的不断发展,为了应对不同场景所演化出来的模型。

而微服务的每个架构都可以再细分成领域模型,下面看一下经典的领域模型架构。

它包括了 Domain、Service 和 Repositories。核心实体(Entity)和值对象(Value Object)应该在 Domain 层,定义的领域服务(Domain Service)在 Service 层,而针对实体和值对象的存储和查询逻辑都应该在 Repositories 层。

值得注意的是,不要把 Entity 的属性和行为分离到 Domain 和 Service 两层中去实现,即所谓的贫血模型,事实证明这样的实现方式会造成很大的维护问题。基于这种设计,工程的结构可以构造为:

当然,在微服务的架构中,每个微服务不必严格遵照这样的规定,切忌死搬硬套,最重要的是理解业务。在不同的业务场合,架构的设计可以适当地调整,毕竟适合的架构一定要具有灵活性。

分层的原则如下:

文件夹分层法

应用分层采用文件夹方式的优点是可大可小、简单易用、统一规范,可以包括5个项目,也可以包括50个项目,以满足所有业务应用的多种不同场景。

调用规约

在开发过程中,需要遵循分层架构的约束,禁止跨层次的调用。

下层为上层服务

以用户为中心,以目标为导向。上层(业务逻辑层)需要什么,下层(数据访问层)就提供什么,而不是下层(数据访问层)有什么,就向上层(业务逻辑层)提供什么。

实体层规约

Entity 是数据表对象,不是数据访问层对象;DTO 是网络传输对象,不是表现层对象;BO 是内存计算逻辑对象,不是业务逻辑层对象,不是只能给业务逻辑层使用。如果仅限定在本层访问,则导致单个应用内大量没有价值的对象转换。以用户为中心来设计实体类,可以减少无价值重复对象和无用转换。

U型访问

下行时表现层是 Input,业务逻辑层是 Process,数据访问层是 Output。上行时数据访问层是 Input,业务逻辑层是 Process,表现层是 Output。

Q:微服务的粒度到底怎么划分,有什么经验吗?

这个也是个设计问题,首先是业务必须熟悉,然后可以根据领域模型进行领域划分,拆分可以根据 AKF 扩展立方体(Scalability Cube)。

这个立方体有三个轴线,每个轴线描述扩展性的一个维度,他们分别是产品、流程和团队:

  • X轴 —— 代表无差别的克隆服务和数据,工作可以很均匀的分散在不同的服务实例上;
  • Y轴 —— 关注应用中职责的划分,比如数据类型,交易执行类型的划分;
  • Z轴 —— 关注服务和数据的优先级划分,如分地域划分。

三个维度扩展的对比

通过这三个维度上的扩展,可以快速提高产品的扩展能力,适应不同场景下产品的快速增长。不同维度上的扩展,有着不同的优缺点:

X轴扩展

  • 优点:成本最低,实施简单;
  • 缺点:受指令集多少和数据集大小的约束。当单个产品或应用过大时,服务响应变慢,无法通过X轴的水平扩展提高速度;
  • 场景:发展初期,业务复杂度低,需要增加系统容量。

Y轴扩展

  • 优点:可以解决指令集和数据集的约束,解决代码复杂度问题,可以实现隔离故障,可以提高响应时间,可以使团队聚焦更利于团队成长;
  • 缺点:成本相对较高;
  • 场景:业务复杂,数据量大,代码耦合度高,团队规模大。

Z轴扩展

  • 优点:能解决数据集的约束,降低故障风险,实现渐进交付,可以带来最大的扩展性。
  • 缺点:成本最昂贵,且不一定能解决指令集的问题;
  • 场景:用户指数级快速增长。

如何将理论付诸实践?

为扩展分割应用

  • X轴:从单体系统或服务,水平克隆出许多系统,通过负载均衡平均分配请求;
  • Y轴 :面向服务分割,基于功能或者服务分割,例如电商网站可以将登陆、搜索、下单等服务进行Y轴的拆分,每一组服务再进行X轴的扩展;
  • Z轴 :面向查找分割,基于用户、请求或者数据分割,例如可以将不同产品的SKU分到不同的搜索服务,可以将用户哈希到不同的服务等。

为扩展分割数据库

  • X轴:从单库,水平克隆为多个库上读,一个库写,通过数据库的自我复制实现,要允许一定的读写时延;
  • Y轴 :根据不同的信息类型,分割为不同的数据库,即分库,例如产品库,用户库等;
  • Z轴 :按照一定算法,进行分片,例如将搜索按照MapReduce的原理进行分片,把SKU的数据按照不同的哈希值进行分片存储,每个分片再进行X轴冗余。

为扩展而缓存

在理想情况下,处理大流量最好的方法是通过高速缓存来避免处理它。从架构层面看,我们能控制的主要有以下三个层次的缓存:

  • 对象缓存:对象缓存用来存储应用的对象以供重复使用,一般在系统内部,通过使用应用缓存可以帮助数据库和应用层卸载负载。
  • 应用缓存:应用缓存包括代理缓存和反向代理缓存,一个在用户端,一个在服务端,目标是提高性能或减少资源的使用量。
  • 内容交付网络缓存:CDN 的总原则是将内容推送到尽可能接近用户终端的地方,通过不同地区使用不同ISP的网关缓存,达到更快的响应时间和对源服务的更少请求。

为扩展而异步

  • 同步改异步:同步调用,由于调用间的同步依赖关系,有可能会导致雪崩效应,出现一系列的连锁故障,进而导致整个系统出现问题,所以在进行系统设计时,要尽可能的考虑异步调用方式,邮件系统就是一个非常好的异步调用例子。
  • 应用无状态:当进行 AKF 扩展立方体的任何一个轴上的扩展时,都要首先解决应用的状态问题,即会话的管理,可以通过避免、集中和分散的方式进行解决。

Q:微服务怎么实现事务管理的?

其实微服务的事务就是分布式事务,刚性事务和柔性事务。

刚性事务是指严格遵循 ACID 原则的事务,例如单机环境下的数据库事务。柔性事务是指遵循 BASE 理论的事务,通常用在分布式环境中,常见的实现方式有:两阶段提交(2PC),TCC 补偿型提交,基于消息的异步确保型,最大努力通知型。

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

强一致性

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

弱一致性

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

最终一致性

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

分布式事务的各种实现方式:

  • 如果业务场景需要强一致性,那么尽量避免将它们放在不同服务中,也就是尽量使用本地事务,避免使用强一致性的分布式事务。
  • 如果业务场景能够接受最终一致性,那么最好是使用基于消息的最终一致性的方案(异步确保型)来解决。
  • 如果业务场景需要强一致性,并且只能够进行分布式服务部署,那么最好是使用 TCC 方案而不是 2PC 方案来解决。

Q:在基于 Spring Cloud 的微服务架构中,使用 Docker 和 k8s 这些容器化技术能带来哪些方面的好处?对于中小规模的微服务架构中,是否有使用它们的必要性呢?

容器技术不是模仿硬件层次,而是在 Linux 内核里使用 cgroup 和 namespaces 来打造轻便的、将近裸机速度的虚拟技术操作系统环境。因为不是虚拟化存储,所以容器技术不会管底层存储或者文件系统,而是你放哪里,它操作哪里。

也就是说,它能更细粒度地控制 Linux,能够做到按需分配,我们企业级开发种经常面临的一个问题就是资源不足,而使用 Docker 可以更加有效地利用资源。这个跟企业的规模个人感觉不是很大。

Q:微服务模式下数据库的管理,多个服务之间的数据聚合怎么做才能避免数据过于分散导致查询实现困难?感觉 k8s 可以代替 Spring Cloud 的一些组件(比如均衡负载、配置服务、服务发现),如何才能分清它们之间的关系?

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

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

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

也就是说,服务需要经过一定的设计处理。可以再网关部分实现数据查询的路由。

说到 k8s 和 Spring Cloud,两个平台在核心领域都很强,并且在其它领域改进。Spring Cloud 可以快速使用、对开发者友好,然而 Kubernetes 对 DevOps 友好,艰难的学习曲线,但是覆盖更广泛的微服务障碍。以下是这些点的总结。

两种架构处理了不同范围的 MSA 障碍,并且它们从根本上用了不同的方法。Spring Cloud 方法是试图解决在 JVM 中每个 MSA 挑战,而 Kubernetes 方法是试图让问题消失,为开发者在平台层解决。Spring Cloud 在 JVM 中非常强大,Kubernetes 管理那些 JVM 很强大。同样的,它就像一个自然发展,结合两种工具并且从两个项目中最好的部分受益。

Q:请教一下,关于微服务架构中的 Service Mesh,它有哪些优势呢?

Service Mesh 最终并不是引入一项新功能,而是功能定位的转变。首先我们要知道 Web 应用程序总是必须管理服务间通信的复杂性。

Service Mesh 是一个网络模型,它是位于 TCP/IP 之上的抽象层,它假定底层的 L3/L4 网络是真实存在的,并且能够点对点地传递字节。但与 TCP 不同的是,Service Mesh 具有更高的性能。

它以专用基础设施层的形式存在,通常作为一组轻量级高性能网络代理,这些代理和程序代码部署在一起,但是应用程序不需要对代理有任何动作,它被用来处理服务间通讯,通过复杂的拓扑结构让请求传递的过程变得更可靠。

你可以思考下2000年的中型 Web 应用程序的典型架构: 三层应用程序。 在这个模型中,应用程序逻辑、Web 服务逻辑和存储逻辑都是单独的一层,层之间的通信虽然复杂,但这种复杂性是限定在一定范围内,因为毕竟只有两个跳转。这里没有“网格”(Mesh),但是在每个层的代码中处理的跳转之间有通信逻辑。

当这种架构方式在面对应用程序内部逻辑越来越复杂化的情形时,它就开始崩溃了。 像 Google、Netflix 和 Twitter 这样的公司无时无刻都面临着巨大的流量需求,它们实现了云原生方案的前身:应用层被分解成许多服务(有时称为“微服务”),层级间则形成了一个拓扑结构。

在这些系统中,广义的通讯层突然变得相关起来,但通常以“胖客户端”的库集(library)形式出现, 比如 Twitter 的 Finagle、Netflix 的 Hystrix,以及 Google 的 Stubby 就是这样的例子。

从很多方面上来讲,像 Finagle、Stubby 和 Hystrix 这些库集其实是 Service Mesh 的雏形。虽然它们受其周围环境的细节影响,并且需要使用特定的语言和框架,但是它们是用于管理服务到服务间通信的专用基础设施,并且(在开源 Finagle 和 Hystrix 库集的情形下)可以在其公司之外使用。

到了云原生应用时期,云原生模型本身结合了许多小型服务的微服务方法和两个额外的因素:容器(例如 Docker),它提供了资源隔离和依赖关系管理,以及一个编排层(例如 Kubernetes),它将底层硬件抽象出了一个同质池。

这三个组件支持应用程序在负载下可弹性伸缩的自然机制, 并能够处理云平台环境中存在的部分故障。

但面对数百个服务或数千个实例,和随时在重新安排实例的编排层,单个请求经由服务拓扑的路径可能非常复杂,而由于容器使每个服务用不同的语言写入处理变得更容易了,库集方法也就不再可行了。

这种复杂性和关键性的结合,激发了对服务到服务间通信的专用基础层的需求,这个专用层与应用程序代码分离出来,并能够捕捉底层环境的高度动态特性。就是这一专用层我们称之为 Service Mesh。这样 Service Mesh 的优势自然也就可以了解了。

Q:我是来自于一家中小企业的运维和开发人员,一直对微服务架构很感兴趣,请问一下如果我们企业将来打算采用微服务架构,我们将面临着哪些挑战?

面临的挑战:

  • 思想的转变。首先要彻底地理解什么是微服务,要知道它相比单体架构、SOA 架构的不同是什么、优劣是什么,具体如何落地等问题。
  • 新技术以及新框架的学习。比如spring boot、docker等。

一些建议:

  • 通过查阅相关资料,对传统架构和微服务架构的区别以及演变流程,可以首先有一个概念性的了解。
  • 可以先让一部分人使用微服务架构并且做到深入的程度,然后再在企业中整体推广。

篇幅限制,只截取了部分,完整内容可以点击下方“阅读原文”查看。

嘉宾:张锋,《微服务架构实战》一书作者,北京航空航天大学软件工程硕士,资深架构师,有10多年管理和架构经验,在业界颇具威望和影响力。曾就职于神州数据、亚信科技、中文在线及多家互联网公司,担任架构师及技术总监等职位,现在就职于中青旅,任架构组组长,成功管理和指导过三农综合服务信息平台、西北企业云服务平台、省级电信平台及多个互联网平台的架构升级改造。拥有工信部认证高级信息系统项目管理师资格。

0 人点赞