Java之 Spring Cloud 微服务搭建Ribbon(第一个阶段)【三】【SpringBoot项目实现商品服务器端是调用】

x33g5p2x  于2021-12-30 转载在 Java  
字(9.0k)|赞(0)|评价(0)|浏览(222)
SpringCloud学习目录点击跳转对应的文章
Java之 Spring Cloud 微服务搭建(第一个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务 Eureka (第一个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建Ribbon(第一个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Consul(第一个阶段)【四】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Feign组件(第二个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Hystrix (第二个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建Sentinel (第二个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建网关 nginx,Zuul(第三个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建网关SpringCloud Gateway微服务网关GateWay(第三个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务的链路追踪 Sleuth 和 Zipkin(第三个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务的 Spring Cloud Stream(第四个阶段)【一】【SpringBoot项目实现商品服务器端调用】
Java之 Spring Cloud 微服务的 SpringCloud Config 配置中心(第四个阶段)【二】【SpringBoot项目实现商品服务器端调用】
Java之 Spring Cloud 微服务的开源配置中心Apollo(第四个阶段)【三】【SpringBoot项目实现商品服务器端调用】

服务调用Ribbon入门

经过以上的学习,已经实现了服务的注册和服务发现。

当启动某个服务的时候,可以通过HTTP的形式将信息注册到注册中心,并且可以通过SpringCloud提供的工具获取注册中心的服务列表。

但是服务之间的调用还存在很多的问题,如何更加方便的调用微服务,多个微服务的提供者如何选择,如何负载均衡等。

1、Ribbon概述

(1) 什么是Ribbon

是 Netflixfa 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。

在 SpringCloud 中,Eureka一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从Eureka中读取到的服务信息,在调用服务节点提供的服务时,会合理的进行负载。

在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的列表信息,并基于内置的负载均衡算法,请求服务

(2) Ribbon的主要作用

(1)服务调用
基于Ribbon实现服务调用, 是通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助RestTemplate 最终进行调用
(2)负载均衡
当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址

2、基于Ribbon实现订单调用商品服务

不论是基于Eureka的注册中心还是基于Consul的注册中心,SpringCloudRibbon统一进行了封装,所以对于服务调用,两者的方式是一样的。

(1)坐标依赖

在springcloud提供的服务发现的jar中以及包含了Ribbon的依赖。
所以这里不需要导入任何额外的坐标

(2)工程改造

在创建RestTemplate的时候,声明@LoadBalanced
使用restTemplate调用远程微服务:不需要拼接微服务的URL路径,以待请求的服务名替换IP地址

1)修改order_service当中的OrderApplication启动类

package cn.itbluebox.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EntityScan("cn.itbluebox.order.entity")
public class OrderApplication {

    /* 使用Spring提供的 RestTemplate 发送http请求到商品服务 1、创建RestTemplate对象交给容器管理 2、在使用的时候,调用其方法完成操作(getXX,postXX) @LoadBalanced : 是Ribbon提供的负载均衡的注解 */
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }
}
2)修改OrderController

实现基于Ribbon的形式调用远程的微服务

1、使用@LoadBalanced声明RestTemplate
2、使用服务名称替换IP地址

package cn.itbluebox.order.controller;
import cn.itbluebox.order.entity.Product;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {

    //注入RestTemplate对象
    @Autowired
    private RestTemplate restTemplate;

    /* 注入DiscoveryClient: SpringCloud 提供的获取原数组的工具类 调用方法获取服务的元数据信息 */
    @Autowired
    private DiscoveryClient discoveryClient;

    /* 参数:商品ID 通过订单系统,调用商品服务 1、需要配置商品对象 2、需要调用商品服务 3、entity.Product 使用java 当中的urlconnection,httpclient,okhttp */
    /* 实现基于Ribbon的形式调用远程的微服务 1、使用@LoadBalanced声明RestTemplate 2、使用服务名称替换IP地址 */
    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        //如何调用商品服务?
        return restTemplate.getForObject("http://service-product/product/"+id,Product.class);
    }
    @RequestMapping(method = RequestMethod.POST)
    public String save(@RequestBody Product product) {
        restTemplate.postForObject("http://service-product/product/",product,Product.class);
        return "保存成功";
    }
    @RequestMapping(method = RequestMethod.PUT)
    public String update(@RequestBody Product product) {
        restTemplate.put("http://service-product/product/",product);
        return "更新成功";
    }
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable Long id) {
        restTemplate.delete("http://service-product/product/"+id);
        return "删除成功";
    }

}

(3)运行测试

访问:http://localhost:9002/order/buy/1

七、服务调用Ribbon高级

1、负载均衡概述

(1)什么是负载均衡

在搭建网站时,如果单节点的 web服务性能和可靠性都无法达到要求;

或者是在使用外网服务时,经常担心被人攻破,一不小心就会有打开外网端口的情况,通常这个时候加入负载均衡就能有效解决服务问题。

负载均衡是一种基础的网络服务,其原理是通过运行在前面的负载均衡服务,按照指定的负载均衡算法,将流量分配到后端服务集群上,从而为系统提供并行扩展的能力。

负载均衡的应用场景包括流量包、转发规则以及后端服务,由于该服务有内外网个例、健康检查等功能,能够有效提供系统的安全性和可用性。

(2)客户端负载均衡与服务端负载均衡

服务端负载均衡
先发送请求到负载均衡服务器或者软件,然后通过负载均衡算法,在多个服务器之间选择一个进行访问;
即在服务器端再进行负载均衡算法分配

客户端负载均衡
客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡;
即在客户端就进行负载均衡算法分配

2、基于Ribbon实现负载均衡

(1)搭建多服务实例

Ribbon是一个典型的客户端负载均衡器,Ribbon会获取服务的所有地址,
根据内部的负载均衡算法,获取本次请求的有效地址

1)准备两个商品微服务(9001,9011 )

修改product_service当中的ProductController类,设置spring cloud 自动的获取当前应用的ip地址

package cn.itbluebox.product.controller;

import cn.itbluebox.product.entity.Product;
import cn.itbluebox.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowired
    private ProductService productService;

    @Value("${server.port}")
    private String port;

    @Value("${spring.cloud.client.ip-address}") //spring cloud 自动的获取当前应用的ip地址
    private String ip;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        Product product = productService.findByID(id);
        product.setProductName("访问的服务地址:"+ip+":"+port);
        return product;
    }
    @RequestMapping(method = RequestMethod.POST)
    public String save(@RequestBody Product product) {
        productService.save(product);
        return "保存成功";
    }
    @RequestMapping(method = RequestMethod.PUT)
    public String update(@RequestBody Product product) {
        productService.update(product);
        return "更新成功";
    }
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable Long id) {
        productService.delete(id);
        return "删除成功";
    }
}
2)运行测试

