跳至主要內容

从根儿上学习微服务03:关于微服务技术,你需要掌握什么?

ltyzzz约 3340 字大约 11 分钟

前言

大家好,我是「周三不Coding」。

上一篇文章open in new window中我详细讲解了为什么需要微服务以及如何划分微服务。今天,咱们正式进入到微服务专栏正题 —— 微服务技术架构。

大家在平常开发的时候,一定或多或少接触过负载均衡、服务发现与注册、服务熔断、服务降级等概念。但是,你有认真地梳理过这些内容吗?如果让你来开发一个微服务,你应该如何开发相关的微服务组件或引入开源解决方案?

今天,我先带大家大概梳理清楚微服务技术架构脉络,使大家对于微服务有一个总体上的认识。对于每一个模块的具体细节,我会在之后的专栏文章中,结合具体的业务场景,逐个详细地进行讲解。

如下为微服务架构思维导图

microservice
microservice

服务描述

在单体项目的开发过程中,很多时候我们采用主流的前后端分离开发模式。

  • 前端请求后端接口
  • 后端将响应 JSON 返回给前端

但是,在微服务项目中,虽然前端仍然只是简单地请求后端,但是后端在处理请求的过程中,可能需要经过不同的微服务。微服务之间是需要进行通信的。

那么在通信之前,我们需要解决一个问题:如何定义当前微服务?更通俗地来说,你的微服务叫什么、服务提供了什么接口、服务接口是如何定义的、服务返回的结果格式是什么、如何解析等。这一系列问题的解决方案就是「服务描述」。

具体的服务描述包括三种方式:

  • RESTful API
  • XML 文件配置
  • IDL 文件配置

这三种方式中,RESTful API 可能是我们日常开发中接触最多的一种形式。即使在单体应用中,我们也经常采用这一方式来规范团队接口定义格式。

IDL 文件也十分常见,它是一种接口描述语言,主要用于 Thrift 与 gRPC 这类跨语言服务框架中,即使是不同语言、不同平台,也可以互相通信。

服务发现与注册

🌟 划重点,重要内容!

当我们实现了多个微服务并定义了相关服务描述之后,应该如何实现互相调用、互相通信呢?这就是服务发现与注册需要解决的问题。

当某一个服务想要调用另外一个服务时,需要知道另一个服务的地址、端口等信息,但是总不可能每一个服务都将所有服务的地址信息记录在本地,这样单服务会存在一定的负载。数据库存储较难维护,也不是一个很好的选择,因为服务的地址信息随时可能发生变化(由于扩缩容、服务下线等原因),这个变化需要被各个服务所感知。

因此,我们需要将这部分信息抽取出来,集中交由某个代理进行统一管理,这就是我们所要提到的「注册中心」。

  • 当服务上线时,需要向注册中心提交自己当前的地址信息,并向注册中心订阅自己所需的服务信息。
  • 当服务下线时,需要通知注册中心,及时删除相关服务信息,并通知其它订阅该服务的服务。
  • 当服务信息发生变化时,注册中心需要及时更改信息。
  • 所有服务需要定时与注册中心进行通信(心跳信息),以确认是否存活。

在日常开发中,较为常见的注册中心有如下几种:

  • Nacos
  • Zookeeper
  • Eureka
  • Consul

服务通信

在单体项目中,不同模块之间可以通过函数调用的方式进行交互。

但是,在微服务的世界中,每个微服务最终是以分布式的方式部署于多台服务器上,是一个分布式系统。各个服务实例都是不同的进程。

因此,不同服务之间必须使用 IPC 进程间通信机制 进行交互。

如下为两类 IPC 技术:

  • 异步、基于消息的通信

    • 异步通信,客户端不会阻塞等待响应返回
    • 采用消息系统标准协议,如:AMQP / STOMP
    • 开源消息系统:如:RabbitMQ / Kafka / RocketMQ 等
  • 同步的请求 & 响应

    • 同步通信,客户端等待响应时为阻塞状态

    • 两类方式:

      • REST,基于 HTTP 协议
      • Thrift,跨语言、支持多种消息格式

对于服务通信,还需要了解通信的消息格式:文本与二进制

  • 对于文本格式,有 JSON 与 XML 格式
  • 对于二进制,可以采用开源序列化协议,如:Protocol Buffer、Kyro、Hessian等

服务路由

🌟 划重点,重要内容!

负载均衡

  • 在实际的微服务调用中,可能一个微服务对应几十个实例节点,那么对于服务调用者而言,应该如何从中选取节点进行调用呢?这就涉及到了服务节点的负载均衡。

  • 负载均衡,顾名思义,就是为了使得同一服务的不同节点,较为均衡地接收并处理请求。

    • 对于机器性能高、响应速度快、处理请求少的节点,尽可能多地处理请求,发挥最大作用

    • 常见的负载均衡算法有如下几种:

      • 随机算法
      • 轮询算法
      • 加权轮询算法
      • 最少活跃连接算法
      • 一致性 Hash 算法

分组调用

通过对 RPC 请求打标签,实现生产环境服务与测试环境服务隔离。

例如:当A、B两个工程师在共同开发一个叫做 UserService 服务时候,A 的 UserService 开发还未完成,处于自测阶段,B 的 UserService 已经开发完成,进入了测试阶段。这时,可以对服务进行分组管理,开发的 UserService 的 group 设置为 dev,B 开发的 UserService 的 group 设置为 test。

全链路灰度发布

