Spring cloud eureka feign ribbon

Ribbon提供一种客户端的负载均衡技术,实现和集群中的服务通信。包含了三种组件
  • Rule 一个逻辑组件用来确定从服务列表中获取哪一个服务
  • Ping 运行在后台的组件,用来确定服务是否可用
  • ServerList 一个后台线程,可以以特定的频率来刷新和过滤服务,可以是静态的也可以是动态的


这些组件既可以通过API方式设定,也可以在配置文件中设定在通过反射方式创建。

1.Common rules
  • RoundRobinRule 这个策略通过简单的轮询策略来选择服务,常常作为默认策略或者是高级策略的后备策略使用
  • AvailabilityFilteringRule 这个策略将跳过那些被认为路由断开的或者是高并发连接数的server instance
  • WeightedResponseTimeRule 这个策略通过利用服务的平均响应时间来得到一个权重,响应时间越长的权重越小,依据权重再随机的挑选一个策略


  • 2.ServerList
  • Adhoc static server list 利用BaseLoadBalancer.setServersList()API设定一个静态的服务列表
  • ConfigurationBasedServerList 默认的ServerList实现方式,可以通过下面的方式设定
  • sample-client.ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
  • DiscoveryEnabledNIWSServerList 这中ServerList实现方式从 Eureka client中获取服务列表,在spring boot程序中,当Eureka相应的jar在classpath中存在,会默认采用这种策略

  • 3.ServerListFilter
    该组件是DynamicServerListLoadBalancer用来在ServerList过滤服务的组件,有以下两种实现方式
  • ZoneAffinityServerListFilter 过滤掉那些和client不在同一个zone的服务,除非client所在的zone中没有可用的server,通过以下方式可以启用
  • myclient.ribbon.EnableZoneAffinity=true
  • ServerListSubsetFilter 这个过滤器确保client只能访问到服务集合中的一个特定子集,并能周期性的不好用的服务替换掉,通过以下方式可以启用
  • myClient.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 
    # the server must register itself with Eureka server with VipAddress "myservice"
    myClient.ribbon.DeploymentContextBasedVipAddresses=myservice
    myClient.ribbon.NIWSServerListFilterClassName=com.netflix.loadbalancer.ServerListSubsetFilter
    # only show client 5 servers. default is 20.
    myClient.ribbon.ServerListSubsetFilter.size=5
    




    例子
  • 1. Eureka server
  • 核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka-server依赖,在启动类中加入@EnableEurekaServer 注解
  • 代码结构:



  • 启动类
  • package hello;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @EnableEurekaServer
    @SpringBootApplication
    public class EurekaServiceApplication {
        
        public static void main(String[] args) {
            SpringApplication.run(EurekaServiceApplication.class, args);
        }
    }
    
    

  • pom文件
  • <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.example</groupId>
    	<artifactId>eureka-service</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.5.1.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-eureka-server</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>Camden.SR5</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    	<repositories>
    		<repository>
    			<id>spring-snapshots</id>
    			<name>Spring Snapshots</name>
    			<url>https://repo.spring.io/libs-snapshot</url>
    			<snapshots>
    				<enabled>true</enabled>
    			</snapshots>
    		</repository>
    	</repositories>
    
    </project>
    
    

  • 应用配置信息
  • server.port=8761
    
    eureka.client.register-with-eureka=false
    eureka.client.fetch-registry=false
    
    logging.level.com.netflix.eureka=OFF
    logging.level.com.netflix.discovery=OFF
    

  • 2.Eureka client(即user server端)
  • 核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka依赖,在启动类中加入@EnableDiscoveryClient注解
  • 代码结构:



  • 启动类
  • package hello;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.Random;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @EnableDiscoveryClient
    @SpringBootApplication
    public class SayHelloApplication {
    
      private static Logger log = LoggerFactory.getLogger(SayHelloApplication.class);
    
      @RequestMapping(value = "/greeting")
      public String greet() {
        log.info("Access /greeting");
    
        List<String> greetings = Arrays.asList("Hi there", "Greetings", "Salutations");
        Random rand = new Random();
    
        int randomNum = rand.nextInt(greetings.size());
        return greetings.get(randomNum);
      }
    
      public static void main(String[] args) {
        SpringApplication.run(SayHelloApplication.class, args);
      }
    }
    
    

  • pom文件
  • <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>hello</groupId>
    	<artifactId>say-hello</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>say-hello</name>
    	<description>Demo project for Spring Boot</description>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.5.1.RELEASE</version>
    		<relativePath /> <!-- lookup parent from repository -->
    	</parent>
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>Camden.SR5</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<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-actuator</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-eureka</artifactId>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    
    </project>
    
    
    

  • 应用配置信息(因为在一台机器上模拟server cluster 所以用了三个profile 分别对应三个port)
  • eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        leaseRenewalIntervalInSeconds: 10
        metadataMap:
          instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
    
    endpoints:
      restart:
        enabled: true
      shutdown:
        enabled: true
      health:
        sensitive: false
    
    ---
    spring:
      application:
        name: say-hello
      profiles: one
    server:
      port: 8090
    
    ---
    spring:
      application:
        name: say-hello
      profiles: two
    server:
      port: 9092
    
    ---
    spring:
      application:
        name: say-hello
      profiles: three
    server:
      port: 9999
    
    

  • 3.User client(调用注册到Eureka server中的Eureka client)
  • 核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka、spring-cloud-starter-feign、spring-cloud-starter-ribbon依赖,在启动类中加入@EnableFeignClients、@RibbonClient(name = "say-hello")注解
  • 代码结构:




  • 启动类
  • package hello;
    
    import static org.springframework.web.bind.annotation.RequestMethod.GET;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.feign.EnableFeignClients;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.cloud.netflix.ribbon.RibbonClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @RibbonClient(name = "say-hello")
    @EnableFeignClients
    public class UserApplication {
    
    	@Autowired
    	HelloClient client;
    
    	@RequestMapping("/greeting")
    	public String hello() {
    		return client.greet();
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(UserApplication.class, args);
    	}
    
    	@FeignClient(name = "say-hello")
    	interface HelloClient {
    		@RequestMapping(value = "/greeting", method = GET)
    		String greet();
    	}
    }
    
    


    FeignClient、RibbonClient中的service id要和Eureka client配置信息中的spring.application.name的值保持一致


  • pom文件
  • <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>hello</groupId>
    	<artifactId>user</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>user</name>
    	<description>Demo project for Spring Boot</description>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>1.5.1.RELEASE</version>
    		<relativePath /> <!-- lookup parent from repository -->
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-ribbon</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-actuator</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-feign</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-eureka</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<dependencyManagement>
    		<dependencies>
    			<dependency>
    				<groupId>org.springframework.cloud</groupId>
    				<artifactId>spring-cloud-dependencies</artifactId>
    				<version>Camden.SR5</version>
    				<type>pom</type>
    				<scope>import</scope>
    			</dependency>
    		</dependencies>
    	</dependencyManagement>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    	<repositories>
    		<repository>
    			<id>spring-snapshots</id>
    			<name>Spring Snapshots</name>
    			<url>https://repo.spring.io/snapshot</url>
    			<snapshots>
    				<enabled>true</enabled>
    			</snapshots>
    		</repository>
    		<repository>
    			<id>spring-milestones</id>
    			<name>Spring Milestones</name>
    			<url>https://repo.spring.io/milestone</url>
    			<snapshots>
    				<enabled>false</enabled>
    			</snapshots>
    		</repository>
    	</repositories>
    
    </project>
    
    

  • 应用配置信息
  • spring:
      application:
        name: user
    
    server:
      port: 8888
    
    say-hello:
      ribbon:
        ServerListRefreshInterval: 15000
    
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
      instance:
        leaseRenewalIntervalInSeconds: 10
        metadataMap:
          instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
    



    三、启动
    按下面的顺序启动
    Eureka server ->Eureka client(say-hello)-> user client(user)
    其中Eureka client 启动时分别用
    --spring.profiles.active=one
    --spring.profiles.active=two
    --spring.profiles.active=three
    启动三个服务,注册到eureka中

    等所有应用都启动后通过界面访问http://localhost:8888/greeting,可以正常访问Eureka client中的方法返回值,整个流程是 界面访问 user client 工程中的hello方法,user client通过@FeignClient中指定的service id从Eureka server中获取到注册的 say-hello instance,因为我们注册到Eureka中的say-hello实例有三个,此处会利用Ribbon的RoundRobinRule规则获取一个实例,调用对应的greet()方法,返回调用结果给 user client,最终返回界面


    猜你喜欢

    转载自fengyilin.iteye.com/blog/2356714