SpringCloud——服务调用入门

对于各个服务都配置到注册中心,我们需要一个技术使得这些服务能够互相调用使用。在原始服务调用是采用httpclient,之后演变成restTemplate(由spring提供的访问rest服务的模板工具集)。

Ribbon

1.Ribbon:基于Netflix Ribbon实现的一套客户端负载均衡的工具。主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。
2.Ribbon工作流程:首先选择EurekaServer,优先选择同一个区域内负载较少的server。再在根据用户指定的策略,从server中取到的服务注册列表中选择一个地址。
3.Ribbon是采用LB(Load Balance)负载均衡:将用户的多个请求平均分摊到多个服务上面。和我们所认知的NGINX负载均衡不同,Nginx是服务器的负债均衡,客户端将所有请求交给Nginx,再由Nginx实现转发请求,即负载均衡是由服务器完成。
4.DiscoveryClient:对于注册eureka里面的微服务,可以通过服务发现来获得该服务的信息。需要在主启动类上加@EnableDiscoveryClient

 @GetMapping("/payment/discovery")
    public Object discovery(){
        // 获取注册中心的服务
        List<String> services = discoveryClient.getServices();
        for(String element: services){
            log.info("***element***"+element);
        }
        // 获取指定服务名的服务信息
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for(ServiceInstance instance:instances){
            log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+
                    instance.getUri());
        }
        return this.discoveryClient;
    }

5.RestTemplate有两种调用服务方法:postForObjectpostForEntity

  //static final String PAYMENT_URL = "http://localhost:8081";

 static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

@GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
        /** postForObject(返回对象为响应体中数据转化为对象:Json)
         * 1.url: 请求地址
         * 2.responseType: 返回的数据
         */
        return  restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
    }

@GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPaymentEntity(@PathVariable("id") Long id){
        /** getForEntity(返回responseEntity对象含有相应中一些信息响应头、响应状态码) 返回需要加上getBody方法
         * 1.url: 请求地址
         * 2.responseType: 返回的数据
         */
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
        if(entity.getStatusCode().is2xxSuccessful()){
            log.info("ResponseEntity{}",entity);
            return entity.getBody();
        }else{
            return new CommonResult<>(400,"操作失败");
        }
    }

补充:对于Eureka集群 消费端不应该再去写死地址而是写服务名称(注册中心名字;大写),并且加上@LoadBalanced注解(默认是轮询机制)
SpringCloud——服务调用入门_第1张图片
6.Ribbon自带7种负载规则:
①com.netflix.loadbalancer.RoundRobinRule(轮询)
②com.netflix.loadbalancer.RandomRule(随机)
③com.netflix.loadbalancer.RetryRule(先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务)
④WeightedResponseTimeRule(对RoundRobinRule的扩展,响应速度越快的实例选择权重越多大,越容易被选择)
⑤BestAvailableRule(会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务)
⑥AvailabilityFilteringRule(先过滤掉故障实例,再选择并发较小的实例)
⑦ZoneAvoidanceRule(默认规则,复合判断server所在区域的性能和server的可用性选择服务器)
7.Ribbon的替换规则:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。不能去掉@LoadBalanced
SpringCloud——服务调用入门_第2张图片SpringCloud——服务调用入门_第3张图片
8.负载均衡算法:rest第几次请求书%(取余)服务集群总数 = 实际调用服务器位置下标,每次重启rest从1开始。
注意:手写算法调用需要去掉@LoadBalanced注解

public interface LoadBalancer {
    ServiceInstance serviceInstance(List<ServiceInstance> serviceInstances);
}


@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     * 获取当前请求次数
     * @return
     */
    public final  int getAndIncrement(){
        int current;
        int next;
        do{
            current = this.atomicInteger.get();
            next = current >+ Integer.MAX_VALUE ? 0:current + 1;
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("*********next访问次数为:"+next);
        return  next;
    }



    /**
     * 负载均衡算法:
     *      第几次请求书%(取余)服务集群总数 =  实际调用服务器位置下标,每次重启rest从1开始。
     * @param serviceInstances
     * @return
     */
    @Override
    public ServiceInstance serviceInstance(List<ServiceInstance> serviceInstances) {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

controller层代码:

@GetMapping(value = "/consumer/payment/lb")
    public String getPaymentLB() {
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");

        if(instances == null || instances.size() <= 0) {
            return null;
        }
        ServiceInstance serviceInstance = loadBalancer.serviceInstance(instances);
        URI uri = serviceInstance.getUri();
        return restTemplate.getForObject(uri+"/payment/lb",String.class);
    }

注意当这边一个服务挂掉都也能访问该服务但是会报错。
源码:
SpringCloud——服务调用入门_第4张图片
服务出错和结果:
SpringCloud——服务调用入门_第5张图片

SpringCloud——服务调用入门_第6张图片

OpenFeign

SpringCloud——服务调用入门_第7张图片
1.Feign:一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。只需创建一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
2.Ribbon+RestTemplate是模板化调用服务(一个接口被多处调用),而feign只需要定义服务绑定接口以声明式方法。
3.Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需 创建一个接口并在接口上添加注解即可
application.yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    fetchRegistry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000
logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.charon.springcloud.service.PaymentFeignService: debug

主启动类:

@SpringBootApplication
@EnableFeignClients
public class OpenFeignMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OpenFeignMain80.class,args);
    }
}

Feign调用(接口)

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeout();
}

4.openFeign一般默认是1秒钟,得不到就返回报错。所以有时候需要超时控制。
5.OpenFeign提供了日志打印的功能,了解Feign中Http请求的细节。说白了就是对于日志的监控和输出。
NULL:默认,不显示日志。
BASIC:仅记录请求方法,url,响应状态码。
HEADERS:出来了BASIC外还有请求和响应信息。
FULL:除了HEADERS外还有请求和响应的正文元数据。

@Configuration
public class FeignConfig {

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

你可能感兴趣的:(Ribbon,Feign,spring,cloud,ribbon)