Skip to content

微服务架构

一、微服务架构概述

1. 什么是微服务?

微服务架构是一种将单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,并通过轻量级机制(通常是 HTTP RESTful API)进行通信。

核心特点:

  • 独立部署 - 每个服务可以独立部署和扩展
  • 技术多样性 - 不同服务可以使用不同技术栈
  • 去中心化 - 数据管理和治理去中心化
  • 故障隔离 - 单个服务故障不影响整体系统

2. 微服务 vs 单体架构

特性单体架构微服务架构
部署整体部署独立部署
扩展垂直扩展水平扩展
技术栈单一技术栈多技术栈
数据管理共享数据库独立数据库
复杂度低(初期)高(需要服务治理)
适用场景小型项目大型复杂系统

3. 微服务的挑战

  • ⚠️ 服务发现 - 如何找到服务?
  • ⚠️ 配置管理 - 如何统一管理配置?
  • ⚠️ 服务通信 - 如何高效通信?
  • ⚠️ 分布式事务 - 如何保证数据一致性?
  • ⚠️ 监控和日志 - 如何追踪问题?
  • ⚠️ 测试 - 如何测试分布式系统?

二、服务发现 - Consul

一、为什么要使用consul?

想象一下,你有一个由 100 个微服务组成的系统,它们部署在几十台服务器或成百上千个容器中。

  • 问题 1:服务在哪里? OrderService 想调用 PaymentService,但它怎么知道 PaymentService 的 IP 和端口?这些地址是动态变化的(容器重启、扩缩容)。 传统做法: 写死在配置文件里。但一旦 PaymentService 的地址变了,所有调用它的服务都得改配置、重启。极其脆弱且不可扩展。
  • 问题 2:服务还活着吗? 如何知道某个 UserService 实例是宕机了,还是只是网络抖动? 传统做法: 手动检查或写脚本。效率低下,无法实时感知。
  • 问题 3:配置怎么管理? 数据库连接字符串、功能开关(Feature Flag)、超时时间等配置,分散在各个服务的配置文件中。 传统做法: 修改一个配置,需要逐个服务更新。一致性差,易出错。
  • 问题 4:如何安全通信? 在服务间传输敏感数据(如用户信息),如何防止被窃听或篡改? 传统做法: 自行实现加密,复杂且容易有安全漏洞。

二、Consul 如何解决这些问题?

  • 1. 服务发现 (Service Discovery) - “它在哪?” 工作原理: 注册 (Register): 当一个服务(如 PaymentService)启动时,它会向 Consul 注册自己,告诉 Consul:“我叫 payment,我的 IP 是 10.0.1.10,端口是 8080,健康检查地址是 /health”。 发现 (Discover): 当另一个服务(如 OrderService)需要调用 payment 时,它向 Consul 查询:“payment 服务在哪?” Consul 返回一个或多个可用的 IP:Port 列表。 优势: 动态: 服务地址变化时,自动更新,调用方无感知。 解耦: 服务之间不需要知道对方的具体地址。 支持 DNS 和 HTTP API: 可以直接用 curl payment.service.consul:8080 或调用 Consul API。
  • 2. 健康检查 (Health Checking) - “它还活着吗?” 工作原理: Consul 会定期(如每 10 秒)对每个注册的服务执行健康检查(通常是 HTTP 请求 /health 或 TCP 端口检查)。 如果检查失败,Consul 会将该服务实例标记为 critical(不健康)。 当 OrderService 查询 payment 服务时,Consul 只返回健康的服务实例。 优势: 自动故障转移: 避免将请求发送到已宕机的服务。 提高系统可用性: 结合负载均衡,实现高可用。
  • 3. 配置管理 (Key/Value Store) - “配置在哪?” 工作原理: Consul 内置一个分布式的 KV (Key-Value) 存储。 你可以把配置(如 database.url, feature.flag.new-ui=true)存到 Consul 的 KV 中。 服务启动时,从 Consul 拉取配置,并可以监听配置变更,实现动态更新。 优势: 集中管理: 所有配置在一个地方。 动态生效: 修改配置后,服务可以自动感知并应用,无需重启。 版本控制与审计: 可以追踪配置变更历史。
  • 4. 安全服务通信 (Connect) - “如何安全地说话?” 工作原理: Consul Connect 通过 mTLS (双向 TLS) 来加密服务间的通信。 每个服务都有一个由 Consul CA (证书颁发机构) 签发的证书。 服务间通信前先互相验证证书,确保身份真实,通信内容加密。 可以定义 Service Intentions(意图)来控制哪些服务可以调用哪些服务(类似防火墙规则)。