当服务全量发布上线之前,我们需要先在一小部分节点上发布服务,进行局部测试。

  • 若测试正常,没有出现问题的话,就继续扩大发布范围,逐渐实现全量更新。
  • 若出现异常,则暂停发布,进行问题排查,这样所造成的负面影响范围较小,不会造成整体的经济损失。

这种部署方式也称为「金丝雀部署」。

服务稳定性治理

🌟 划重点,重要内容!

服务限流、降级与熔断

在我们日常开发中,一定会经常接触到这三个词:限流、降级、熔断。这其实是高并发场景下最常遇到的服务治理问题。

通过这三种方案,确保服务在大多数情况下的「高可用」。

  • 服务限流:在高并发系统中,可能会遇到流量高峰,这时需要通过服务限流,以此限制 QPS,从而起到保护服务、削减流量的作用。

    • 常见限流方式:单实例限流、分布式限流
  • 服务降级:对于微服务项目,为了在高并发场景下保护核心服务,通常会采用 “弃车保帅” 的降级思路,通过丢弃非核心服务请求,削减流量。

  • 服务熔断:当服务出现重大事故、Bug 时,为了防止故障扩散、全链路崩溃、整体服务宕机的情况,需要对服务上游源头进行熔断操作,即直接抛出异常信息,以此在最大程度下保护下游服务。

动态超时

一次微服务请求,可能涉及到几十个服务调用,调用链路十分长。为了防止长时间处理请求,造成请求资源占用的情况,需要引入超时机制

可以有效避免由于长时间的服务调用,造成服务过载,进而引起链路崩溃。

请求重试

当请求失败时,有可能是由于网络阻塞、服务卡顿、TCP 连接异常等原因。这时可以进行适当的请求重试,从而减少请求失败次数,提升服务整体的可用性。

但是,也需要注意设置合理的重试次数,避免重试次数过大、请求累积,进而压垮整个服务。

对于非幂等请求,需要额外小心,防止由于多次重试,造成服务端数据异常问题。

服务可观测

对于微服务系统而言,存在着复杂的链路调用,使得排查线上问题的难度增大。因此,需要建立更加可靠的「可观测系统」,也就是我们日常开发中经常接触的三个概念:日志系统性能指标链路追踪

微服务可观测性并不仅仅是数据的收集、展现、查询,它更加强调数据关联性,帮助我们快速发现、定位问题所在。

服务安全保障

在微服务系统中,我们需要确保服务安全,防止用户敏感信息泄漏。

  • 身份认证:在请求入口(如 API 网关),需要对请求者身份进行校验,较为常规的做法是 Token 校验。

  • 访问控制:对于不同的用户,具有的权限不同,可操控的资源不同,需要进行细粒度、精确到按钮的访问权限控制。具体方案如 RBAC 权限控制。

  • 黑白名单机制:

    • 对于异常流量,需要进行及时的检查与封禁。通过拦截 IP 请求,判断该 IP 是否位于黑名单中,及时拒绝访问
    • 对于开发者、管理员等角色,直接放行,方便开发、测试或管理。

服务运维

微服务架构的升级,往往伴随着容器化技术与 Devops 自动化运维,它们经常搭配使用。

因为当传统的单体应用升级为微服务之后,虽然降低了耦合性,但同时提高了复杂程度,其中就包括运维部署的复杂度。服务的拆分会造成多个服务的打包、测试、部署发布上线,运维的负担大大加重。这时便需要 Devops 解决这一问题。

  • Devops 其实是开发 Development 与运维 Operation 的组合词,这意味着开发与运维的关系变得更加紧密。有了 Devops,开发人员也可解决一键解决运维部署问题,它强调运维部署的自动化流程。

容器化技术则是简化了环境配置操作,解决了环境初始化的问题,使得微服务能够在开发、测试、生产环境之间随意切换。

  • Docker 容器化技术能够封装、打包应用程序,将程序以及其依赖文件打包为一个镜像之后,便可在不同的环境快速运行,无需处理配置、依赖问题。

总结

通过本篇文章,我们基本梳理清楚了微服务技术架构的相关知识点。接下来,我们对以上知识点用「一句话」进行总结。

  • 服务描述:定义服务接口名、接口参数信息、接口响应信息等内容。
  • 服务发现与注册:抽取服务基本信息到注册中心中,实现服务注册、服务上下线管理、服务调用信息获取功能。
  • 服务通信:通过异步消息队列或同步请求响应方式,实现 IPC 进程间通信。
  • 服务路由:负载均衡、分组调用、全链路灰度发布。
  • 服务稳定性治理:多用于高并发微服务场景,通过服务限流、降级、熔断、请求超时、请求重试等确保服务高可用。
  • 服务可观测:从日志 Logging、性能指标 Metrics、链路追踪 Tracing 等三个角度,实现服务可观测。
  • 服务安全保障:在 API 网关入口处,实现身份认证、访问控制、黑白名单过滤机制,保障服务安全,防止数据泄漏。
  • 服务运维:结合容器化技术与 Devops,实现自动化运维,提升微服务运维效率,开发人员也可承担运维职责,实现敏捷开发。

大家可以顺着知识点进行深入的学习与实践。

大家也可以期待一下之后的专栏文章,我会结合实际应用场景与具体知识点,对每个部分的细节进行详细的讲解~

如果本篇文章对你有帮助的话,麻烦点个赞呀~那么今天就到这里啦,下期专栏再见!