第三章 Ribbon负载均衡及源码解析笔记

本文详细介绍了Spring Cloud Ribbon的使用,包括配置介绍、如何为消费者集成Ribbon以及Ribbon的负载均衡实现。通过Ribbon,消费者可以连接Eureka获取服务,并利用Ribbon的负载算法实现服务间的调用。此外,文章还深入解析了Ribbon的源码,如@RibbonClient、LoadBalancerClient、ILoadBalancer接口和选择服务器的策略。
摘要由CSDN通过智能技术生成

现在服务提供方已经可以通过Eureka进行注册了,但对于服务的消费者,目前并没有处理,对于服务的消费方,也应该连接上eureka,进行服务的获取,这个时候就应该使用Ribbon这个组件了。

现在服务提供方已经可以通过Eureka进行注册了,但对于服务的消费者,目前并没有处理,对于服务的消费方,也应该连接上eureka,进行服务的获取,这个时候就应该使用Ribbon这个组件了。

代码Git地址:https://gitee.com/hankin_chj/springcloud-micro-service.git

一、Ribbon基本使用

1、Ribbon配置介绍

1.1、对应的pom文件如下

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

注意:如果是Edgware或之前的版本,ribbon文件如下:

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

在用到负载均衡之前,先要到eureka中获取相关的服务,所以我们这一块依然需要用到eureka,但eureka中已经内置集成了ribbon,所以在pom文件中,并不需要显示引入ribbon的依赖。

1.2、bootstrap.properties配置文件可以指定某个微服务配置

springcloud-service2020\springcloud-web\src\main\resources\bootstrap.properties

spring.application.name=micro-web
server.port=8083
#eureka.client.serviceUrl.defaultZone=http\://localhost\:8763/eureka/
eureka.client.serviceUrl.defaultZone=http://admin:admin@localhost:8763/eureka/
#服务续约,心跳的时间间隔
eureka.instance.lease-renewal-interval-in-seconds=30
#如果从前一次发送心跳时间起,90 秒没接受到新的心跳,剔除服务
eureka.instance.lease-expiration-duration-in-seconds=90
#表示 eureka client 间隔多久去拉取服务注册信息,默认为 30 秒
eureka.client.registry-fetch-interval-seconds=30
# 关闭ribbon访问注册中心Eureka Server发现服务,但是服务依旧会注册。
#true使用eureka false不使用
ribbon.eureka.enabled=true
#指定调用的节点    localhost:8001  localhost:8002  localhost:8003
micro-order.ribbon.listOfServers=localhost:8001,localhost:8002,localhost:8003
#单位ms ,请求连接超时时间
micro-order.ribbon.ConnectTimeout=1000
#单位ms ,请求处理的超时时间
micro-order.ribbon.ReadTimeout=2000
micro-order.ribbon.OkToRetryOnAllOperations=true
# 切换实例的重试次数
micro-order.ribbon.MaxAutoRetriesNextServer=2
#对当前实例的重试次数 当Eureka中可以找到服务,但是服务连不上时将会重试
micro-order.ribbon.MaxAutoRetries=2
#
micro-order.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
micro-order.ribbon.NFLoadBalancerPingClassName=com.netflix.loadbalancer.PingUrl

2、为consumer集成Ribbon

2.1、consumer服务修改pom文件,增加eureka的支持:

<!-- eureka中已经内置集成了ribbon,所以并不需要显示引入ribbon的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2.2、consumer服务修改RestConfig配置类

在获取RestTemplate对象的时候加入Ribbon的配置信息@LoadBalanced

@Configuration
public class RestConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return  new RestTemplate();
    }
    /**
     * 服务提供方目前已经使用了密码验证,这个时候服务的消费方如果想直接访问就不可能了,
     * 这个时候一个以头的信息进行处理,然后使用Base64进行加密处理后才能得到正确的访问路径
     */
    @Bean
    public HttpHeaders getHeaders() { // 要进行一个Http头信息配置
        HttpHeaders headers = new HttpHeaders(); // 定义一个HTTP的头信息
        String auth = "admin:admin"; // 认证的原始信息
        byte[] encodedAuth = Base64.getEncoder()
                .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 进行一个加密的处理
        String authHeader = "Basic " + new String(encodedAuth);
        headers.set("Authorization", authHeader);
        return headers;
    }
}

2.3、consumer服务增加Eureka服务注册信息

consumer服务修改application.yml文件,增加Eureka服务注册相关信息

server:
  port: 80
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://admin:admin@eureka1:7001/eureka,http://admin:admin@eureka2:7002/eureka,http://admin:admin@eureka3:7003/eureka

2.4、启动类增加Eureka客户端的配置注解

Consumer服务员修改项目启动类ConsumerApp,增加Eureka客户端的配置注解@EnableEurekaClient。

2.5、修改ConsumerProductController控制器

现在在eureka中注册的服务名称都是大写字母:SPRINGCLOUD-MICRO-PRODUCT

 