三、Consul 的典型应用场景

  • 微服务架构: 这是 Consul 最主要的场景。管理成百上千个服务的发现、配置和安全。
  • 混合云/多数据中心: Consul 支持多数据中心,可以跨 AWS、Azure、本地机房统一管理服务。
  • 容器编排集成: 与 Kubernetes、Docker Swarm 集成,为容器化应用提供服务发现。
  • 边缘计算: 在网络边缘的设备上运行 Consul,实现本地服务发现

四、替代方案

Consul 不是唯一的解决方案,常见的还有:

  • ZooKeeper: 老牌的分布式协调服务,功能强大但较重,主要用于 Hadoop 生态。
  • etcd: CoreOS 开发,Kubernetes 的默认存储,轻量,主要用于配置存储和协调。
  • Eureka (Netflix): 专注于服务发现,常用于 Spring Cloud 生态。
  • Nacos (Alibaba): 集成了服务发现、配置管理、服务管理等功能,国内流行。
  • Consul 的优势在于: 功能全面(发现+配置+安全+多数据中心)、易于部署、文档完善、社区活跃。

五、.NET 中使用 Consul

  • 1.添加健康检查接口
    app.MapHealthChecks("/health"); //健康检查地址
    2.添加 Consul注册,一般启动一个后台任务
    ///Consul服务注册
    public class ConsulService : IHostedService
    {
        private ConsulClient? _client;
        private string? _registrationId;
    
        /// <summary>
        /// 启动
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            try
            {
                var builder = WebApplication.CreateBuilder();
                var config = builder.Configuration;
    
                var consulAddress = AppSettings.ConsulConfig.Address;
                var serviceName = AppSettings.ConsulConfig.Service;
                var serviceHost = AppSettings.ConsulConfig.Host;
                var servicePort = AppSettings.ConsulConfig.Port;
    
                _client = new ConsulClient(c => c.Address = new Uri(consulAddress));
                _registrationId = $"{serviceName}-{serviceHost}-{servicePort}";
    
                var registration = new AgentServiceRegistration
                {
                    ID = _registrationId,
                    Name = serviceName,
                    Address = serviceHost,
                    Port = servicePort,
                    Tags = new[] { "urlprefix-/" },
                    Check = new AgentServiceCheck
                    {
                        HTTP = $"http://{serviceHost}:{servicePort}/health",
                        Interval = TimeSpan.FromSeconds(10),
                        Timeout = TimeSpan.FromSeconds(5),
                        DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1)
                    }
                };
    
                SerilogHelper.Log(LogCategoryEnum.System, LogEventLevel.Information, $"  Consul服务已注入...");
                await _client.Agent.ServiceRegister(registration, cancellationToken);
            }
            catch (Exception ex)
            {
                SerilogHelper.Log(LogCategoryEnum.System, LogEventLevel.Error, $"  Consul服务测试失败:{ex.Message}{ex.StackTrace}");
            }
        }
    
        /// <summary>
        /// 结束
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task StopAsync(CancellationToken cancellationToken)
            => _client != null && _registrationId != null
                ? _client.Agent.ServiceDeregister(_registrationId, cancellationToken)
                : Task.CompletedTask;
    }

三、API 网关 - Ocelot

