后端架构师必知必会系列:微服务架构设计与实践

发布于:2023-09-27 ⋅ 阅读:(106) ⋅ 点赞:(0)

作者:禅与计算机程序设计艺术

1.简介

微服务架构(Microservices Architecture)是一种分布式系统架构风格,它将复杂的单体应用分解成一个个可管理的小服务,每个服务运行在独立的进程中,通过轻量级的通讯协议进行通信、互相协作完成任务。微服务架构拥有以下优点:

  1. 容错性高:由于每个服务都可以独立部署,因此一旦某个服务出现故障或崩溃,影响面就会局限于该服务及其依赖的服务;
  2. 可扩展性强:服务之间采用轻量级的通信协议,使得服务的组合方式灵活多变;
  3. 开发效率高:单个服务的开发速度快、迭代周期短,便于快速响应业务需求变化;
  4. 技术栈灵活:服务之间可以使用不同编程语言、框架、数据库等实现不同的功能,充分利用公司内部各部门的技术能力;
  5. 测试方便:各服务可以分别测试并集成到一起,提升了测试效率;

本文是《后端架构师必知必会系列:微服务架构设计与实践》的第一期文章,主要阐述微服务架构相关知识点,包括服务注册中心、服务发现机制、API网关、负载均衡策略、熔断降级、消息队列、服务容错、配置中心、日志监控、数据一致性保证。以及适用于微服务架构设计的一些最佳实践。

2.微服务架构核心要素

2.1 服务注册中心

在微服务架构下,服务间通信需要借助于服务发现机制,即找到对方提供的服务地址,比如服务A想要调用服务B,则首先需要知道服务B的地址,再发起请求。服务注册中心通常用于服务的动态注册和服务地址的管理,目的是为了能够让客户端能够根据服务名称动态地获取服务地址。常用的服务注册中心有:

  1. Consul
  2. Zookeeper
  3. Etcd

Consul 和 Etcd 都是强一致性存储,因此性能比 Zookeeper 更好,不过它们在可用性方面也有所差距。Etcd 更适合作为服务发现中心,因为它的 API 支持查询目录,而 Consul 提供了更丰富的特性如健康检查、键值存储、订阅机制、ACL支持等。

一般情况下,建议选择 Consul 或 Etcd 来构建服务注册中心,如果没有特殊要求,推荐优先考虑 Etcd,因为它更简单易用、性能较 Consul 好。

2.2 服务发现机制

服务发现机制指服务消费者如何发现服务生产者,并且能够使用这些信息发起远程调用。服务发现一般采用两种方式:

  • 静态配置:配置文件中记录了服务提供者的地址信息,服务消费者根据配置文件进行查找;
  • 基于 DNS 的服务发现:服务消费者向 DNS 发起查询请求,DNS 服务器返回相应的 IP 地址列表,然后服务消费者根据 IP 地址列表进行连接;

上述两种方法都存在单点问题,服务发现中心可能会出现网络分区、失效等故障,对于长时间运行的服务来说,难以满足服务发现的实时性要求。

因此,通常会结合使用 DNS 和服务发现中心。具体流程如下:

  1. 服务启动时,向服务注册中心报告自己的地址,供其他服务消费者查找到;
  2. 服务消费者定时或者定时的从服务注册中心获取最新的服务地址列表,然后根据地址列表和负载均衡算法,选择一个服务进行访问;
  3. 当服务出现故障或发生网络分区时,服务注册中心能够及时更新地址信息,服务消费者能够感知到并及时切换到备份节点;

DNS 作为域名解析服务器,能够将域名转换为 IP 地址,所以服务消费者只需知道服务的域名即可,无需配置服务地址。除此之外,服务注册中心还会记录服务的元数据,如服务名、版本号、端口号、协议类型等,这样服务消费者就可以根据元数据过滤自己感兴趣的服务,避免调用非必要的服务。

2.3 API网关

API网关(Gateway)作为边界层,用来接收外部请求并将请求转发至内部的微服务集群,为调用方提供统一的接口,屏蔽内部服务的复杂性和高可用、容错等问题。其作用包括安全控制、流量控制、协议转换、流量调度、访问统计等。

