当前位置:首页 > 架构 > 正文内容

系统架构的演进之路-单体到SOA到微服务

phpmianshi2年前 (2019-05-10)架构336

单体系统的困难


在微服务出现之前,互联网应用系统主要是单体系统,也就是说一个网站的整个系统由一个应用构成。如果是 Java,就打包成一个 war 包,一个 war 包包含整个应用系统,系统更新的时候,即使只是更新其中极小的一部分,也要重新打包整个 war 包,发布整个系统。


这样的单体系统面临的挑战主要是什么呢?


1.编译、部署困难


2.随着网站的业务不断发展,系统会变得越来越庞大,最后变成一个巨无霸的系统。


3.代码分支管理困难


4.数据库连接耗尽


5.新增业务困难


6.发布困难


微服务架构


解决上述问题的主要手段是将一个单体的巨无霸系统,根据模块以及复用的粒度进行拆分,拆分成多个可以独立部署的分布式服务。应用通过远程访问调用的方式,使用这些服务,构成一个系统。但是由于它的核心服务是在其他的服务器上分布部署的,本身的业务逻辑可以变得比较简单,这样就把一个巨无霸系统单体应用拆成了若干个可复用的服务,利用较少的逻辑代码就可以组成一个应用系统。


SOA 架构


这样的设计思路其实并不是在互联网时代才出现的。在早期的时候,就有人提出了 SOA 面向服务的体系架构。在面向服务的体系架构里面,服务的提供者向注册中心注册自己的服务,而服务的使用者向注册中心去发现服务。发现服务以后,根据服务注册中心提供的访问接口和访问路径对服务发起请求,由服务的提供者完成请求返回结果给调用者。现在的微服务或者分布式服务,其实也是 SOA 架构的一种实现。但是在早期的 SOA 架构实践中,服务的注册与服务的调用都非常复杂,服务调用效率也比较低。


后来在互联网时代的微服务中,人们简化了 SOA 架构中的调用规范和服务规范,形成了我们现在所熟悉的分布式微服务架构。


在微服务体系中,连接数据库的是具体的服务,应用系统不需要自己去连接数据库,只需要调用组合服务,对服务进行编排。所以对数据库的连接也相对比以前更少一些。最主要的是当需要开发新业务的时候,使用这种方式不需要对原有的单体系统进行各种重构和代码修改,只需要开发一个新的业务系统,组合调用现有的微服务,就可以组合出来一个新的产品功能,可以快速开发新产品。


微服务架构策略

对微服务架构而言,技术现在其实比较成熟。使用什么样的技术去实现一个微服务,本身并没有太多的困难。构建一个微服务架构最困难的还是服务治理,也就是业务划分。一个微服务包含的功能有哪些?服务的边界是什么?服务之间的依赖关系如何?这些关键的问题决定了服务的复用程度,维护的难易程度,开发的便利程度。所以设计微服务架构的时候,首先要关注的是业务,业务要先行,理顺业务模块之间的边界和依赖,做好服务治理和调用依赖管理。


微服务最主要的目的还是实现服务治理——如何划分和管理服务。首先要有独立的功能模块,然后才有分布式的服务。也就是说在软件设计的时候,软件功能模块之间的依赖关系就要清晰、合理、规范、便于维护、便于扩展,便于实现新的功能。服务之间的依赖关系要清晰、参数要简单、耦合关系要少。设计好这样的模块化结构以后,将这些设计好的模块,拆分成独立的微服务进行部署和调用,就可以构建一个良好的微服务系统。如果模块本身就是混乱的、耦合严重的、边界不清晰的、关系复杂的,那么,把它们拆分成独立的微服务进行部署,只会使事情变得更加复杂。


微服务的使用模式


一、事件溯源


第一是事件溯源,因为微服务的调用过程会比较复杂,调用链路可能会比较长。如果某个微服务调用出错,如何进行管理和监控?使用事件溯源这种模式是一种解决办法。

所谓的事件溯源是指将用户的请求处理过程,每一次的状态变化都记录到事件日志中,并按照时间序列进行持久化的存储,也就是说,把所有的变更操作都按日志的方式,按时间化序列进行记录。

使用事件溯源的好处有如下两点。

1.可以精确地复现用户的状态变化。

用户执行了哪些操作,使它成为现在这样一种状况,然后通过事件溯源的方式,追溯以往的操作和动作,从而进行复核和审计。当用户投诉的时候,当状态不一致的时候,可以通过事件溯源中的日志进行审计和查找。

2.可以有效监控用户的状态变化,并在此基础上实现分布式的事务。

我们传统的事务使用数据库事务进行实现,可以将多个数据库操作统一提交,或者统一回滚,保持数据的一致性,但是在分布式状况下,对数据的操作是分布在多个独立部署的服务进行处理。这个时候就无法使用数据库的事务进行管理。


那么,如何在这种情况下实行分布式系统的事务?