一、什么是 API 网关?为什么需要它?

  1. 在微服务架构中,前端(Web、App)可能需要调用多个后端服务。直接让前端调用每个服务会带来问题:
  • 复杂性: 前端需要知道每个服务的地址。
  • 安全性: 每个服务都暴露在公网,风险高。
  • 重复代码: 认证、限流、日志等功能需要在每个服务中重复实现。
  • 协议转换: 前端用 HTTP,后端可能用 gRPC。
  • Ocelot 是一个基于 .NET 的微服务网关,用于 API 网关和边缘路由。
  1. API 网关就是解决这些问题的“守门人”。它集中处理:
  • 路由 (Routing): 把 /api/users 转发到 UserService,/api/orders 转发到 OrderService。
  • 认证与授权 (Authentication & Authorization): 统一校验 JWT Token。
  • 限流 (Rate Limiting): 防止某个用户或 IP 滥用接口。
  • 熔断与重试 (Circuit Breaker & Retry): 服务不可用时降级或重试。
  • 日志与监控 (Logging & Monitoring): 记录所有请求日志。
  • 请求/响应聚合 (Aggregation): 一个请求返回多个服务的数据。

二、Ocelot 核心功能

Ocelot 提供了上述所有功能,其核心是通过一个 JSON 配置文件 (ocelot.json) 来定义路由规则和中间件行为。

三、详细使用步骤

  1. 创建项目并安装 Ocelot
    // 创建一个新的 ASP.NET Core Web API 项目作为网关
    dotnet new webapi -n OcelotGateway
    cd OcelotGateway
    
    // 安装 Ocelot 包
    dotnet add package Ocelot
  2. 创建 Ocelot 配置文件 ocelot.json
    {"Routes": [
        {
            "DownstreamPathTemplate": "/api/users/{everything}", // 后端服务的实际路径
            "DownstreamScheme": "http",                          // 后端协议 (http/https)
            "DownstreamHostAndPorts": [
                {
                "Host": "localhost",                             // 后端服务主机
                "Port": 5001                                     // 后端服务端口
                }
            ],
            "UpstreamPathTemplate": "/users/{everything}",       // 客户端访问的路径
            "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ], // 支持的 HTTP 方法
            "Key": "UserService",                                // 路由唯一标识
            "AuthenticationOptions": {
                "AuthenticationProviderKey": "Bearer",
                "AllowedScopes": []
            },
            "RateLimitOptions": {
                "ClientWhitelist": [],
                "EnableRateLimiting": true,
                "Period": "1m",
                "PeriodTimespan": 60,
                "Limit": 100
            },
            "LoadBalancerOptions": {
                "Type": "RoundRobin" // 轮询负载均衡
            },
            "QoSOptions": {
                "ExceptionsAllowedBeforeBreaking": 3,
                "DurationOfBreak": 10,
                "TimeoutValue": 5000
            },
            "UseServiceDiscovery": false // 是否使用服务发现
        },
        {
            "DownstreamPathTemplate": "/api/orders/{everything}",
            "DownstreamScheme": "http",
            "DownstreamHostAndPorts": [
                {
                "Host": "localhost",
                "Port": 5002
                }
            ],
            "UpstreamPathTemplate": "/orders/{everything}",
            "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
            "Key": "OrderService"
        }
    ],
    "GlobalConfiguration": {
        "BaseUrl": "http://localhost:5000", // 网关的基地址
        "ServiceDiscoveryProvider": {
        "Host": "localhost",
        "Port": 8500,
        "Type": "Consul"
        }
    }
    }
  3. 配置 Program.cs
    using Ocelot.DependencyInjection;
    using Ocelot.Middleware;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // 1. 添加 Ocelot 服务
    builder.Configuration.SetBasePath(builder.Environment.ContentRootPath)
        .AddJsonFile("ocelot.json", optional: false, reloadOnChange: true); // 重要:启用热重载
    
    builder.Services.AddOcelot(builder.Configuration);
    var app = builder.Build();
    
    // 2. 使用 Ocelot 中间件
    await app.UseOcelot(); // 这是 Ocelot 的核心中间件
    app.Run();