API网关与传统的代理服务器不同,它处理的不仅仅是 HTTP 请求,还可以处理 TCP/UDP 数据包、WebSocket 等非 HTTP 协议,也可以同时支持 HTTP 和 WebSocket,将不同协议的数据交换转化为统一的 API 形式,极大的方便了微服务之间的互联互通。

2.4 负载均衡策略

负载均衡(Load Balancing)是微服务架构下的重要技术,其目标是平衡服务集群中各个服务节点的负载,确保所有服务节点均匀分配压力,提高整体服务的可用性和性能。常用的负载均衡策略有:

  1. 轮询法(Round Robin):简单的轮流选择一个节点;
  2. 随机法(Random):随机选择一个节点;
  3. 加权轮询法(Weighted Round Robin):按照各节点的权重进行分配;
  4. 最小连接数(Least Connections):选择当前并发量最小的节点;
  5. 源地址hash法(Source Address Hashing):根据源地址进行哈希运算,选择一个节点;

除了以上几种策略,还有基于设备的负载均衡方法,如基于路由器的 VPN LB (Virtual Private Network Load Balance),它通过隧道的方式将 TCP 数据包封装进 UDP 数据包,再通过 BGP 对外发布出去,从而实现跨运营商、跨城市的负载均衡。另外,还有基于云平台的负载均衡方法,如 AWS Elastic Load Balance (ELB),它提供了多种类型的负载均衡,如 EC2 实例、Lambda 函数等,可以根据实际情况选择合适的方法。

2.5 熔断降级

熔断降级(Circuit Breaker Pattern)是应对服务雪崩效应的一项容错手段,当某一服务发生过多的调用超时、错误、异常等失败时,则停止调用该服务,等待一段时间,如此反复,直到达到某个临界状态,然后再重新打开继续调用。降级是指限制服务的调用次数或流量,比如将部分服务降级,减少其对外暴露的调用量。

当服务的调用成功率超过一定阈值后,熔断就自动关闭,开始进入半开放状态,允许一定数量的流量通过,如若调用失败率持续超出阈值,则再次开启熔断,然后开始逐渐排除故障节点。

2.6 消息队列

微服务架构下,不同服务之间往往需要异步交互,比如订单服务调用库存服务,这时候就需要引入消息队列。消息队列是一种典型的分布式中间件产品,它在微服务架构下扮演着缓冲、交换、传输作用。常用的消息队列有:

  1. RabbitMQ
  2. Kafka
  3. ActiveMQ

RabbitMQ 是社区活跃的消息队列系统,具有稳定、高性能、易维护等特点,可以满足微服务架构下多种消息模式。Kafka 以高吞吐量、低延迟著称,主要用于高速数据实时采集、消费和传输;ActiveMQ 则以 Java 语言编写,在资源消耗和性能上都有些许优势。

2.7 服务容错

微服务架构下,任何单点故障都会造成整个系统瘫痪,为了应对这一问题,就需要对微服务集群进行容错处理。容错方法主要包括:

  1. 服务隔离:通过多个微服务集群实现业务隔离,避免单点故障导致整个系统瘫痪;

  2. 熔断降级:当某一服务发生过多的调用超时、错误、异常等失败时,则停止调用该服务,等待一段时间,如此反复,直到达到某个临界状态,然后再重新打开继续调用;

  3. 服务超时设置:服务超时设置需要综合考虑服务超时、同步调用、异步调用、消息处理等场景,防止因超时造成死锁或者长时间阻塞;

  4. 重试机制:重试机制可以一定程度上解决超时问题,但不能完全替代超时设置;

  5. 数据一致性保证:微服务架构下,由于各服务的部署、扩缩容、故障恢复等操作,会导致数据的不一致问题,因此需要通过数据一致性协议保证数据最终一致性。常用的一致性协议有:

    • Paxos

    • Raft

    • ACID

    • BASE

      其中 Paxos 比较老牌,Raft 比较新,ACID 是传统的事务模型,BASE 在 ACID 的基础上融入了 CAP 原则,即 BASE 可以兼顾高可用和一致性。

2.8 配置中心

