源码仓库地址:https://github.com/heibaiying/spring-samples-for-all

一、ribbon 简介

ribbon是Netfix公司开源的负载均衡组件,采用服务端负载均衡的方式,即消费者客户端维护可用的服务列表,并通过负载均衡的方式将请求按照指定的策略分摊给消费者,从而达到负载均衡的方式。

二、项目结构

  • common: 公共的接口和实体类;
  • consumer: 服务的消费者,采用RestTemplate调用产品服务;
  • producer:服务的提供者;
  • eureka: 注册中心,ribbon 从注册中心获取可用的服务列表,是实现负载均衡的基础。这里使用我们在服务的注册与发现这个用例中搭建的简单注册中心作为测试即可。

三、服务提供者的实现

3.1 产品服务由ProductService提供,并通过ProducerController将服务暴露给外部调用。

ProductService.java:

/**
 * @author : heibaiying
 * @description : 产品提供接口实现类
 * 这里为了之后直观的看到负载均衡的结果,我们继承了 ApplicationListener,从 WebServerInitializedEvent 获取服务的端口号,并拼接在产品名称上
 */
@Service
public class ProductService implements IProductService, ApplicationListener<WebServerInitializedEvent> {

    private static List<Product> productList = new ArrayList<>();

    public Product queryProductById(int id) {
        for (Product product : productList) {
            if (product.getId() == id) {
                return product;
            }
        }
        return null;
    }

    public List<Product> queryAllProducts() {
        return productList;
    }

    @Override
    public void saveProduct(Product product) {
        productList.add(product);
    }

    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        int port = event.getWebServer().getPort();
        for (long i = 0; i < 20; i++) {
            productList.add(new Product(i, port + "产品" + i, i / 2 == 0, new Date(), 66.66f * i));
        }
    }
}

ProducerController.java:

@RestController
public class ProducerController {

    @Autowired
    private IProductService productService;

    @GetMapping("products")
    public List<Product> productList() {
        return productService.queryAllProducts();
    }

    @GetMapping("product/{id}")
    public Product productDetail(@PathVariable int id) {
        return productService.queryProductById(id);
    }

    @PostMapping("product")
    public void save(@RequestBody Product product) {
        productService.saveProduct(product);
    }
}

3.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient

server:
  port: 8020
# 指定服务命名
spring:
  application:
    name: producer
# 指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8010/eureka/
@SpringBootApplication
@EnableDiscoveryClient
public class ProducerApplication {

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

}

四、服务消费者的实现

4.1 导入负载均衡需要的依赖

<!--ribbon 依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

4.2 指定注册中心地址,并在启动类上开启自动注册@EnableDiscoveryClient

server:
  port: 8080
# 指定服务命名
spring:
  application:
    name: consumer
# 指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8010/eureka/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

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

}

4.3 使用@LoadBalanced配置RestTemplate即可实现客户端负载均衡

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

    @LoadBalanced   // 配置客户端负载均衡
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

4.4 使用RestTemplate调用远程服务

这里我们在调用远程服务的时候,url填写的是服务名+具体接口地址 ,由于我们的同一个服务会存在多个实例,在使用@LoadBalanced配置RestTemplate调用服务时,客户端就会从按照指定的负载均衡的方式将请求分摊到多个实例上。(默认的负载均衡采用的是RoundRobinRule(轮询)的策略,有特殊需求时候可以采用其他内置的策略规则,或者实现IRule来定义自己的负载均衡策略)。

@Service
public class ProductService implements IProductService {

    @Autowired
    private RestTemplate restTemplate;

    public Product queryProductById(int id) {
        ResponseEntity<Product> responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id);
        return responseEntity.getBody();
    }

    public List<Product> queryAllProducts() {
        ResponseEntity<List> responseEntity = restTemplate.getForEntity("http://producer/products", List.class);
        List<Product> productList = responseEntity.getBody();
        return productList;
    }

    public void saveProduct(Product product) {
        restTemplate.postForObject("http://producer/product", product, Void.class);
    }
}

五、启动测试

5.1 启动一个Eureka服务、三个producer服务(注意区分端口)、和一个消费者服务

服务注册中心:

5.2 访问http://localhost:8080/sell/products 查看负载均衡的调用结果

六、 附1: 关于RestTemplate的说明

6.1 restTemplate 规范

restTemplate 调用对应resultful接口时候,使用的方法应该与接口声明方式(@GetMapping、@PostMapping、@PutMapping、@DeleteMapping)保持一致。请求类型与对应的调用方法如下。

  • GET请求(getForObject 、getForEntity)
  • POST请求(postForObject 、postForEntity)
  • PUT请求(put)
  • DELETE请求 (delete)

6.2 ForEntity()和ForObject的区别

  • ForEntity()发送一个请求,返回的ResponseEntity包含了响应体所映射成的对象
  • ForObject()发送一个请求,返回的请求体将映射为一个对象

例如:

ResponseEntity<Product> responseEntity = restTemplate.getForEntity("http://producer/product/{1}", Product.class, id);
Product product = restTemplate.getForObject("http://producer/product/{1}", Product.class, id);

七、 附2: 关于ribbon更多负载均衡的策略

Ribbon内置了多种负载均衡策略,如果有更复杂的需求,可以自己实现IRule。

7.1 内置的负载均衡的策略如下图

图片来源于博客:Ribbon负载均衡策略与自定义配置

7.2 配置文件指定负载均衡的方式

要设置IRule名为的服务名称users,您可以设置以下属性:

users:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

7.3 代码指定负载均衡的方式

@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class TestConfiguration {
}
@Configuration
public class CustomConfiguration {

	@Bean
	public IRule ribbonRule() {
		return new BestAvailableRule();
	}
}

