SpringCloud-Ribbon
1. Ribbon简介
Ribbon是一个基于HTTP和TCP的客户端负载均衡器,当使用Ribbon对服务进行访问的时候,他会扩展Eureka客户端的服务发现功能,实现从Eureka注册中心获取服务端列表,并通过Eureka客户端来确定服务端是否已经启动。Ribbon在Eureka客户端服务发现的基础上,实现对服务实例的选择策略,从而实现对服务的负载均衡消费。负载均衡在系统架构中是一个非常重要的内容,因为负载均衡是对系统的高可用、网络的压力的缓冲和处理能力扩容的重要手段之一,我们通常说的负载均衡都是指的是服务端的负载均衡,其中分为硬件负载均衡和软件负载均衡。
-
硬件负载均衡:主要通过服务器节点之间安装专门用于负载均衡的设备,比如F5,深信服,Array等。
-
软件负载均衡:则是通过服务器上安装一些具有负载功能或模块的软件来完成请求分发工作,比如Nginx、LVS、HAProxy等。
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个可用的服务端清单,通过心跳检测来剔除故障的服务端节点保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡的设备时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端地址,然后进行转发。
Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,是一个基于HTTP和TCP的客户端负载均衡工具。SpringCloud对Ribbon做了二次封装,可以让我们使用 RestTemplate的服务请求,自动转换成客户端负载均衡的服务调用。Ribbon支持多种负载均衡算法,还支持自定义的负载均衡算法。Ribbon只是一个工具类框架,比较小巧, SpringCloud对它封装后使用也非常方便,它不像服务注册中心、配置中心、API网关那样需要独立部署, Ribbon 只需要在代码直接使用即可。
Ribbon与 Nginx的区别:
- 都是软负载
- Ribbon是客户端负载均衡
- Nginx是服务器段负载均衡
- 服务端的负载均衡是提前配置好的:Nginx
- 客户端的负载均衡是从注册中心找的:Ribbon
区别在于:
服务清单所存储的位置不同,在客户端负载均衡中,所有客户端节点下的服务端清单,需要自己从服务注册中心上获取,比如Eureka服务注册中心。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,只是这个步骤需要与服务注册中心配合完成,在SpringCloud实现的服务治理框架中,默认会创建针对各个服务治理框架到的Ribbon自动化整合配置,比如Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration
,在实际使用的时候,我们可以通过查看这个类的实现,以找到他们的配置详情来帮助我们更好的使用它。
2. 能干什么
实现微服务间请求的负载均衡策略。
3. Quick Start
通过SpringCloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常的简单,只需要如下两步:
- 服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心上。
- 服务消费者直接通过调用被
@LoadBalanced
注解修饰过的RestTemplate
来实现面向服务的接口调用。
在SpringCloud中,Ribbon主要与RestTemplate对象配合使用,Ribbon会自动化配置RestTemplate对象,通过@LoadBalance开启RestTemplate对象调用时的负载均衡,Ribbon所处的作用如图
创建服务模块如下
3.1 创建服务注册中心
3.1.1 引入依赖坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.1.2 配置application.yml
server:
port: 8080
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
# 是否将自己注册到Eureka服务中,本身就是所有无需注册
registerWithEureka: false
# 是否从Eureka中获取注册信息
fetchRegistry: false
# 客户端与Eureka服务端进行交互的地址
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3.1.3 配置启动类
添加@EnableEurekaServer 标记为EurekaServer
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
3.1.4 启动项目
浏览器输入
localhost:8080
访问注册中心
3.2 创建服务提供者
3.2.1 引入依赖坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.2.2 配置application.yml
这里将port设置为动态传参,主要是想通过设置vm参数来使启动两个端口不同的服务,以便后续通过consumer调用的时候实现负载均衡效果
server:
# 缺省为8010
port: ${port:8010}
spring:
application:
name: provider
eureka:
client:
# eureka server的路径
serviceUrl:
defaultZone: http://localhost:8080/eureka/
3.2.3 创建测试接口
package com.ldx.provider.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Value("${server.port}")
String port;
@GetMapping("hi")
public String hi(){
// 通过返回port,使掉用端方便查看调用的是那个端口的服务
return "hi~ my port ===" + port;
}
}
3.2.4 配置启动项
通过idea的复制功能创建两个启动模板,且8011模板通过传port参数实现服务端口的动态替换
3.2.5 启动服务
查看注册中心控制台
服务已注册成功
测试服务接口
3.3 创建服务消费者
3.3.1 引入坐标依赖
spring-cloud默认集成了ribbon,所以不用额外的引用ribbon坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.3.2 配置application.yml
server:
port: 8082
spring:
application:
name: consumer
eureka:
client:
# eureka server的路径
serviceUrl:
defaultZone: http://localhost:8080/eureka/
3.3.3 配置启动类
package com.ldx.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
// ribbon 提供的负载均衡注解
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3.3.4 创建测试接口
controller
package com.ldx.consumer.controller;
import com.ldx.consumer.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("hi")
public String hi(){
return helloService.hi();
}
}
service
通过服务名调用(启动类中默认集成了ribbon)
package com.ldx.consumer.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String hi(){
return restTemplate.getForObject("http://PROVIDER/hi",String.class);
}
}
3.3.5 启动项目
查看注册中心控制台
服务注册已成功
测试接口
第一次访问:
第二次访问: