第10章:服务调用与负载均衡

在微服务架构中,服务间的通信是核心环节。一旦服务被注册到注册中心,我们就需要一种机制来发现并调用这些服务。同时,为了保证高可用和高性能,单个服务通常会部署多个实例,这就引入了负载均衡的需求。本章将深入探讨Spring Cloud中实现服务调用和负载均衡的两种主流方式:Ribbon和OpenFeign。


10.1 Ribbon 负载均衡

内容讲解

Ribbon 是Netflix开源的一款客户端负载均衡器。它工作在服务的消费方,可以让我们轻松地将服务请求分发到多个服务实例上。当与Eureka等注册中心结合使用时,Ribbon可以自动从注册中心获取服务实例列表,并根据指定的负载均衡策略将请求发送到其中一个实例。

核心概念:

  • 客户端负载均衡:与Nginx等服务端负载均衡不同,Ribbon将负载均衡的逻辑实现在了客户端。客户端自己维护一份服务提供者的地址列表,并自己决定调用哪一个实例。
  • 集成RestTemplate:Spring Cloud通过@LoadBalanced注解,对标准的RestTemplate进行了增强。当RestTemplate的Bean被标记上这个注解后,它发出的请求就会被Ribbon的拦截器拦截,从而实现客户端负载均衡。

注意:Spring Cloud 2020.0.x版本之后,官方推荐使用Spring Cloud LoadBalancer替代Ribbon。但Ribbon的设计思想和使用方式仍然非常重要,且在老项目中广泛存在。

代码示例

假设我们有一个order-service需要调用user-service

1. 在order-service中配置RestTemplate

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced // 开启客户端负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2. 在order-service中发起调用

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class OrderService {

    @Autowired
    private RestTemplate restTemplate;

    public String getUserById(Long userId) {
        // 直接使用服务名(user-service)代替硬编码的IP和端口
        // Ribbon会自动将其解析为某个实例的实际地址
        String url = "http://user-service/users/" + userId;
        return restTemplate.getForObject(url, String.class);
    }
}

10.2 OpenFeign 声明式调用

内容讲解

虽然RestTemplate结合Ribbon可以实现服务调用,但手动拼接URL和处理HTTP请求的方式显得有些繁琐。OpenFeign 是Spring Cloud提供的一种声明式的、模板化的HTTP客户端。它允许我们像调用本地方法一样调用远程HTTP服务。

核心优势:

  • 声明式:只需定义一个Java接口,并使用注解来描述HTTP请求(URL、请求方法、参数、头信息等)。
  • 高度集成:无缝集成了Ribbon(或Spring Cloud LoadBalancer)实现客户端负载均衡,集成了Hystrix(或Resilience4J)实现服务容错。
  • 代码优雅:将网络调用的细节完全屏蔽,让业务代码更专注于业务逻辑。
代码示例

1. 在order-service中添加OpenFeign依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. 在主启动类上开启Feign功能

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients // 开启Feign扫描
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

3. 创建一个Feign Client接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// value/name 指定了要调用的服务名
@FeignClient(value = "user-service")
public interface UserServiceClient {

    // 接口中的方法签名要与服务提供方的Controller方法保持一致
    @GetMapping("/users/{id}")
    String getUserById(@PathVariable("id") Long id);
}

4. 在OrderService中注入并使用UserServiceClient

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private UserServiceClient userServiceClient;

    public String findUser(Long userId) {
        // 像调用本地方法一样调用远程服务
        return userServiceClient.getUserById(userId);
    }
}

10.3 Feign 核心原理

内容讲解

OpenFeign的魔法在于它使用了动态代理。当我们启动应用并开启@EnableFeignClients时,Spring Cloud会扫描所有被@FeignClient注解标记的接口。对于每一个接口,它会通过JDK的动态代理(或CGLIB)技术创建一个代理对象,并将其注册到Spring的IoC容器中。当我们注入并调用这个接口的方法时,实际上是调用了这个代理对象的方法。

架构图
Controller/Service 调用Feign接口方法
Feign代理 (InvocationHandler)
解析方法注解 (@GetMapping)
构建请求模板 (RequestTemplate)
请求拦截器 (RequestInterceptor)
编码器 (Encoder)
负载均衡器 (Load Balancer)
选择服务实例
HTTP客户端发送请求
接收HTTP响应
解码器 (Decoder)
返回最终结果

10.4 负载均衡策略

内容讲解

Ribbon内置了多种负载均衡策略,我们可以根据业务场景选择合适的策略。常见的策略有:

  • RoundRobinRule (默认):轮询。按顺序循环选择服务实例。
  • RandomRule:随机。从列表中随机选择一个实例。
  • AvailabilityFilteringRule:可用性过滤。过滤掉连接失败和并发过高的实例,然后轮询。
  • WeightedResponseTimeRule:加权响应时间。根据实例的平均响应时间计算权重,响应时间越短,权重越大,被选中的概率越高。
  • BestAvailableRule:最佳可用。过滤掉故障实例后,选择并发量最小的实例。

我们可以通过Java代码或配置文件的方式来修改负载均衡策略。

代码示例 (配置文件方式)

order-serviceapplication.yml中配置,为user-service指定负载均衡策略。

user-service: # 指定要配置的服务名
  ribbon:
    # 指定负载均衡策略的全限定类名
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

本章总结

本章我们掌握了微服务架构中服务调用的关键技术。我们学习了如何使用RestTemplate结合@LoadBalanced注解实现基础的客户端负载均衡,这背后是Ribbon在发挥作用。更重要的是,我们深入学习了声明式服务调用框架OpenFeign,它极大地简化了服务调用的编码工作,提高了开发效率。我们还探讨了Feign的动态代理原理以及如何配置不同的负载均衡策略。掌握了服务调用,我们就打通了微服务之间通信的“任督二脉”,为构建复杂的业务流程奠定了基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值