在使用代码方式的时候需要注意 官方文档中关于注解方式有以下强调:

The CustomConfiguration clas must be a @Configuration class, but take care that it is not in a @ComponentScan for the main application context. Otherwise, it is shared by all the @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the @ComponentScan).

CustomConfiguration类必须是@Configuration标注的,但需要注意的它不是在@ComponentScan主应用程序上下文。否则,它将由所有@RibbonClients共享。如果你使用@ComponentScan(或@SpringBootApplication),你需要采取一些措施来避免它被扫描到(例如,你可以把它放在一个独立的,非重叠的包,或用@ComponentScan时显示扫描指定的包)。

源码仓库地址:https://github.com/heibaiying/spring-samples-for-all

spring cloud 系列第3篇 —— ribbon 客户端负载均衡 (F版本)的更多相关文章

  1. Spring Cloud系列教程第九篇-Eureka自我保护机制

    Spring Cloud系列教程第九篇-Eureka自我保护机制 本文主要内容: 1:自我保护介绍 2:导致原因分析 3:怎么禁止自我保护 本文是由凯哥(凯哥Java:kagejava)发布的< ...

  2. spring cloud --- Ribbon 客户端负载均衡 + RestTemplate ---心得【无熔断器】

    spring boot      1.5.9.RELEASE spring cloud    Dalston.SR1 1.前言 了解了 eureka 服务注册与发现 的3大角色 ,会使用RestTem ...

  3. 3.Spring Cloud初相识--------Ribbon客户端负载均衡

    前言: 在生产环境中,未避免单点故障,每个微服务都会做高可用部署. 通白的说,就是每一个一模一样的服务会根据需求提供多分在多台机器上. 那么在大并发的情况下,如何分配服务可以快速得到响应,就成为了我们 ...

  4. spring cloud系列教程第一篇-介绍

    spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...

  5. Spring cloud系列教程第二篇:支付项目父工程图文搭建

    Spring cloud系列教程第二篇:支付项目父工程图文搭建 在讲解spring cloud相关的技术的时候,咱们就模拟订单支付这个流程来讲讲 在这个支付模块微服务搭建过程中,上面的这些技术,都会融 ...

  6. spring cloud --- Ribbon 客户端负载均衡 + RestTemplate + Hystrix 熔断器 [服务保护] ---心得

    spring boot      1.5.9.RELEASE spring cloud    Dalston.SR1 1.前言 当超大并发量并发访问一个服务接口时,服务器会崩溃 ,不仅导致这个接口无法 ...

  7. springcloud(十二):Ribbon客户端负载均衡介绍

    springcloud(十二):Ribbon客户端负载均衡介绍 Ribbon简介 使用分布式微服务脚骨的应用系统,在部署的时候通常会为部分或者全部微服务搭建集群环境,通过提供多个实例来提高系统的稳定型 ...

  8. SpringBoot(三) - Ribbon客户端负载均衡,Zuul网关,Config配置中心

    1.Ribbon客户端负载均衡 1.1 依赖 1.2 配置信息 # feign默认加载了ribbon负载均衡,默认负载均衡机制是:轮询 # 负载均衡机制是添加在消费端(客户端)的,如果改为随机,指定服 ...

  9. 笔记:Spring Cloud Ribbon 客户端负载均衡

    Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,基于 Netflix Ribbon 实现,通过Spring Cloud 的封装,可以让我们轻松的将面向服 ...

随机推荐

  1. java学习笔记(2)——函数

    int a = 1; a = a++; 1,取出a的值1作为a++表达式的值(a++表达式等于1) 2,a增加1变为2 3,执行赋值运算,a++表达式的值再赋给a,a又成为了1. ---------- ...

  2. WPF教程002 - 实现Step步骤条控件

    原文:WPF教程002 - 实现Step步骤条控件 在网上看到这么一个效果,刚好在用WPF做控件,就想着用WPF来实现一下 1.实现原理 1.1.该控件分为2个模块,类似ComboBox控件分为Ste ...

  3. WPF 悬浮键盘

    原文:WPF 悬浮键盘 public class TouchScreenKeyboard : Window { #region Property & Variable & Constr ...

  4. WPF 代码实现动画

    <Window x:Class="wpf180709.Window2"        xmlns="http://schemas.microsoft.com/win ...

  5. WPF x:Array的使用

    <Window x:Class="XamlTest.Window1"        xmlns="http://schemas.microsoft.com/winf ...

  6. 错误:“ResourceDictionary”根元素需要 x:Class 特性来支持 XAML 文件中的事件处理程序。请移除 MouseLeftButtonDown 事件的事件处理程序.

    原文:错误:"ResourceDictionary"根元素需要 x:Class 特性来支持 XAML 文件中的事件处理程序.请移除 MouseLeftButtonDown 事件的事 ...

  7. C#判断系统是32位还是64位

    bool type; type = Environment.Is64BitOperatingSystem; Console.WriteLine(type);

  8. Android疑难杂症之Theme

    背景:最近在把自己之前写的一个应用换成Material Design风格,在看官方Guide后动手试了一试,没想到出门就遇到了坑,在换成Material Design风格的主题后,我设置了一下colo ...

  9. 论文阅读计划1(Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming & An Enforcement of Real Time Scheduling in Spark Streaming & StyleBank: An Explicit Representation for Neural Ima)

    Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming[1] 简介:雅虎发布的一份各种流处理引擎的基准 ...

  10. HTTP通信过程原理

    HTTP协议 通信过程介绍 HTTP协议介绍 Http(Hypertext Transfer Protocol)超文本传输协议. Http是应用层协议,当你上网浏览网页的时候,浏览器和服务器之间就会通 ...