源码仓库地址: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. 初次使用glog

    一.安装配置 1.简单介绍 google 出的一个C++轻量级日志库,支持下面功能: ◆ 參数设置,以命令行參数的方式设置标志參数来控制日志记录行为: ◆ 严重性分级,依据日志严重性分级记录日志: ◆ ...

  2. 构建自己的PHP框架(邮件发送)

    完整项目地址:https://github.com/Evai/Aier 我们采用 'nette/mail' 包作为我们的邮件发送基础模块,在它的基础上封装一个 'Mail' 类,暴露出简洁的 API ...

  3. duilib拖动控制功能的实现(源代码)

    转载请注明原始出处.谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41144283 duilib库中原本没有显示的对控件添加拖拽的功能.而实 ...

  4. .net reactor 学习系列(四)---.net reactor应用场景

    原文:.net reactor 学习系列(四)---.net reactor应用场景         前面已经学习了.net reactor一些基础知识,现在准备学习下实际的应用场景,只是简单的保护和 ...

  5. Ajax请求小结

    参数说明 ajax请求异步刷新页面=把需要异步刷新的页面单独写成一个.cshtml进行操作$.ajax({}); -------ajax方法.type: ------- 类型,此处为“POST” 还有 ...

  6. WPF 4 开发Windows 7 跳转列表(JumpList)

    原文:WPF 4 开发Windows 7 跳转列表(JumpList)      在之前写过的<Windows 7 任务栏开发系列>中我们通过Visual Studio 2008 借助微软 ...

  7. Bootstrap 标签徽章巨幕页头

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  8. JS 密码弱中强显示

    <!DOCTYPE html><html><head>    <meta http-equiv="Content-Type" conten ...

  9. WPF MVVM+EF增删改查 简单示例(二) 1对1 映射

    WPF MVVM+EF增删改查 简单示例(一)实现了对学生信息的管理. 现在需求发生变更,在录入学生资料的时候同时需要录入学生的图片信息,并且一名学生只能有一张图片资料.并可对学生的图片资料进行更新. ...

  10. 图像滤镜艺术---(Instagram)1977滤镜

    原文:图像滤镜艺术---(Instagram)1977滤镜 图像特效---(Instagram)1977滤镜 本文介绍1977这个滤镜的具体实现,这个滤镜最早是Instagram中使用的 ,由于Ins ...