事件溯源是一种办法。因为事件溯源将所有的数据变更都按日志的方式记录起来,所以如果日志不完整,我们就知道事务不完整,可以对事务进行重组或者补偿操作,从而使数据变得一致。


二、命令与查询职责隔离(CQRS)


这种模式在服务接口层面将查询操作(也就是读操作)和命令操作(也就是写操作)隔离开来,在服务层实现读写分离。

使用 CQRS 模式,主要的好处是可以有更清晰的领域模型,根据操作的方式不同,使用不同的领域模型。还可以分别进行读写优化,从而实现更好的性能。

我们知道在读操作中主要使用的优化方式是缓存操作。那么,我们可以将接口层面的查询操作即读操作,尽量多地通过缓存来返回。而写操作也就是命令操作,主要的性能优化方式是使用消息队列。那么,我们可以将数据的更新操作,尽量通过消息队列,通过异步化的方式进行处理,以改善性能。


因为使用 CQRS 查询和命令分离的方式,我们可以在接口层面上使用不同的优化手段。查询操作不会修改数据库,那么所有来自于查询接口的服务,可以统一连接到只读数据库中,防止误操作破坏数据,可以更好地保护数据,同时使用 CQRS,还可以更好地实现刚才的事件溯源机制。因为查询操作是无须进行事件溯源的,所有的事件溯源都可以统一设置在命令服务接口上。


三、断路器


使用微服务的时候,你还需要关注一个事情:服务的不可用。

当某个服务实例出现故障的时候,它的响应延迟或者失败率增加的时候,继续调用这个服务实例会导致请求者阻塞。请求阻塞以后会导致资源消耗增加,最后可能会导致请求者也失败和崩溃,进而出现服务的级联崩溃,也就是服务请求者的请求者也失败,最后会导致整个系统全部失败,即雪崩现象。


在这种情况下,可以使用断路器对故障服务进行隔离。断路器有三种状态:关闭、打开、半开。当服务出现故障的时候,通过断路器阻断对故障服务实例的调用,避免它的故障扩散开来。


四、超时


还有一件需要关注的事情是:微服务调用的超时机制如何设置。

如果使用统一的超时设置,那么当下游调用者超时的时候,上游调用者一定也已经超时了,因为服务调用是阻塞的。所以,下游调用的超时一定会反应在上游调用者上。因此在设置超时的时候,要设置上游调用者的超时时间大于下游调用者的超时时间之和,相同的超时设置是没有意义的。


总结回顾  


首先,之所以要使用微服务,是因为传统的单体巨无霸系统带来的挑战和困难,包括编译和部署的困难、连接的困难、打包代码冲突的困难,以及复用的困难、新增业务的困难。


使用微服务最重要的是做好业务的模块化设计,模块之间要低耦合,高聚合,模块之间的依赖关系要清晰简单。只有这样的模块化设计,才能够构建出良好的微服务架构。如果系统本身就是一团遭,强行将它们拆分在不同的微服务里,只会使系统变得更加混乱。


使用微服务的时候,有几个重要的使用模式,需要关注:一个是事件溯源,一个是命令与查询隔离,还有一个是断路器以及关于超时如何进行设置。


版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

微博朋友圈亿级Feed流如何设计

微博朋友圈亿级Feed流如何设计

简介Feed流是Feed + 流,Feed的本意是饲料,Feed流的本意就是有人一直在往一个地方投递新鲜的饲料,如果需要饲料,只需要盯着投递点就可以了,这样就能源源不断获取到新鲜的饲料。 在...

如何应对网站流量暴增

如何应对网站流量暴增

按照经验大概出问题地方是DB,磁盘io、CPU、带宽、连接数、内存其中的一个或几个。不同的业务,不同的系统设计,出问题的地方会有所不同。如果流量增大数倍,势必某个资源会在瞬间被榨干,然后所有的服务都会...

高性能网络编程中的I/O模型

高性能网络编程中的I/O模型

互联网服务端处理网络请求的原理首先看看一个典型互联网服务端处理网络请求的典型过程由上图可以看到,主要处理步骤包括:1. 获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3);2. 构...

如何写出漂亮的代码-代码整洁之道

如何写出漂亮的代码-代码整洁之道

背景代码本就该是直接简单的,横就是横,纵就是纵,架构原本也本是清晰明了的,模块是模块,过程是过程。可随着项目生命周期的变长,随着需求不断的被实现,面对不同思想的人,不同场景的要求,不同技能水平的实施,...

秒杀如何设计

秒杀难点:1、突发流量、数据热点2、数据一致性、短暂混沌态如果采用传统的数据库进行数据存储,对同一资源的争抢,就会面临严重的锁冲突问题。一般是通过一个前置的,速度更快的存储顶在前面,这就涉及到源库和目...

基于rebase的Git工作流

使用Git在多人协作的过程中,我们也会面临如何运用好Git的问题。这种情况下,就出现了各种各样的Git Workflow,而本文将介绍一种基于rebase的工作流,这种工作流也是目前开源社区所比较推崇...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。