四、核心配置详解

  1. 路由配置

    • DownstreamPathTemplate: 后端服务的真实路径。{everything} 是通配符,匹配所有子路径。
    • UpstreamPathTemplate: 客户端访问网关的路径。/users/123 会被转发到 http://localhost:5001/api/users/123
    • UpstreamHttpMethod: 指定哪些 HTTP 方法可以触发此路由
  2. 负载均衡 (Load Balancer)

    "LoadBalancerOptions": {
         "Type": "RoundRobin" // 轮询
         "Type": "LeastConnection" // 最少连接
         "Type": "NoLoadBalance" // 无负载均衡
     }

    当 DownstreamHostAndPorts 有多个节点时,Ocelot 会根据策略选择一个。

  3. 服务质量 (QoS) - 熔断器

    "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3, // 允许3次异常后熔断
        "DurationOfBreak": 10,                // 熔断持续10秒
        "TimeoutValue": 5000                  // 请求超时5秒
    }

    防止一个慢服务拖垮整个系统。

  4. 限流 (Rate Limiting)

    "RateLimitOptions": {
         "EnableRateLimiting": true,
         "Period": "1m",     // 每分钟
         "Limit": 10         // 最多10次请求
    }

    保护后端服务不被刷爆。

  5. 认证 (Authentication)

    "AuthenticationOptions": {
         "AuthenticationProviderKey": "Bearer"
    }

    这表示此路由需要 JWT Bearer Token 认证。你还需要在项目中配置 JWT:

     // 在 AddOcelot() 之前
     builder.Services.AddAuthentication("Bearer")
         .AddJwtBearer("Bearer", options =>
         {
             options.Authority = "https://your-auth-server.com"; // IdentityServer 地址
             options.TokenValidationParameters = new TokenValidationParameters
             {
                 ValidateAudience = false
             };
         });
    
     builder.Services.AddOcelot(builder.Configuration);
  6. 服务发现 (Service Discovery) 让 Ocelot 从 Consul 获取服务地址,而不是写死。

    • 修改 ocelot.json
    "GlobalConfiguration": {
         "ServiceDiscoveryProvider": {
             "Host": "localhost",
             "Port": 8500,
             "Type": "Consul"
         }
     },
     "Routes": [
         {
             "DownstreamPathTemplate": "/api/users/{everything}",
             "DownstreamScheme": "http",
             // 移除 DownstreamHostAndPorts
             "UpstreamPathTemplate": "/users/{everything}",
             "UpstreamHttpMethod": [ "GET" ],
             "ServiceName": "UserService", // Consul 中注册的服务名
             "UseServiceDiscovery": true   // 启用服务发现
         }
     ]
    • 安装 Consul 包:
     dotnet add package Ocelot.Provider.Consul
    • 在 Program.cs 中启用:
    builder.Services.AddOcelot(builder.Configuration)
               .AddConsul(); // 启用 Consul 支持

五、高级功能

  1. 请求聚合 (Request Aggregation)
    "Aggregates": [
    {
        "RouteKeys": [
        "UserService",
        "OrderService"
        ],
        "UpstreamPathTemplate": "/summary"
    }
    ]
  2. 自定义中间件 你可以编写自定义的 Ocelot 中间件来处理特殊逻辑。
  3. 配置中心 可以将 ocelot.json 存储在 Consul KV 或数据库中,实现动态配置。

六、总结

功能Ocelot配置项说明
路由Routes, DownstreamPathTemplate, UpstreamPathTemplate定义请求转发规则
负载均衡LoadBalancerOptions支持轮询、最少连接等
熔断QoSOptions防止级联故障
限流RateLimitOptions保护后端服务
认证AuthenticationOptions集成 JWT、IdentityServer
服务发现UseServiceDiscovery, ServiceName与 Consul/Eureka 集成
动态配置reloadOnChange: true配置文件修改后自动重载

四、微服务通信

1. 同步通信

HTTP/REST:

  • 简单易用
  • 浏览器友好
  • 性能相对较低

gRPC:

2. 异步通信

消息队列:

  • RabbitMQ
  • Kafka
  • Azure Service Bus

事件驱动:

  • 发布/订阅模式
  • 事件溯源

五、微服务治理

1. 服务发现

Consul:

  • 服务注册与发现
  • 健康检查
  • 配置管理
  • 详见本文档 Consul 章节

其他方案:

  • Eureka(Spring Cloud)
  • Nacos(Alibaba)
  • etcd(Kubernetes)

