第五节:SpringCloud Ribbon与Feign

Ribbon

1:什么是Ribbon

①:什么是客户端的负载均衡

进程内的LB(Load Balancer),他是一个类库集成到消费端,通过消费端进行获取提供者的地址
生活中:类似与你去火车站排队进站(有三条通道),只要是正常人,都会排队到人少的队伍中去.
程序中: 我们消费端 能获取到服务提供者地址列表,然后根据某种策略去获取一个地址进行调用.

在这里插入图片描述

②:什么是服务端的负载均衡

1.2) 什么是服务端的负载均衡?

生活中:类似与你去火车站排队进站的时候,有一个火车站的引导员告诉你说三号通道人少,你去三号通道排队。
程序中:就是你消费者调用的是ng的地址,由ng来选择 请求的转发(轮询 权重,ip_hash等)

在这里插入图片描述

2:如何快速整合ribbon

第一步:搭建二个eureka的集群

参考第四节Eureka

第二步:把ribbon集成到消费端

①:加入依赖

<!-- eureka 客户端的依赖(其实他集成了ribbon的依赖)-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 集成ribbon的依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>

②:写application.yml的配置文件

server:
  port: 9004
  servlet:
    context-path: /

spring:
  application:
    #注册到eureka服务端的微服务名称
    name: eureka-ribbon-client
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://127.0.0.1:3306/yinz
    driver-class-name: com.mysql.cj.jdbc.Driver
    
eureka:
  client:
  service-url:
    #注册到eureka服务端的地址
    defaultZone: http://localhost:9000/eureka/

    defaultZone=http://www:
      eureka9000:
        com:9000/eureka/,http://www:
          eureka9001:
            com:9001/eureka/​:instance:
  #点击具体的微服务,右下角是否显示ip
  prefer-ip-address: true
  #显示微服务的名称
  instance-id: eureka-ribbon-client-9004


③:修改调用配置

package com.ribbon.client.conf;

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 MyConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

package com.ribbon.client.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RibbonController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/ribbon")
    public String ribbon() {
        //通过微服务实例名称进行调用
        return restTemplate.getForObject("http://EUREKA-CLIENT2/eurekaClient2Test", String.class);
    }
}

第三步:搭建服务提供者

即其他客服端提供的服务,这里使用yinz-eureka-client的服务
测试地址:http://localhost:9004/ribbon

3:如何使用ribbon进行负载均衡测试

拷贝yinz-ribbon-client客服端两份,修改端口,定义相同的服务,打印不同的日志测试调用

4:测试Ribbon的负载均衡策略(默认的是轮询)#

关闭某台服务,测试宕机

5:Ribbon核心知识点

Ribbon所包含的负载均衡策略分类

**RandomRule:**随机选择一个Server
**RetryRule:**对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的server
**RoundRobinRule:**轮询选择, 轮询index,选择index对应位置的Server
**AvailabilityFilteringRule:**过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个Server的运行状态
**BestAvailableRule:**选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。
**WeightedResponseTimeRule:**根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低;
**ZoneAvoidanceRule:**复合判断Server所在区域的性能和Server的可用性选择Server

如何修改默认负载均衡的策略

写一个配置类来修改ribbon的负载均衡的配置

@Configuration
public class MyConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


    /**
     * 随机算法的负载均衡
     * @return
     */
    @Bean
    public IRule MyRule() {
        //return new RandomRule();
        return new RetryRule();
    }
}

如何来自定义负载均衡策略

引用规则,使用@RibbonClient指定负载均衡策略

@SpringBootApplication
@EnableDiscoveryClient
@RibbonClient(name = "EUREKA-CLIENT2",configuration = MyRule.class)
public class RibbonClientApplication {

自定义的负载均衡策略不能写在@SpringbootApplication注解的@CompentScan扫描得到的地方

自定义负载均衡策略
原生的RandomRule策略解析

public class RandomRule extends AbstractLoadBalancerRule {
    Random rand;

    public RandomRule() {
        rand = new Random();
    }


    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
			//获取所注册的机器
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
 
			//随机获取一个服务下标
            int index = rand.nextInt(serverCount);
			//获取一个服务列表
            server = upList.get(index);

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }
 
