springcloud the Ribbon load balancing and Feign consumer calls the service

1, simple to understand Ribbon

Ribbon is Netflix released a load balancer, which helps to control HTTP and TCP client behavior. After you configure the service provider address for the Ribbon, Ribbon can be some sort of load balancing algorithm to automatically help consumers to request service. Ribbon default load balancing algorithm provides a lot for us, such as polling, randomly. Of course, we can also achieve load balancing algorithm customized for the Ribbon.
In the Spring Cloud, Ribbon when used in conjunction with the Eureka, Eureka Ribbon Server can be acquired from the service provider list of addresses and load balancing algorithm, wherein a service provider requesting instance. Shows the architecture of the Ribbon when used in conjunction with Eureka.

Micro service call Ribbon

Use the Ribbon, combined eureka, to achieve call services;
Here Insert Picture Description
initial application
Ribbon client load balancing, so it must re-integration of the consumer side, which is the consumer end
we modify microservice-student-consumer-80
First, the introduction of dependence, pom.xml Join ribbon relevant dependent

<!--ribbon相关依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

application.yml 加

server:
  port: 80
  context-path: /
eureka:
  client:
    service-url:
      defaultZone: http://eureka2001.javachz.com:2001/eureka/,http://eureka2002.javachz.com:2002/eureka/,http://eureka2003.javachz.com:2003/eureka/
    register-with-eureka: false

2, Ribbon load balancing

ribbon combination eureka to call the service provider;

SpringCloudConfig also changed to add a load balancing configuration @LoadBalanced

package com.javachz.microservicestudentconsumer80.config;

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 SpringCloudConfig {
    @LoadBalanced  // 引入ribbon负载均衡
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

Because the integration and eureka, so start class StudentConsumerApplication_80 add a comment @EnableEurekaClient

package com.javachz.microservicestudentconsumer80;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class MicroserviceStudentConsumer80Application {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentConsumer80Application.class, args);
    }

}

Here there is one, to modify PRE_HOST under StudentConsumerController, the name changed to micro-service application specified;
of course here in the first application.yml plus Configuration service provider microservice-student-provider-1001's, under the specified application name:
the Application :
name: microservice-student
Here Insert Picture Description
micro-service application name is microservice-student
so the service the caller side of the controller in PRE_HOST change http: // mICROSERVICE-STUDENT can;
microService-STUDENT Eureka application name registry of
Here Insert Picture Description
the above configuration is good after, we can test case;
first start three eureka, then start the service provider, and then start the service consumer;
Here Insert Picture Description
execute http: // localhost / student / list
Here Insert Picture Description
the results came out, the configuration OK;

Ribbon Load Balancing

Establishing a sub microservice-student-provider in accordance with its microservice-student-provider-1001, and then microservice-student-provider-1001 This component kill;

前面搭建了初步例子,但是还没实现真正负载均衡,我们这里要先搞三个服务提供者集群,然后才能演示负载均衡,以及负载均衡策略;
Here Insert Picture Description
新建项目microservice-student-provider-1002,microservice-student-provider-1003
pom.xml,application.yml,以及java类都复制一份,启动类名称对应的改下;
yml配置文件有两处要对应的改下,port端口改下,以及服务实例名称改下;
相关代码如下
相关pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.javachz</groupId>
        <artifactId>microservice</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>microservice-student-provider</artifactId>

    <properties>
        <java.version>1.8</java.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>com.javaxl</groupId>
            <artifactId>microservice-common</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>


        <!--添加注册中心Eureka相关配置-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!-- actuator监控引入 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

---
---
server:
  port: 1001
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  application:
    name: microservice-student
  profiles: provider-1001
eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1001
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.javachz.com:2001/eureka/,http://eureka2002.javachz.com:2002/eureka/,http://eureka2003.javachz.com:2003/eureka/

info:
  groupId: com.javachz.testSpringcloud
  artifactId: microservice-student-provider-1001
  version: 1.0-SNAPSHOT
  userName: http://javachz.com
  phone: 123456


---
server:
  port: 1002
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  application:
    name: microservice-student
  profiles: provider-1002
eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1002
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.javachz.com:2001/eureka/,http://eureka2002.javachz.com:2002/eureka/,http://eureka2003.javachz.com:2003/eureka/