微服务架构下,每一个服务都有自身的配置项,不同服务甚至可能由不同的编程语言实现,这时候就需要有一个配置中心来集中管理和协同服务配置项。配置中心一般采用如下两种方式:

  1. 集中式配置中心:将所有的配置项集中管理,通常采用数据库或文件系统存储;
  2. 分布式配置中心:每个服务节点只保存自己的配置,但是仍然需要一个集中的配置中心同步和通知。

两种方案各有利弊,集中式配置中心管理起来比较方便,但往往无法满足随意扩缩容、动态调整配置项的需求;分布式配置中心相对集中式配置中心更具弹性,但要注意防止过多的同步和通知,否则会影响配置中心的性能。

2.9 日志监控

微服务架构下,不同的服务、容器和主机的日志往往存放在不同的地方,而且不同级别的日志往往不是分开存储的,因此需要统一的日志收集和监控系统来聚合和分析日志,从而定位、诊断问题。一般日志收集和监控系统包括以下几个模块:

  1. 数据采集:负责从不同的数据源收集日志,如日志文件、管道、socket、stdout 等;
  2. 数据清洗:对日志进行清洗、切片、归类等操作,实现日志标准化;
  3. 日志存储:将日志按时间、大小、类别等维度存储到日志数据库中;
  4. 日志查询:提供日志查询、搜索、检索、分析等功能;
  5. 日志分析:对日志进行分析、统计、趋势、异常等;
  6. 告警系统:根据日志监控结果,触发相应的告警,如邮件告警、短信通知、微信通知等。

目前比较热门的开源日志系统有 ELK Stack(Elasticsearch + Logstash + Kibana),它是一个开源的日志收集、分析和可视化工具。

2.10 数据一致性保证

微服务架构下,服务之间的数据往往需要保持一致性,但由于各种原因,往往不能做到完全一致,因此需要制定数据一致性保证协议来确保数据最终一致性。常用的数据一致性协议有:

  1. 2PC(Two Phase Commit):两阶段提交协议,由两个阶段组成,第一个阶段准备阶段,第二个阶段提交阶段。准备阶段对参与者资源预留,提交阶段释放资源,最后如果其中任何参与者节点失败则取消事务;
  2. 3PC(Three Phase Commit):三阶段提交协议,与两阶段提交类似,增加了一个事务预提交阶段,这个阶段可以实现提交前对参与者做一次协商,以决定是否提交事务;
  3. Paxos 协议:是分布式一致性算法,主要用于解决分布式环境下一致性的问题,Paxos 协议包括领导者、被告知者和acceptors。当一个节点作为领导者时,他通过选举产生一个值,这个值被称为编号,领导者通过广播的方式通知所有参与者,让他们承认这个编号的值,当一个被告知者接收到超过半数的参与者确认消息后,他就把这个值作为commit,当领导者收到足够多的确认消息后,他把这个编号的值作为commit,那么就达到了一致性。
  4. Raft 协议:Raft 协议是另一种分布式一致性算法,它在 Paxos 协议的基础上做了改进。Raft 使用了强 leader 和 follower 两个角色,leader 用来接受客户端请求并复制日志,follower 只用来复制日志。Raft 使用心跳检测和日志回填机制来实现成员的存活与故障检测。

3.微服务架构设计原则

微服务架构设计原则包含两类:规范性原则和优化性原则。前者要求遵守微服务设计的理念,包括单一职责原则、分层架构原则、服务拆分原则、独立部署原则等;后者则提供一些最佳实践,包括通过容器编排管理微服务、设计微服务内的数据库、设计微服务间的通信、实现自动化测试等。

3.1 单一职责原则

单一职责原则(Single Responsibility Principle,SRP)是微服务架构设计的基本原则,它认为每个模块、类和函数都应该有且仅有一个单独的功能,即只做好一件事情,做好这件事情的同时也不得罪其他部分的代码。单一职责原则可以帮助团队各司其职、增强模块的可理解性、降低修改难度,更容易针对性地做单元测试、集成测试、性能测试、功能测试等。

