微服务架构,你需要关注的哪些点
今天谈到系统架构模式,很难不联想起微服务架构。企业或组织在系统架构的实践过程中,从最初的单体架构,之后⾛向 SOA,逐渐分布式之后,最终产⽣了微服务架构。
微服务架构的出现,为应对快速变化的业务需求、冗长的开发周期提供了⼀种新的解决⽅案,它以模块化的思维应对快速变化的业务需求,解耦系统之间各个⼦系统、业务、数据库,甚⾄开发团队,使⽤如⾃动化部署、⾃动化业务监控预警、调⽤链监控、容器化,以及敏捷开发等思想加快软件的开发周期,实现更快速、更⾼质量的交付,成为当下最流⾏的架构风格之⼀。
微服务架构如此⽕热,开发者想要了解其相关知识点,可以通过看书、学习各个公司的实践经验,或者请教有经验的专家,要不就去听技术会议分享,同时⽹上也有很多相关理论与实践总结可以查看。
⽽我们之前通过⽹站上“⾼⼿问答”这⼀栏⽬,为⼤家提供了⼀个集中式向专家提问的机会,让更多⼈能够直接⾯对专家,提升微服务架构相关能⼒。当期观众提问与专家的回答有许多精彩之处,故整理出此⽂,以飨读者。
Q:微服务架构和传统的 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 的⼀些组件(⽐如均衡负载、配置服务、服务发现),如何才能分清它们之间的关系?
数据聚合其实涉及到微服务的⼀种设计模式,微服务的设计模式主要有以下⼏种:链式设计模式、聚合器设计模式、数据共享设计模式和异步消息控制模式。
聚合器设计模式是将请求统⼀由⽹关路由到聚合器,聚合器向下路由到指定的微服务中获取结果,并且完成聚合。⾸页展现、分类搜索和个⼈中⼼等通常都使⽤这种设计。
数据共享模式也是微服务设计模式的⼀种。应⽤通过⽹关调⽤多个微服务,微服务之间的数据共享通过同⼀个数据库,这样能够有效地减少请求次数,并且对于某些数据量⼩的情况⾮常适合。
也就是说,服务需要经过⼀定的设计处理。可以再⽹关部分实现数据查询的路由。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。