二.、SpringCloud服务消费者(rest+ribbon)

一、ribbon简介

负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。
目前主流的负载方案分为两种,一种是集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的,比如F5,也有软件的,比如Nginx。另一种则是客户端自己做负载均衡,根据自己的请求情况做负载,Ribbon就是属于客户端自己做负载的。
ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。Feign默认集成了ribbon。比Nginx更注重的是承担并发而不是请求分发,可以直接感知后台动态变化来指定分发策略。它一共提供了7种负载均衡策略,Ribbon默认的策略是轮询,我们可以自定义负载策略来覆盖默认的,当然也可以通过配置指定使用哪些策略。

策略名 策略声明 策略描述 实现说明
BestAvailableRule public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 选择一个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
AvailabilityFilteringRule public class AvailabilityFilteringRule extends PredicateBasedRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRule public class WeightedResponseTimeRule extends RoundRobinRule 根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成status时,使用roubine策略选择server。
RetryRule public class RetryRule extends AbstractLoadBalancerRule 对选定的负载均衡策略机上重试机制。 在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server
RoundRobinRule public class RoundRobinRule extends AbstractLoadBalancerRule roundRobin方式轮询选择server 轮询index,选择index对应位置的server
RandomRule public class RandomRule extends AbstractLoadBalancerRule 随机选择一个server 在index上随机,选择index对应位置的server
ZoneAvoidanceRule public class ZoneAvoidanceRule extends PredicateBasedRule 复合判断server所在区域的性能和server的可用性选择server 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。

二、创建多个eureka-client实例

继续上一个例子,启动eureka-server 工程;启动service-ls1工程,它的端口为8005;将service-ls2的配置文件的端口改为8006,并启动,这时你会发现:service-ls在eureka-server注册了2个实例,这就相当于一个小的集群。访问localhost:8001如图所示:
这里写图片描述

二、创建服务消费者

1.新建一个spring-boot工程,名为:service-ribbon;
在它的pom.xml文件分别引入起步依赖spring-cloud-starter-eureka、spring-cloud-starter-ribbon、spring-boot-starter-web,如下:

<?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>serice-feign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>serice-feign</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</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>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

2.在工程的配置文件指定服务的注册中心地址为http://localhost:8001/eureka/,程序名称为 service-ribbon,程序端口为8000。配置文件application.yml如下:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8001/eureka/
server:
  port: 8000
spring:
  application:  
    name: service-ribbon    

3.在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册;并且向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。

package com.example.serviceribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
@EnableHystrix  //开启断路由模式
@EnableCircuitBreaker
@EnableHystrixDashboard
public class ServiceRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceRibbonApplication.class, args);
    }
    /**
     * @LoadBalanced注解表明这个restRemplate开启负载均衡的功能
     * @return
     */
    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
    //配置策略
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}

4.写一个测试类TestService,通过之前注入ioc容器的restTemplate来消费service-ls服务的“/port”接口,在这里我们直接用的程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名,代码如下:
TestService类代码:

package com.example.serviceribbon.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class TestService {
    @Autowired
    RestTemplate restTemplate;

    public String getServerName() {
        return restTemplate.getForObject("http://service-ls/port",String.class);
    }
}

TestController,在controller中用调用TestService 的方法,代码如下

package com.example.serviceribbon.controller;
import com.example.serviceribbon.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
    @Autowired
    TestService testService;
    @RequestMapping(value = "/getPort")
    public String getPort(){
        return testService.getServerName();
    }
}

在浏览器上多次访问http://localhost:80004/getPort,浏览器交替显示:

我的端口是:8005
我的端口是:8006

这说明当我们通过调用restTemplate.getForObject(“http://SERVICE-ls/port“,String.class)方法时,已经做了负载均衡,访问了不同的端口的服务实例。

运行流程:

1)启动一个高可用的Eureka-server
2)创建一个服务应用,以对外提供接口服务
3)复制一份该服务端服务,除了端口号不一致其他都保持一致,尤其spring.application.name要保持一致,用于验证在外部请求到达时是否负载均衡
一个服务注册中心,eureka server,端口为8001
service-ls工程跑了两个实例,端口分别为8005,8006,分别向服务注册中心注册
sercvice-ribbon端口为8000,向服务注册中心注册
当sercvice-ribbon通过restTemplate调用service-ls的port接口时,因为用ribbon进行了负载均衡,会轮流的调用service-port:8005和8006 两个端口的hi接口;

猜你喜欢

转载自blog.csdn.net/u010520146/article/details/81461729
今日推荐