info:
  groupId: com.javachz.testSpringcloud
  artifactId: microservice-student-provider-1002
  version: 1.0-SNAPSHOT
  userName: http://javachz.com
  phone: 123456


---
server:
  port: 1003
  context-path: /
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
  application:
    name: microservice-student
  profiles: provider-1003
eureka:
  instance:
    hostname: localhost
    appname: microservice-student
    instance-id: microservice-student:1003
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://eureka2001.javachz.com:2001/eureka/,http://eureka2002.javachz.com:2002/eureka/,http://eureka2003.javachz.com:2003/eureka/

info:
  groupId: com.javachz.testSpringcloud
  artifactId: microservice-student-provider-1003
  version: 1.0-SNAPSHOT
  userName: http://javachz.com
  phone: 123456

启动类

package com.javchz.microservicestudentprovider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EntityScan("com.javachz.*.*")
@EnableEurekaClient
@SpringBootApplication
public class MicroserviceStudentProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentProviderApplication.class, args);
    }

}

StudentProviderController.java
Here Insert Picture Description

StudentConsumerController.java
Here Insert Picture Description
先测试服务提供者:
http://localhost:1001/student/list
Here Insert Picture Description
http://localhost:1002/student/list
Here Insert Picture Description
http://localhost:1003/student/list
Here Insert Picture Description
看看是否有结果;

再测试下 eureka:
http://eureka2001.javachz.com:2001/
Here Insert Picture Description
http://eureka2002.javachz.com:2002/
Here Insert Picture Description
http://eureka2003.javachz.com:2003/
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
然后再启动服务消费者:
http://localhost/student/list 多刷新几次 看控制台,我们看到 有默认的轮询策略,访问对应的服务提供者;
http://localhost/student/ribbon
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
但是这种默认的轮询策略肯定是不能满足实际需求的,比如有3个服务提供者,突然挂了一个,这样的话,默认轮询 ,总有1/3的概率访问失败;
举例:
假设宕掉了一个服务提供者,如图所示:
Here Insert Picture Description
Here Insert Picture Description
负载均衡有好几种实现策略,常见的有:

随机 (Random)
轮询 (RoundRobin)
一致性哈希 (ConsistentHash)
哈希 (Hash)
加权(Weighted)
所以我们看下ribbon默认给我们提供的策略有哪些;

策略名 策略声明
BestAvailableRule public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule
AvailabilityFilteringRule public class AvailabilityFilteringRule extends PredicateBasedRule
WeightedResponseTimeRule public class WeightedResponseTimeRule extends RoundRobinRule
RetryRule public class RetryRule extends AbstractLoadBalancerRule
RoundRobinRule public class RoundRobinRule extends AbstractLoadBalancerRule
RandomRule public class RandomRule extends AbstractLoadBalancerRule
ZoneAvoidanceRule public class ZoneAvoidanceRule extends PredicateBasedRule

默认7个策略,根据具体产品需求,我们选用;
服务消费端 SpringCloudConfig配置类
指定IRule实现;
这里演示用 RetryRule,大伙可以自行测试;

package com.javachz.microservicestudentconsumer80.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RetryRule;
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 SpringCloudConfig {
    @LoadBalanced  // 引入ribbon负载均衡
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
    /**
     * 自定义轮询算法
     * @return
     */
    @Bean
    public IRule myRule(){
        return new RetryRule();
    }
}

用法很简单;

3、Feign简介及应用

简介
声明式服务调用Feign简单介绍下;

Feign是一个声明式的Web Service客户端,它使得编写Web Serivce客户端变得更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成。它具备可插拔的注解支持,包括Feign注解和JAX-RS注解。Feign也支持可插拔的编码器和解码器。Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。

这段话看起来比较懵逼,这里说下实际使用,前面Ribbon调用服务提供者,我们通过restTemplate调用,缺点是,多个地方调用,同一个请求要写多次,不方便统一维护,这时候Feign来了,就直接把请求统一搞一个service作为FeignClient,然后其他调用Controller需要用到的,直接注入service,直接调用service方法即可;同时Feign整合了Ribbon和Eureka,所以要配置负载均衡的话,直接配置Ribbon即可,无其他特殊地方;当然Fiegn也整合了服务容错保护,断路器Hystrix,后面再说。
应用
1、在common项目里建一个service(实际项目肯定是多个service)作为Feign客户端,用Feign客户端来调用服务器提供者,当然可以配置负载均衡;Feign客户端定义的目的,就是为了方便给其他项目调用;
修改 microservice-common
pom.xml引入Feign依赖:

<!--引入Feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

我们定义了 FeignClient,同时指定了调用的服务名称MICROSERVICE-STUDENT
common项目修改后,maven clean下 然后install下;

建StudentClientService接口;

package com.javachz.microservicecommon.service;

import com.javachz.microservicecommon.entity.Student;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;


/**
 * Student Feign接口客户端
 * @author Administrator
 *
 */
@FeignClient(value="MICROSERVICE-STUDENT")
public interface StudentClientService {
 
    /**
     * 根据id查询学生信息
     * @param id
     * @return
     */
    @GetMapping(value="/student/get/{id}")
    public Student get(@PathVariable("id") Integer id);
     
    /**
     * 查询学生信息
     * @return
     */
    @GetMapping(value="/student/list")
    public List<Student> list();
     
    /**
     * 添加或者修改学生信息
     * @param student
     * @return
     */
    @PostMapping(value="/student/save")
    public boolean save(Student student);
     
    /**
     * 根据id删除学生信息
     * @return
     */
    @GetMapping(value="/student/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id);

    @RequestMapping("/student/ribbon")
    public String ribbon();
}

2、新建一个Feign消费者项目;
参考microservice-student-consumer-80建一个microservice-student-consumer-feign-80
代码都复制一份,包括pom.xml

Here Insert Picture Description
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.javachz</groupId>
        <artifactId>microservice</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>microservice-student-consumer-feign-80</artifactId>

    <properties>
        <druid.version>1.1.10</druid.version>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>


        <!--ribbon相关依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!--引入Feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.javachz</groupId>
            <artifactId>microservice-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <!--  连接池  -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

server:
  port: 80
  context-path: /
eureka:
  client:
    service-url:
      defaultZone: http://eureka2001.javachz.com:2001/eureka/,http://eureka2002.javachz.com:2002/eureka/,http://eureka2003.javachz.com:2003/eureka/
    register-with-eureka: false

MicroserviceStudentConsumerFeign80Application启动类
Note: Modify the startup class name, and processing notes at startup class name change, change StudentConsumerFeignApplication_80, at the same time add a comment @EnableFeignClients support of Feign;

package com.javachz.microservicestudentconsumerfeign80;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableEurekaClient
@EnableFeignClients(value = "com.javachz.*.*")
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class MicroserviceStudentConsumerFeign80Application {

    public static void main(String[] args) {
        SpringApplication.run(MicroserviceStudentConsumerFeign80Application.class, args);
    }

}

config层
SpringCloudConfig

package com.javachz.microservicestudentconsumerfeign80.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RetryRule;
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 SpringCloudConfig {
    @LoadBalanced  // 引入ribbon负载均衡
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
    /**
     * 自定义轮询算法
     * @return
     */
    @Bean
    public IRule myRule(){
        return new RetryRule();
    }
}

controller
StudentConsumerController

package com.javachz.microservicestudentconsumerfeign80.controller;

import com.javachz.microservicecommon.entity.Student;
import com.javachz.microservicecommon.service.StudentClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/student")
public class StudentConsumerController {

    @Autowired
    private StudentClientService studentClientService;

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping(value = "/save")
    private boolean save(Student student) {
        return studentClientService.save(student);
    }

    @GetMapping(value = "/list")
    public List<Student> list() {
        return studentClientService.list();
    }

    @GetMapping(value = "/get/{id}")
    public Student get(@PathVariable("id") Integer id) {
        return studentClientService.get(id);
    }

    @GetMapping(value = "/delete/{id}")
    public boolean delete(@PathVariable("id") Integer id) {
        try {
            studentClientService.delete(id);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @RequestMapping("/ribbon")
    public String ribbon(){
        return studentClientService.ribbon();
    }
}

Because now with Fiegn, so the restTemplate removed, injected into service, calls the service method to realize call services;
Here Insert Picture Description
5, test load balancing;
SpringCloudConfig class myrule, modified self-testing to everyone;
Here Insert Picture Description
Here Insert Picture Description

Published 66 original articles · won praise 4 · Views 947

Guess you like

Origin blog.csdn.net/weixin_45346741/article/details/103924019