一、微服务架构为什么需要服务发现

想象一下,你管理着一个大型超市,里面有上百个货架(服务)。顾客(请求)需要快速找到商品(服务实例),如果每次都要问管理员(硬编码IP),效率会很低。这就是微服务架构面临的实际问题——服务发现。

在.NET Core微服务中,服务可能动态扩缩容,IP地址也会变化。我们需要一个"超市导购系统"来自动维护服务地址清单。常见方案有:

  1. 客户端直接查询服务注册中心(如Consul)
  2. 通过网关统一路由(如Ocelot)
  3. 服务间使用DNS轮询
// 示例技术栈:.NET Core + Consul
// 服务注册示例
public void Configure(IApplicationBuilder app) 
{
    var consulClient = new ConsulClient();
    var registration = new AgentServiceRegistration()
    {
        ID = "OrderService-1",      // 服务唯一标识
        Name = "OrderService",       // 服务组名称
        Address = "localhost",       // 服务实例地址
        Port = 5000,                 // 服务端口
        Check = new AgentCheckRegistration() // 健康检查
        {
            HTTP = "http://localhost:5000/health",
            Interval = TimeSpan.FromSeconds(10)
        }
    };
    
    consulClient.Agent.ServiceRegister(registration); // 注册到Consul
}

二、服务通信的三种经典模式

2.1 同步通信(HTTP/RPC)

就像打电话,必须等待对方接听。适合需要立即响应的场景:

// 使用HttpClient调用其他服务
[HttpGet]
public async Task<Order> GetOrder(int id)
{
    // 从Consul发现用户服务地址
    var serviceUrl = await _consulClient.GetServiceUrl("UserService");
    
    // 发起同步调用
    using var httpClient = new HttpClient();
    var user = await httpClient.GetFromJsonAsync<User>($"{serviceUrl}/users/{order.UserId}");
    
    return new Order { ..., User = user };
}

2.2 异步通信(消息队列)

类似发短信,发完就可以干别的事。适合耗时操作:

// 使用RabbitMQ发送订单创建事件
public void CreateOrder(Order order)
{
    _orderRepository.Add(order);
    
    // 不需要等待处理结果
    _rabbitMQ.Publish("order.created", new {
        OrderId = order.Id,
        TotalAmount = order.Total
    });
}

2.3 混合模式(gRPC流式)

像视频通话,可以持续双向通信。适合实时数据推送:

// gRPC协议定义
service OrderTracking {
  rpc TrackOrders (stream TrackingRequest) returns (stream PositionUpdate);
}

三、实战中的五个避坑指南

3.1 超时控制

网络不可靠,必须设置超时:

// 配置HttpClient超时
var httpClient = new HttpClient
{
    Timeout = TimeSpan.FromSeconds(3) // 超过3秒视为失败
};

3.2 熔断机制

当服务连续失败时,快速失败避免雪崩:

// 使用Polly实现熔断
var policy = Policy<HttpResponseMessage>
    .Handle<HttpRequestException>()
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromSeconds(30)
    );

3.3 负载均衡

避免所有请求都打到同一个实例:

// 使用随机负载均衡策略
var instances = await _consulClient.GetServiceInstances("PaymentService");
var randomInstance = instances.OrderBy(x => Guid.NewGuid()).First();

3.4 版本兼容

服务升级时要考虑兼容性:

// API版本控制
[ApiVersion("1.0")]
[Route("v{version:apiVersion}/orders")]
public class OrdersController : ControllerBase

3.5 安全通信

内部服务也要加密:

// 配置HTTPS证书
services.AddHttpClient("secure-client")
    .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
    {
        ClientCertificateOptions = ClientCertificateOption.Automatic
    });

四、完整示例:电商订单流程

让我们用一个电商场景串联所有知识点:

// 订单服务完整示例
public class OrderService
{
    private readonly IConsulClient _consul;
    private readonly IMessageBus _bus;
    
    public async Task ProcessOrder(Order order)
    {
        // 1. 验证用户(同步HTTP)
        var userServiceUrl = await _consul.GetServiceUrl("UserService");
        var user = await _httpClient.GetAsync<User>($"{userServiceUrl}/{order.UserId}");
        
        if (!user.IsActive) throw new Exception("用户无效");
        
        // 2. 扣减库存(异步消息)
        _bus.Publish("inventory.lock", new {
            OrderId = order.Id,
            Items = order.Items
        });
        
        // 3. 支付处理(gRPC流式)
        using var paymentChannel = GrpcChannel.ForAddress(
            await _consul.GetServiceUrl("PaymentService"));
            
        var paymentClient = new PaymentGateway.PaymentGatewayClient(paymentChannel);
        using var call = paymentClient.ProcessPayment();
        
        await call.RequestStream.WriteAsync(new PaymentRequest { ... });
        await call.RequestStream.CompleteAsync();
        
        // 4. 更新订单状态
        await _dbContext.SaveChangesAsync();
    }
}

五、技术选型建议

5.1 轻量级场景

  • 服务发现:Consul/Eureka
  • 通信:HTTP + JSON

5.2 高性能场景

  • 服务发现:Kubernetes Service
  • 通信:gRPC/protobuf

5.3 复杂系统

  • 服务网格:Linkerd/Istio
  • 通信:混合模式

六、总结

微服务通信就像城市交通系统:服务发现是GPS导航,同步通信是公交,异步通信是快递,而流式通信则是地铁。选择合适的方式需要考虑:

  1. 响应速度要求
  2. 系统容错能力
  3. 开发维护成本
  4. 团队技术储备

记住没有银弹,最适合的才是最好的解决方案。