@RestController
@RequestMapping("/consumer")
public class ConsumerProductSecurityController {
    // 普通方式访问product服务接口
//    public static final String PRODUCT_GET_URL = "http://localhost:8080/prodcut/get/";
//    public static final String PRODUCT_LIST_URL="http://localhost:8080/prodcut/list/";
//    public static final String PRODUCT_ADD_URL = "http://localhost:8080/prodcut/add/";
    // TODO 通过使用ribbon访问product服务
    public static final String PRODUCT_GET_URL = "http://SPRINGCLOUD-MICRO-PRODUCT/prodcut/get/";
    public static final String PRODUCT_LIST_URL="http://SPRINGCLOUD-MICRO-PRODUCT/prodcut/list/";
    public static final String PRODUCT_ADD_URL = "http://SPRINGCLOUD-MICRO-PRODUCT/prodcut/add/";
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private HttpHeaders httpHeaders;
    /**
     * 添加了spring security以后,访问接口需要密码验证,需要在请求头HttpHeaders中添加验证信息
     */
    @RequestMapping("/product/get2")
    public Object getProduct2(long id) {
        Product product = restTemplate.exchange(PRODUCT_GET_URL + id,HttpMethod.GET,
                new HttpEntity<Object>(httpHeaders), Product.class).getBody();
        return  product;
    }
    @RequestMapping("/product/list2")
    public  Object listProduct2() {
        List<Product> list = restTemplate.exchange(PRODUCT_LIST_URL,HttpMethod.GET,
                new HttpEntity<Object>(httpHeaders), List.class).getBody();
        return  list;
    }
    @RequestMapping("/product/add2")
    public Object addPorduct2(Product product) {
        Boolean result = restTemplate.exchange(PRODUCT_ADD_URL, HttpMethod.POST,
                new HttpEntity<Object>(product,httpHeaders), Boolean.class).getBody();
        return  result;
    }
}

启动服务,访问地址:http://localhost/consumer/product/list2

可以返回结果,这个时候Ribbon与Eureka已经整合成功。

[{"productId":null,"productName":"java编程","productDesc":"springcloud"},

{"productId":null,"productName":"Springboot","productDesc":"springcloud"},

{"productId":null,"productName":"西游记","productDesc":"springcloud"},

{"productId":null,"productName":"水浒传","productDesc":"springcloud"},

{"productId":null,"productName":"西厢记","productDesc":"springcloud"}]

3、ribbon服务调用restTemplate使用说明

3.1、restTemplate调用代码:

@Slf4j
@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public class UserServiceImpl implements UserService {
    private AtomicInteger s = new AtomicInteger();
    private AtomicInteger f = new AtomicInteger();
    public static String SERVIER_NAME = "micro-order";
    @Autowired
    private RestTemplate restTemplate;
    @Override
    public String queryContents() {
        s.incrementAndGet();
        //TODO 注意:getForObject是 getForEntity() 的封装,包含了请求头等信息
        String results = restTemplate.getForObject("http://"
                + SERVIER_NAME + "/queryUser", String.class);
        return results;
    }
}

通过getForObject方法可以掉到用micro-order服务的,queryUser接口。然后在调用期间会存在负载均衡,micro-order服务对应有几个服务实例就会根据负载均衡算法选择某一个去调用。

3.2、Get请求说明:

getForEntity:此方法有三种重载形式,分别为:

getForEntity(String url, Class<T> responseType)

getForEntity(String url, Class<T> responseType, Object... uriVariables)

getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)

getForEntity(URI url, Class<T> responseType)

注意:此方法返回的是一个包装对象ResponseEntity<T>其中TresponseType传入类型,想拿到返回类型需要使用这个包装类对象的getBody()方法。

getForObject:此方法也有三种重载形式,这点与 getForEntity 方法相同:

getForObject(String url, Class<T> responseType)

getForObject(String url, Class<T> responseType, Object... uriVariables)

getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)

getForObject(URI url, Class<T> responseType)

注意:此方法返回的对象类型为 responseType 传入类型

3.2、Post请求

post请求 get请求都有*ForEntity 和*ForObject 方法,其中参数列表有些不同,除了这两个方法外,还有一个postForLocation方法,其中postForLocation以post请求提交资源,并返回新资源的URI

postForEntity:此方法有三种重载形式,分别为:

postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)

postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)

postForEntity(URI url, Object request, Class<T> responseType)

注意:此方法返回的是一个包装对象ResponseEntity<T>其中T为responseType传入类型,想拿到返回类型需要使用这个包装类对象的getBody()方法。

postForObject:此方法也有三种重载形式,这点与 postForEntity 方法相同: 

postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)

postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)

postForObject(URI url, Object request, Class<T> responseType)

注意:此方法返回的对象类型为responseType传入类型

postForLocation:此方法中同样有三种重载形式,分别为:

postForLocation(String url, Object request, Object... uriVariables)

postForLocation(String url, Object request, Map<String, ?> uriVariables)

postForLocation(URI url, Object request)

注意:此方法返回的是新资源的URI,相比getForEntity、getForObject、postForEntity、postForObject方法不同的是这个方法中无需指定返回类型,因为返回类型就是URI,通过Object... uriVariables、Map<String, ?> uriVariables进行传参依旧需要占位符,参看postForEntity部分代码。

二、Ribbon负载均衡的实现

 通过上面的代码发现我们用到了一个注解@LoadBalanced,根据这名字大概就能知道Ribbon是可以实现负载均衡的。

 

1、复制多个product服务实例

第一步:将springcloud-micro-product服务复制两份:

分别为springcloud-micro-product2与springcloud-micro-product3。

第二步:将springcloud数据库复制两份,分别为springcloud2与springcloud3数据库,里面分别执行spingcloud数据库的脚本。

1.1、product2服务修改application.yml文件如下:

注意:切记application:name: springcloud-micro-product这个不能修改,这样做的目的是同一个服务下面有多个服务实例。

server:
  port: 8081
mybatis:
  mapper-locations: # 所有的mapper映射文件
    - classpath:mapping/*.xml
spring:
  application:
    name: springcloud-micro-product
  datasource:
    type

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值