2. API 网关

Ocelot:

其他方案:

  • Kong
  • Zuul
  • Nginx

3. 认证授权

IdentityServer4:

4. 容错机制

熔断:

限流:

重试:

  • 指数退避
  • 带抖动重试

降级:

  • 返回默认值
  • 使用缓存数据

六、微服务最佳实践

  1. 服务拆分原则 - 按业务领域拆分(DDD)
  2. API 设计 - RESTful 或 gRPC,保持一致性
  3. 服务发现 - 使用 Consul、Eureka 等
  4. 配置管理 - 集中配置管理(Consul KV、Apollo)
  5. 监控和日志 - 分布式追踪(Jaeger、Zipkin)
  6. 容错机制 - 熔断、降级、重试
  7. 安全 - 服务间认证和授权(IdentityServer4)
  8. 测试 - 单元测试、集成测试、契约测试
  9. 数据管理 - 每个服务独立数据库
  10. 部署 - 容器化部署(Docker、Kubernetes)

七、微服务挑战和解决方案

1. 分布式事务

问题: 跨服务的数据一致性

解决方案:

  • Saga 模式 - 分布式事务编排
  • 最终一致性 - 接受最终一致性
  • 事件溯源 - 通过事件保证一致性

2. 服务间通信

问题: 网络延迟、故障

解决方案:

  • 异步通信 - 使用消息队列
  • 熔断器 - 快速失败
  • 重试机制 - 指数退避

3. 数据一致性

问题: 跨服务数据同步

解决方案:

  • 事件驱动 - 发布/订阅
  • CQRS - 命令查询职责分离
  • 最终一致性 - 接受延迟一致性

4. 监控和调试

问题: 分布式系统难以追踪

解决方案:

  • 分布式追踪 - Jaeger、Zipkin
  • 集中日志 - ELK Stack
  • 指标监控 - Prometheus、Grafana

八、微服务架构模式

1. API 网关模式

作用: 统一入口,路由转发

实现: Ocelot、Kong

2. 服务发现模式

作用: 动态发现服务地址

实现: Consul、Eureka

3. 配置中心模式

作用: 集中管理配置

实现: Consul KV、Apollo、Nacos

4. 断路器模式

作用: 防止级联故障

实现: Polly、Hystrix

5. 服务网格模式

作用: 服务间通信基础设施

实现: Istio、Linkerd

九、常见面试题

Q1: 微服务和单体架构如何选择?

选择微服务:

  • ✅ 大型复杂系统
  • ✅ 团队规模大
  • ✅ 需要独立部署和扩展
  • ✅ 技术栈多样化

选择单体:

  • ✅ 小型项目
  • ✅ 团队规模小
  • ✅ 快速迭代
  • ✅ 简单业务

Q2: 如何拆分微服务?

拆分原则:

  1. 按业务领域 - DDD 领域驱动设计
  2. 高内聚低耦合 - 服务内部高内聚,服务间低耦合
  3. 数据独立 - 每个服务独立数据库
  4. 团队结构 - 按团队拆分(康威定律)

Q3: 如何处理分布式事务?

方案:

  1. Saga 模式 - 分布式事务编排
  2. 两阶段提交(2PC) - 性能较差,不推荐
  3. 最终一致性 - 接受延迟一致性
  4. 事件溯源 - 通过事件保证一致性

Q4: 微服务的监控和日志?

监控:

  • 指标监控 - Prometheus、Grafana
  • 链路追踪 - Jaeger、Zipkin
  • 健康检查 - 定期检查服务状态

日志:

  • 集中日志 - ELK Stack(Elasticsearch、Logstash、Kibana)
  • 结构化日志 - JSON 格式
  • 日志聚合 - 统一收集和查询

Q5: 微服务的部署策略?

容器化:

  • Docker 容器化
  • Kubernetes 编排

CI/CD:

  • 自动化构建和部署
  • 蓝绿部署
  • 金丝雀发布

服务治理:

  • 服务发现
  • 负载均衡
  • 健康检查

基于 VitePress 构建 | Copyright © 2026-present