		//直接返回
        return server;

    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
 
	}
}

自定义Rule

package com.config;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 自定义的随机策略
 * Created by smlz on 2019/4/8.
 */
public class MyRule extends AbstractLoadBalancerRule {

    Random rand;

    public MyRule () {
        rand = new Random();
    }

    private int currentIndex = 0;

    private List<Server> currentChooseList = new ArrayList<Server>();

    /**
     * Randomly choose from all living servers
     */
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            //第一次进来 随机选取一个下标
            int index = rand.nextInt(serverCount);

            //当前轮询的次数小于等于5
            if(currentIndex<5) {
                //保存当前选择的服务列表ip
                if(currentChooseList.isEmpty()) {
                    currentChooseList.add(upList.get(index));
                }
                //当前的++
                currentIndex++;
                //返回保存的
                return currentChooseList.get(0);
            }else {
                currentChooseList.clear();
                currentChooseList.add(0,upList.get(index));
                currentIndex=0;
            }


            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            server = null;
            Thread.yield();
        }

        return server;

    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub

    }
}

Feign

1:什么是Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。
在Spring Cloud中,使用Feign非常简单——只需创建接口,并在接口上添加注解即可。
Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便

eg: 以前我们调用dao的时候 ,我们是不是一个接口加 注解然后在service中就可以进行调用了
@Mapper
public interface OrderDao {
List queryOrdersByUserId(Integer userId);
}

2:Feign VS Ribbon

Ribbon+RestTemplate进行微服务调用缺点:
ResponseEntity responseEntity = restTemplate.getForEntity(“http://order-service/order/queryOrdersByUserId/”+userId,List.class);

①:我们不难发现,我们构建上诉的URL 是比较简单的,假如我们业务系统十分复杂,类似如下节点
https://www.baidu.com/s?wd=asf&rsv_spt=1&rsv_iqid=0xa25bbeba000047fd&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=3&rsv_sug1=2&rsv_sug7=100&rsv_sug2=0&inputT=328&rsv_sug4=328

那么我们构建这个请求的URL是不是很复杂,若我们请求的参数有可能变动,那么是否这个URL是不是很复杂

②:如果系统业务非常复杂,而你是一个新人,当你看到这行代码,恐怕很难一眼看出其用途是什么!此时,你很可能需要寻求老同事的帮助(往往是这行代码的作者,哈哈哈,可万一离职了呢?),或者查阅该目标地址对应的文档(文档常常还和代码不匹配),才能清晰了解这行代码背后的含义!否则,你只能陷入蛋疼的境地!

3:工程搭建

1、加入依赖

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

2、定义服务

// 正接口上的name指定微服务的名称,  path是指定服务消费者的调用前缀
@FeignClient(name = "ms-provider-user",path = "/user")
public interface OrderApi {

    @RequestMapping("/queryUserById/{userId}")
    public String queryUserById(@PathVariable("userId") Integer userId);
}

将yinz-feign-client 打成jar

3、在消费端依赖jar

<dependency>
	<groupId>com.tuling</groupId>
	<artifactId>yinz-feign-client</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

4、在消费端主启动类商添加

@EnableFeignClients(basePackages = "com.yinz")

3、如何自定义Feign

1:自定义日志级别

日志级别:
NONE:【性能最佳,适用于生产】:不记录任何日志(默认值)

public class MyConfig{
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.NONE;
    }
}

HEADERS:记录BASIC级别的基础上,记录请求和响应的header

public class MyConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.HEADERS;
    }
}

FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据

public class MyConfig {
   @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

代码中如何自定义

public class MyConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
}

@FeignClient(name = "ms-provider-user",configuration=MyConfig.class,path = "/user")
public interface OrderApi {

    @RequestMapping("/queryUserById/{userId}")
    public String queryUserById(@PathVariable("userId") Integer userId);
}

yml中如何配置:

feign.client.config.ms-provider-order-feign-custom01.loggerLevel=full

如何支持feign的注解来替换springmvc的注解

代码配置

public class MyConfig {
    // 修改协议契约
    @Bean
    public Contract feignContract() {
        return new Contract.Default();
    }
}

