微服务那点事

前言

记得刚开始出来实习的时候,那时候连 Java Web 是什么都没有个清晰的概念,面试的时候面试的是 Android,结果去到公司却被叫去干后端。那时候只记得上过两节 Java SE 的课,连 SSH 都没搭建过,然后公司用的框架是 SSM,那时候抱佛脚恶补了一下 Java Web 的知识,然后就硬着头皮干了。

第一次接触微服务是在跟公司同事吃饭的时候,他问我们听说过微服务吗,当时听他说什么每个业务拆分成一个项目,又不同的团队开发,感觉很屌的样子。直到现在做了微服务之后才对微服务有个大概的了解。

何为微服务

微服务这个概念是14年提出来的,这里引用 Microservices 之父 Martin Fowler 对微服务的描述来说明何为微服务:

the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.

原文链接:https://martinfowler.com/articles/microservices.html#MicroservicesAndSoa
(看不懂就翻译一下吧,我懒得翻译)

根据 Martin Fowler 的描述,可以总结出以下节点:
# 为什么要微服务
每个新事物的出现一定是为了解决现有问题的,微服务也是如此,微服务的出现是为了解决传统架构存在的问题。那么就要先对比以下微服务架构跟传统架构的区别。

单体架构

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

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

垂直架构

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

分布式架构

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

微服务架构

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

可以看到,每个架构都是为了处理当时的某个问题而演进出来的。

如何搭建微服务项目

微服务拆分原则

  • 单一职责、松耦合高内聚

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

  • 关注点分离

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

  • 无状态服务

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

微服务需要考虑的问题

业务层面

  • 分布式任务

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

首先是基于 消息的一致性方案 ,这种方案是基于消息中间件来完成,属于强一致性方案。假设有A、B两个两个任务分别处在系统 A 跟系统 B 中,此时系统 A 存在一个业务流程,需要将 AB 两个任务在同一个事务中处理。简单的基于消息一致性方案的执行流程如下:
在这里插入图片描述
首先,A 系统在执行任务之前,先发送一条预备消息给消息中间件,消息中间件接收到 A 发送过来的消息,把消息持久化之后返回一条确认消息给 A 系统,告诉 A 系统,我已经收到了,你可以执行事务了。

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

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

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

接下来是 TCC编程式补偿方案 ,TCC 是 try-commit-cancel 的缩写,顾名思义,TCC实现分布式事务一共有三个操作:
image.png
整体的执行流程如下,首先由业务应用发起一个事务请求到事务协调器,然后由业务应用调用服务AB的try接口。紧接着业务应用在接收到try的返回结果之后,通知事务协调器业务执行状态(成功/失败),事务调度器在接收到提交状态的时候,调用两个系统的commit/cancel接口,提交/取消事务执行。分布式事务流程结束。

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

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

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

  • 分布式任务调度

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

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

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

这里只是简单的对分布式调度有个了解,想对这几个框架深入了解,可以查看官方 github 跟官方文档
lts:https://github.com/ltsopensource/light-task-scheduler
elastic-job:https://github.com/ltsopensource/light-task-scheduler/tree/master
xxl-job:https://github.com/xuxueli/xxl-job

运维层面

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

到底要不要上微服务呢

前面讲了这么多,开始说单体架构不能满足高并发场景的要求,微服务架构又会提高系统的复杂性,增加开发成本,那么大家可能会有疑问,我的系统,到底要不要上微服务呢?

  • 项目现有架构

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

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

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

完了吗

当然没有,微服务是一个很庞大的体系,上面只是粗略的讲了一些,还有容器化部署、技术选型…,最后放一张网上比较常见的微服务架构图,大家自行体会一下
image.png

公众号

觉得不错可以关注我的公众号,不定时更新博客 spring boot 教程
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值