什么是微服务(一)

什么是微服务?

每个新事物的出现一定是为了解决现有问题的,微服务也是如此,微服务的出现是为了解决传统架构存在的问题。那么就要先对比以下微服务架构跟传统架构的区别。

单体架构

image.png

如图是比较常见的单体应用架构图。实习的时候做的项目就是单体架构的项目,这种架构当网站流量很小的时候,只需要将应用的所有功能写到一个项目中,并将其打包部署到单台服务器上,以减少部署节点和成本。

单体架构的优点很明显,项目架构简单、前期开发成本低、周期短、部署简单,适用于小型项目。缺点也很明显,将所有代码写在同个项目中,任何一个 bug 都有可能导致整个系统宕机。而且单机的处理能力有限,支撑不了高并发的请求。

垂直架构

针对上面所说的单体架构的问题,我们可以将应用拆分成互不相干的几个应用,并使用数据库的读写分离,以增加系统的响应能力,架构图如下:
image.png

分布式架构

当垂直应用越来越多,应用之间难免会互相调用,例如订单模块会调用管理模块的接口。为了减少各模块之间的耦合,可以引入企业服务总线(ESB),将各个模块应用发布到 ESB 中,模块之间通过 ESB 发送和接收消息。此时的架构如下:
image.png

微服务架构

微服务架构与分布式架构有点类似,但分布式架构侧重于将每个单体应用服务集成到 ESB 上,而微服务做的更加彻底,微服务强调每个模块都有自己完整的体系,模块之间通过简单的协议(如HTTP)进行相互调用。微服务架构如下:image.png

微服务架构图:
image.png

如何搭建微服务项目

微服务拆分原则

单一职责、松耦合高内聚

每个服务只复制业务功能的一个单独的部分,比如商城系统,可以将商品管理拆分成一个单独的服务,商品服务只负责商品的业务。松耦合指的是服务间的耦合度低,服务可以单独修改,单独修改一个服务不会影响到其他服务的正常使用。高内聚指的是在整个系统中,相关的行为都聚集在一个服务中,而不是分布在不同的服务中,这样当修改一个行为的时候,就只需要修改一个服务即可。

关注点分离

关注点分离分为按职责、按通用性分离、按粒度级别分离。按职责分离比如一些明显的按业务领域可以划分出来的服务,他的职责比较单一,可以直接划分为一个微服务模块。通用性分离是指与具体业务无关或者整个系统通用的组件,可以将拆分出来,形成一个相对独立的集成服务。微服务模块的粒度是一个不好把握的点,并不是听到微服务的微就认为服务拆分的越小越好,而是根据项目的具体情况,对微服务的粗细粒度进行把握。

无状态服务

如果一个服务需要依赖服务外部的数据才能完成一个请求,那么该数据称之为状态,在微服务模块拆分的时候,需要尽可能的将这些有状态的服务改变成无状态的服务。比如用户模块在本地存储的用户信息缓存,就需要将用户信息缓存迁移到分布式缓存中存储,迁移后,业务服务就变成了一个无状态的服务。这样就能做到服务的动态伸缩,动态增删节点,而不需要考虑数据的同步问题。

微服务需要考虑的问题

业务层面

分布式任务
在单体架构中,实现事务是很容易的一件事。但到了分布式系统中,要在不同节点中实现事务却是件麻烦的事情。常见的分布式事务解决方案有两种: 基于消息一致性方案 和 TCC 编程式补偿事务

首先是基于 消息的一致性方案 ,这种方案是基于消息中间件来完成,属于强一致性方案。假设有A、B两个两个任务分别处在系统 A 跟系统 B 中,此时系统 A 存在一个业务流程,需要将 AB 两个任务在同一个事务中处理。简单的基于消息一致性方案的执行流程如下:
在这里插入图片描述

首先,A 系统在执行任务之前,先发送一条预备消息给消息中间件,消息中间件接收到 A 发送过来的消息,把消息持久化之后返回一条确认消息给 A 系统,告诉 A 系统,我已经收到了,你可以执行事务了。

A 系统在收到中间件返回的消息之后,就开始执行本地事务。在事务执行完之后,再发一条提交消息(事务执行成功/失败)给中间件,中间件在接收到 A 的提交消息之后,如果提交消息是失败消息,就把消息进行丢弃并终止流程。如果提交消息是成功消息,中间件将消息进行持久化之后,将消息发送给 B 系统,通知 B 系统执行事务。

B 系统接收到消息之后,开始执行本地事务,同样的,在本地事务执行完的时候,发送一条提交消息给中间件,中间件再把提交信息转发给 A 系统,A 系统在确认到消息之后,此时,该分布式事务执行完成。

