【SpringCloud】5. 服务间通信方式

431 阅读4分钟

接下来在整个微服务架构中,我们比较关心的就是服务间的服务改如何调用,有哪些调用方式?

服务通信技术

Spring框架提供的RestTemplate类可用于在应用中调用Rest服务,它简化了与HTTP服务的通信方式,统一了RESTful的标准,封装了HTTP链接,我们只需要传入URL及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。

点对点服务调用

仅仅使用RestTemplate进行服务调用。

/**
 * 在users微服务中不通过服务注册中心指定调用products微服务中某一服务器暴露出来的接口
 */
@GetMapping("user/showProducts")
public String showProducts() {
    RestTemplate restTemplate = new RestTemplate();
    // 访问指定URL,获取响应信息
    String result = restTemplate.getForObject("http://localhost:9001/product/showProducts", String.class);
    log.info("result: [{}]", result);
    return result;
}

存在的问题:

  • 直接使用RestTemplate方式调用,而没有经过服务注册中心获取服务地址,当服务宕机时不能高效剔除。
  • 代码写死,耦合度太高,不利于维护。
  • 调用服务时没有负载均衡需要自己实现负载均衡策略。

负载均衡调用

使用RestTemplate+Ribbon进行服务调用。

1. Ribbon

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。

2. 使用Ribbon

  1. 引入依赖

    如果注册中心使用的Consul,那么不需要引入依赖,因为Consul中已经继承了Ribbon。

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    
  2. Ribbon使用方式

    1. DiscoveryClient
    2. LoadBalancerClient
    3. @LoadBalanced
  3. DiscoveryClient + RestTemplate

    @Autowired
    private DiscoveryClient discoveryClient;
    
    /**
     * 在users微服务中通过服务注册中心指定调用products微服务中某一服务器暴露出来的接口
     * @return 响应信息
     */
    @GetMapping("user/showProductsByDiscoveryClient")
    public String showProductsByDiscoveryClient() {
        RestTemplate restTemplate = new RestTemplate();
        String result = "result is null";
        // 指定服务名,从服务注册中心获取该服务集群中当前所有可用服务器
        List<ServiceInstance> instances = discoveryClient.getInstances("products");
        for (ServiceInstance instance : instances) {
            // 获取每一个服务器的服务名
            String host = instance.getHost();
            // 获取每一个服务器的端口
            int port = instance.getPort();
            // 访问指定URL,获取响应信息
            if ("localhost".equals(host) && port == 9001) {
                result = restTemplate.getForObject(instance.getUri() + "/product/showProducts", String.class);
            }
        }
        return result;
    }
    
  4. LoadBalancerClient + RestTemplate

    @Autowired
    private LoadBalancerClient loadBalancerClient;
    
    /**
     * 在users微服务中通过服务注册中心负载均衡调用products微服务中某一服务器暴露出来的接口
     * @return 响应信息
     */
    @GetMapping("user/showProductsByLoadBalancerClient")
    public String showProductsByLoadBalancerClient() {
        RestTemplate restTemplate = new RestTemplate();
        String result = "result is null";
        // 指定服务名,从服务注册中心负载均衡地获取某一个可用服务器
        ServiceInstance instance = loadBalancerClient.choose("products");
        // 访问由负载均衡算法提供的URL,获取响应信息
        result = restTemplate.getForObject(instance.getUri() + "/product/showProducts", String.class);
        return result;
    }
    
  5. @LoadBalanced + RestTemplate(推荐)

    创建RestTemplateConfig类

    @Configuration
    public class RestTemplateConfig {
    
        /**
         * 构建能通过服务注册中心负载均衡调用服务器的RestTemplate
         * @return 实例
         */
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }
    

    Controller中使用

    @Autowired
    private RestTemplate restTemplate;
    
    /**
     * 在users微服务中通过服务注册中心负载均衡调用products微服务中某一服务器暴露出来的接口
     * @return 响应信息
     */
    @GetMapping("user/showProductsByLoadBalanced")
    public String showProductsByLoadBalanced() {
        String result = "result is null";
        // 在URL中传递服务名,然后底层拆解URL获取服务名再使用LoadBalancerClient实现服务调用
        result = restTemplate.getForObject("http://products/product/showProducts", String.class);
        return result;
    }
    

Ribbon负载均衡策略

1. 过程

当A服务集群中某一台服务器调用B服务集群中的某一台服务器的某一个接口时,A服务器会从服务注册中心拿到所有B服务中正常的服务器的列表,并将列表缓存到A服务器中。然后根据A服务器中的负载均衡策略从列表中选择一个服务器,再调用该服务器中的接口。

2. 常用负载均衡策略

  • RoundRobinRule轮训策略(默认):按顺序循环选择。
  • RandomRule随机策略:随机选择。
  • AvailabilityFilteringRule可用过滤策略(常用):会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值(临界值)的服务,然后对剩余的服务列表按照轮询策略进行访问。
  • WeightedResponseTimeRule响应时间加权策略(常用):根据平均响应的时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高,刚启动时如果统计信息不足,则使用RoundRobinRule轮询策略。
  • RetryRule重试策略:先按照RoundRobinRule的策略获取服务,如果获取失败则在指定时间内进行重试,获取可用的服务。
  • BestAviableRule最低并发策略:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。

3. 修改服务负载均衡策略

调用方配置application.yml

服务id:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.策略名