源码仓库地址: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. WPF Bind 绑定

    原文:WPF Bind 绑定 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/koloumi/article/details/74332515 用过W ...

  2. Java踩坑之路

    陆陆续续学Java也快一年多了,从开始的一窍不通到现在的初窥门径,我努力过,迷茫过,痛过,乐过,反思过,沉淀过.趁着新年,我希望能把这些东西记下来,就当是我一路走来的脚印. 一.初识网站应用 记得第一 ...

  3. Oracle实践--PL/SQL综合之分页存储过程

    Oracle PL/SQL分页的存储过程 Oracle,分页,存储过程三个词结合起来,来个综合点的小练习,运用之前的PL/SQL创建一个分页的存储过程,仅仅须要简单几步就可以. 1.声明一个引用游标 ...

  4. 写在程序猿的困惑(特别Java程序猿)入行一年,感觉我不知道接下来该怎么办才能不断进步的,寻求翼

    入行了一年.感觉不知道接下来该怎么做才干继续进步了,求不吝赐教(V2EX) @kafka0102 :做技术能够学的东西太多了.仅仅是在不同的阶段做好不同的规划.要结合当前所做的事情去做更深入或广度的学 ...

  5. 常见信号的模拟仿真(matlab)(spike signal)

    1. 一维信号 构造离散时间向量: Fs = 1000; % sampling frequency,采样频率 T = 1/Fs; % sampling period,采样周期 L = 1000; % ...

  6. Linux(CentOS 7)+ Nginx(1.10.2)+ Mysql(5.7.16)+ PHP(7.0.12)完整环境搭建

    首先安装Linux系统,我以虚拟机安装来做示例,先去下载 VitualBox,这是一款开源的虚拟机软件,https://www.virtualbox.org 官网地址.或者是VMware,www.vm ...

  7. 特殊存储过程——触发器Trigger

    触发器类型 insert 触发器delete 触发器update 触发器 Inserted和Deleted两个临时表的作用 Inserted:对于插入记录操作来说,插入表里存放的是要插入的数据:对于更 ...

  8. js动态创建表格

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  9. 基于IOCP的高速文件传输代码

    //服务端: const   //transmit用的参数   TF_USE_KERNEL_APC     = $20;   //命令类型   CMD_CapScreen             =  ...

  10. PHP的MIPS交叉编译(CC=mipsel-openwrt-linux-uclibc-gcc,LD=mipsel-openwrt-linux-uclibc-ld)

    物联网内存吃紧,跑JVM这种内存大户肯定吃不消.要跑还是跑C实现的服务,比如Nginx+PHP+SQLite.比如一些家用无线路由器,系统是Linux发行版OpenWrt,内存只有64MB到128MB ...