为了符合单一职责原则,可以通过下面几种方式来设计微服务:

  1. 根据业务领域划分服务:很多公司将业务领域划分为多个子域,比如支付系统、商品系统等,每个子域对应一个微服务;
  2. 根据业务规则划分服务:一些公司采用业务规则来划分服务,比如将用户相关服务、订单相关服务等;
  3. 根据模块划分服务:将系统模块划分为单独的微服务,比如将用户模块、订单模块等微服务。

3.2 分层架构原则

分层架构原则(Layered Architecture Principle,LAP)认为应用程序应该分为多个层次,每一层只负责一层的功能,并且在层与层之间建立相互的依赖关系,层与层之间都有明确定义的接口。分层架构原则能够有效地降低耦合性、提高模块的可测试性、可移植性、可扩展性。

微服务架构下,通常采用四层架构来组织服务,即 Presentation Layer(表现层)、Business Logic Layer(业务逻辑层)、Service Layer(服务层)、Data Access Layer(数据访问层)。Presentation Layer 是服务的表现层,它主要负责接收用户请求,验证参数,调用业务逻辑层的接口,并呈现结果给用户;Business Logic Layer 是服务的核心业务逻辑层,它处理服务的核心业务逻辑,包括校验、加密、计算、缓存等;Service Layer 是服务的接口层,它暴露微服务的接口,其他服务可以通过调用 Service Layer 中的方法来访问这个微服务;Data Access Layer 是数据访问层,它提供服务数据读写的功能,比如 MySQL 数据库、Redis 缓存等。

3.3 服务拆分原则

服务拆分原则(Separation of Concerns Principle,SOC)认为一个完整的业务活动应该被拆分成多个独立的服务,每个服务只负责一个功能,而且应该通过接口暴露出来。服务拆分原则可以提高系统的可维护性、可测试性、可复用性。

为了符合服务拆分原则,可以将系统划分为多个子系统,每个子系统负责某个功能模块,这样就可以将复杂的业务逻辑拆分为多个服务,每个服务只负责一个模块的功能。每个服务之间通过接口进行交互,这种架构称为“服务式”架构。

3.4 独立部署原则

独立部署原则(Independent Deployment Principle,IDP)认为每个微服务都应该可以独立部署,即每个服务都可以打包、构建、测试、发布,并且可以在生产环境中单独启动和停止。独立部署原则可以降低微服务之间的耦合性,并使得微服务的部署、测试、发布过程更加可控。

独立部署也意味着微服务的大小也应该适中,不能太大,也不能太小。可以通过下面的方法来实现微服务的独立部署:

  1. 每个微服务部署在独立的 Docker 镜像中;
  2. 每个微服务使用不同的编程语言、依赖版本、运行环境等;
  3. 微服务之间通过 RESTful API 或 RPC 协议通信;
  4. 为微服务提供配置中心;
  5. 为微服务提供日志、监控系统;
  6. 为微服务提供服务注册中心、服务发现机制。

4.微服务架构设计最佳实践

微服务架构设计最佳实践是为了使得微服务架构落地更加顺畅,提升开发效率和项目质量。以下是微服务架构设计过程中常用的一些最佳实践:

  1. 合理划分微服务:在开始设计微服务架构之前,应该合理划分微服务,确定每个微服务的职责范围、依赖关系和部署架构,确保服务粒度细化,每个服务只做好一件事。

  2. 优先使用松耦合、低耦合的微服务:松耦合的服务和组件之间彻底解耦,便于维护和修改;而低耦合的服务和组件之间通过接口和数据进行交互,可以通过协议来描述交互过程。

  3. 避免共享数据库:微服务架构下,服务之间的数据应该严格独立,避免多个服务共享相同的数据库。

  4. 使用事件驱动架构:事件驱动架构可以让服务之间的通信更加灵活、异步化。

  5. 使用容器技术部署微服务:容器技术可以简化微服务的部署工作,并提供更好的隔离性和环境一致性。

  6. 实现异步通信机制:实现异步通信机制可以提高微服务的可伸缩性和韧性。

  7. 使用无状态的微服务:无状态的微服务可以提高可扩展性,并降低服务间的耦合性。

  8. 灵活使用日志、监控和跟踪:使用日志、监控和跟踪可以提高微服务的可观测性,并使得问题快速定位和修复。


网站公告

今日签到

点亮在社区的每一天
去签到