访问:http://localhost:9001/product/1

3)设置复制另外一个启动方式
  • 修改端口号

  • 复制项目启动

  • 为了方便后期测试,将product_service当中的application.yml改回原来的配置

(2)在订单系统中远程以负载均衡的形式调用商品服务(order_service)

在之前在 @LoadBalanced已当中经配置了,直接启动就实现负载均衡

访问http://localhost:9002/order/buy/1
我们发现端口是9011

刷新页面
我们发现端口是9001

再次刷新页面
我们发现端口是9011

上述情况我们实现了负载均衡

(3)修改order_service设置application.yml修改Ribbon的策略配置

  • com.netflix.loadbalancer.RoundRobinRule :以轮询的方式进行负载均衡。
  • com.netflix.loadbalancer.RandomRule :随机策略
  • com.netflix.loadbalancer.RetryRule :重试策略。
  • com.netflix.loadbalancer.WeightedResponseTimeRule :权重策略。会计算每个服务的权重,越高的被调用的可能性越大。
  • com.netflix.loadbalancer.BestAvailableRule :最佳策略。遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。
  • com.netflix.loadbalancer.AvailabilityFilteringRule :可用过滤策略。过滤掉故障和请
    求数超过阈值的服务实例,再从剩下的实力中轮询调用。

# 修改ribbon的负载均衡策略 服务名称 + ribbon - NFLoadBalancerRuleClassName : 策略
service-product:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

程序启动order_service

访问:
http://localhost:9002/order/buy/1

刷新

刷新

1、如果每个机器配置一样,则建议不修改策略 (推荐)
2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule

完善后面的测试设置上述的配置注释掉

(4)Ribbon:请求重试

1)完善后面的测试在order_service当中的application.yml设置上述的配置注释掉

设置打印日志

logging:
  level:
    root: debug #使用ip地址注册

重新运行测试

访问:http://localhost:9002/order/buy/1

刷新

在这里我们关闭一台ProductApplication模拟网络波动

刷新页面

再次刷新

2)Ribbon重试机制

引入Spring的重试组件
对Ribbon进行重试的配置

01)引入Spring的重试组件,修改order_service的pom.xml

<dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
02)设置重试机制

service-product:
  ribbon:
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数

访问测试:http://localhost:9002/order/buy/1

刷新

启动停掉的服务

刷新页面

刷新

现在我们关闭一个服务

刷新页面

再次刷新

3、Ribbon中负载均衡的源码解析

(1) Ribbon中的关键组件

  • ServerList:可以响应客户端的特定服务的服务器列表。
  • ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器。
  • ServerListUpdater:用于执行动态服务器列表更新。
  • Rule:负载均衡策略,用于确定从服务器列表返回哪个服务器。
  • Ping:客户端用于快速检查服务器当时是否处于活动状态。
  • LoadBalancer:负载均衡器,负责负载均衡调度的管理。

(2) @LoadBalanced注解

SpringCloud学习目录点击跳转对应的文章
Java之 Spring Cloud 微服务搭建(第一个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务 Eureka (第一个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建Ribbon(第一个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Consul(第一个阶段)【四】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Feign组件(第二个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建 Hystrix (第二个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建Sentinel (第二个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建网关 nginx,Zuul(第三个阶段)【一】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务搭建网关SpringCloud Gateway微服务网关GateWay(第三个阶段)【二】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务的链路追踪 Sleuth 和 Zipkin(第三个阶段)【三】【SpringBoot项目实现商品服务器端是调用】
Java之 Spring Cloud 微服务的 Spring Cloud Stream(第四个阶段)【一】【SpringBoot项目实现商品服务器端调用】
Java之 Spring Cloud 微服务的 SpringCloud Config 配置中心(第四个阶段)【二】【SpringBoot项目实现商品服务器端调用】
Java之 Spring Cloud 微服务的开源配置中心Apollo(第四个阶段)【三】【SpringBoot项目实现商品服务器端调用】

相关文章

微信公众号

最新文章

更多