@FeignClient(name = "ms-provider-user",configuration=MyConfig.class,path = "/user")
public interface OrderApi {
    @RequestMapping("/queryUserById/{userId}")
    public String queryUserById(@PathVariable("userId") Integer userId);
}

配置文件配置

feign.client.config.ms-provider-order-feign-custom01.contract=feign.Contract.Default

创建拦截器设置公用参数实现:RequestInterceptor

编写拦截器:

public class MyInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        System.out.println("自定义拦截器");
        template.header("token","123456");
    }
}

加入拦截器配置
代码配置

public class MyCfg {
    @Bean
    public RequestInterceptor myInterceptor () {
        return new MyInterceptor();
    }
}

Yml配置

feign.client.config.ms-provider-order-feign-custom01.requestInterceptors[0]=com.yinz.client.MyInterceptor

服务提供端获取公共参数

在这里插入图片描述

原文地址:https://blog.csdn.net/allcovetalllose/article/details/114869888

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等,那这些参数都是什么意思?又该如何设置?接下来我们一起来盘它。 1.命名空间 在 Nacos 中通过命名空间(Namespace)+ 分组(Group)+服务名(Name)可以定位到一个唯一的服务实例。 命名
Nacos 支持两种 HTTP 服务请求,一个是 REST Template,另一个是 Feign Client。之前的文章咱们介绍过 Rest Template 的调用方式,主要是通过 Ribbon(负载均衡) + RestTemplate 实现 HTTP 服务调用的,请求的核心代码是这样的: @
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能。 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连接管理和请求转发的功能,让程序的开发者无需过多的关注服务提供者的稳定性和健康程度以及调用地址,因为这
Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案,目前已被 Spring Cloud 官方收录。而 Nacos 作为 Spring Cloud Alibaba 的核心组件之一,提供了两个非常重要的功能:服务注册中心(服务注册和发现)功能,和统一配置中心功能。 Nac
在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈值和就近访问。因为这 3 个内容都是彼此独立的,所以今天我们就单独拎出“保护阈值”来详细聊聊。 保护阈值 保护阈值(ProtectThreshold):为了防止因过多实例故障,导致所有流量全部流入剩余健康实例,继而造成流量压力将剩余健
前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了一番,最后还是顺利解决了。以下是原因分析和解决方案,建议先收藏,以备不时之需。 临时实例和持久化实例是 Nacos 1.0.0 中新增了一个特性。临时实例和持久化实例最大的区别是健康检查的方式:临时实例使用客户端主动上报的健康检查模式,而
Spring Cloud Alibaba 技术体系中的 Nacos,提供了两个重要的功能:注册中心(服务注册与发现)功能和配置中心功能。 其中注册中心解决了微服务调用中,服务提供者和服务调用者的解耦,让程序开发者可以无需过多的关注服务提供者和调用者的运行细节,只需要通过 Nacos 的注册中心就可以
负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策略的需求,而使用不同负载均衡策略的场景确实是存在的,所以客
本篇文章为大家展示了如何解决Spring Cloud 服务冲突问题,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、背景...
本篇内容主要讲解“spring cloud服务的注册与发现怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spri...
本篇内容介绍了“Dubbo怎么实现Spring Cloud服务治理 ”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本篇内容主要讲解“SpringCloud相关面试题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringCloud相...
如何分析Spring Cloud Ribbon、Spring Cloud Feign以及断路器,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要讲解了“springcloud微服务的组成部分有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“s...
这篇文章主要讲解了“SpringCloud的OpenFeign项目怎么创建”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习...
本篇内容主要讲解“spring cloud oauth3整合JWT后获取用户信息不全怎么办”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带...
怎样解析微服务架构SpringCloud,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。...
这篇文章主要介绍spring cloud中API网关的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、服务网关简介1、外观模式客户端...
本篇内容介绍了“Spring Cloud微服务的相关问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处...
本文小编为大家详细介绍“spring cloud config整合gitlab如何搭建分布式的配置中心”,内容详细,步骤清晰,细节处理妥当,希望这篇“spring cloud config整合gi...