这只是简化后的分布式事务流程,实际应用中消息有可能在传输的过程中丢失,所以还需加入超时轮询/重试机制,保证消息的可靠性。如果超时轮询跟重试机制都不能解决问题,那么此时就需要进行人工干预了。

TCC编程式补偿方案

TCC编程式补偿方案 ,TCC 是 try-commit-cancel 的缩写,顾名思义,TCC实现分布式事务一共有三个操作:

image.png

整体的执行流程如下,首先由业务应用发起一个事务请求到事务协调器,然后由业务应用调用服务AB的try接口。紧接着业务应用在接收到try的返回结果之后,通知事务协调器业务执行状态(成功/失败),事务调度器在接收到提交状态的时候,调用两个系统的commit/cancel接口,提交/取消事务执行。分布式事务流程结束。

try:尝试执行业务
try过程并未真正执行业务,只是完成业务的一致性检查,并预备好执行业务的资源。

commit:执行业务并提交
commit过程开始真正执行业务,在该阶段中会使用到 try 预留的资源。

cancel:取消业务执行,进行回滚操作
若业务执行失败,则进入Cancel阶段,它会释放所有占用的业务资源,并回滚Confirm阶段执行的操作。

分布式任务调度
同样的,在单体应用中执行定时任务是很简单的事情。但是在分布式架构中,因为系统是水平扩展的,一个系统可以部署多套实例。这就还需考虑分同个任务在同个时间点被多个实例执行的问题。

如果你的系统的定时任务是幂等性的,而且任务也不是什么耗性能的操作,则可以不处理分布式任务问题。如果不是,可以通过分布式锁解决任务重复执行的问题,在任务执行的时候加分布式锁,其他实例没获取到锁就不执行。通过分布式锁虽然能解决问题,但是当系统中存在大量的定时任务的时候,就需要在每个任务加锁。会导致系统中存在大量的重复代码,为了解决这个问题,就需要一个分布式的任务调度中心,将任务提交到调度中心,由调度中心统一调度,将任务分配给一个实例执行。引入任务调度中心还有很多好处,比如可以查看每个任务的执行状态,对任务进行管理等。

前阵子在公司对分布式调度框架做了调研,市面上用的比较多的任务调度框架有 3 个,分别是 light-task-scheduler(lts)、elastic-job、xxl-job。xxl-job 文档比较齐全,功能也满足系统业务要求,没有明显短板。目前项目仍有更新,也有很多公司使用。elastic-job 跟 lts 从去年开始就没有更新,文档缺乏,万一出现问题比较难解决,而且对注册中心有一定要求,只能使用 zookeeper 或者 redis。所以推荐使用 xxl-job。

运维层面

单体架构运维管理起来还是比较简单的,只有一个应用,当应用出现问题,到服务器上排查起来也很简单,只需要到部署项目的机器上查看应用的运行状态,查看运行日志,并对问题进行处理就好了。但当项目微服务化之后,一个项目分成多个模块,每个模块由部署多个实例,而且多个实例还有可能部署在不同的机器上。每个实例的日志文件又分布在不同服务器的不同目录下。这时候一旦系统出现问题,排查起来可能要人命。所以微服务集群监控是必不可少,可以通过集成 Spring Boot Admin 对集群健康进行健康,ELK(elasticsearch、logstash、kibana)对系统运行日志进行采集分析等。

到底要不要上微服务呢

项目现有架构
如果说是现有一个系统,想改造成微服务架构以应对业务发展需求的话。那么可以不用那么着急上微服务架构,因为系统的重构改造还是要花费大量的人力财力的,可以先考虑是否能从别的地方着手,提高系统的性能,比如现在是一个单体架构,如果要提高系统的处理能力,最简单的方法就是将系统部署多套,将需要共享的系统资源提取出来(如session,只需要将 session 提取出来存到分布式缓存中即可),这样既省时省力,又不用改动太多的代码。

如果是新项目,则要考虑具体业务的并发量。如果是一个内部用的管理系统,内部员工都没几个人,直接上微服务就有点杀鸡用牛刀的意思。而且也会增加服务器的成本。

还有一点需要考虑的就是项目的人员结构,毕竟上微服务对项目人员的要求还是比较高的,项目中每个成员要熟悉微服务的技术栈,这样才能承担起项目的开发。其次就是人员的组织,每个微服务都由一个小团队组成,倾向于由团队负责整个服务的生命周期(开发-测试-运维-部署)。

猜你喜欢

转载自www.cnblogs.com/macT/p/11471086.html