SpringCloud快速学习(2)——Ribbon
Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 NetflixRibbon 实现。通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求自动转换成客户端负载均衡的服务调用。 轮询 hash 权重简单的说 Ribbon 就是 netfix 公司的一个开源项目,主要功能是提供客户端负载均衡算法和服务调用。Rib
·
SpringCloud快速学习(2)——Ribbon
个人的动力节点视频学习笔记 视频地址:https://www.bilibili.com/video/BV1f94y1U7AB
基本介绍
Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix
Ribbon 实现。通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求
自动转换成客户端负载均衡的服务调用。 轮询 hash 权重
简单的说 Ribbon 就是 netfix 公司的一个开源项目,主要功能是提供客户端负载均衡算法和
服务调用。Ribbon 客户端组件提供了一套完善的配置项,比如连接超时,重试等。
在 Spring Cloud 构建的微服务系统中, Ribbon 作为服务消费者的负载均衡器,有两种使
用方式,一种是和 RestTemplate 相结合,另一种是和 OpenFeign 相结合。OpenFeign 已经
默认集成了 Ribbon。
快速上手
架构
02-provider-a
- pom
<?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">
<parent>
<artifactId>02-ribbon</artifactId>
<groupId>edu.bcy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>02-provider-a</artifactId>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- yml
server:
port: 8080
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
hostname: localhost
prefer-ip-address: true
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
- 启动类
@SpringBootApplication
@EnableEurekaClient
public class ProviderAApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderAApplication.class, args);
}
}
- 开放接口
@RestController
public class ProviderController {
@GetMapping("hello")
public String hello(){
return "我是提供者aaaa的接口";
}
}
02-provider-b
基本和 02-provider-a 一致
- pom
<?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">
<parent>
<artifactId>02-ribbon</artifactId>
<groupId>edu.bcy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>02-provider-b</artifactId>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- yml
server:
port: 8081
spring:
application:
name: provider
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
hostname: localhost
prefer-ip-address: true
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
- 启动类
@SpringBootApplication
@EnableEurekaClient
public class ProviderBApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderBApplication.class, args);
}
}
- 开放接口
@RestController
public class ProviderController {
@GetMapping("hello")
public String hello(){
return "我是提供者bbbb的接口";
}
}
02-consumer
- pom
<?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">
<parent>
<artifactId>02-ribbon</artifactId>
<groupId>edu.bcy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>02-consumer</artifactId>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- yml
server:
port: 8082
spring:
application:
name: consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
hostname: localhost
prefer-ip-address: true
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 访问不用的服务可以使用不用的算法规则
#provider: # 先写服务提供者的应用名称
# ribbon:
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #几种算法的全限定类名
ribbon:
eager-load:
enabled: false # ribbon它只有自己的话 能不能做服务发现 借助eureka # ribbon需要去eureka中获取服务列表 如果false就懒加载
eureka:
enabled: true
http: # 我们使用ribbon 用的restTemplate发请求 java.net.HttpUrlConnection 发的请求 很方便 但是它不支持连接池
client: # 发请求的工具有很多 httpClient 它支持连接池 效率更好 如果你想改请求的工具 记得加这个依赖即可
enabled: false
okhttp: # 这个也是请求工具 移动端用的比较多 轻量级的请求
enabled: false
- 启动类
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
/**
* 这个RestTemplate 已经变了
* LoadBalanced 他就会被ribbon来操作
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
/**
* 往容器中放一个rule对象
* 你访问任何一个提供者 都是这个算法
* @return
*/
@Bean
public IRule myRule(){
return new RandomRule();
}
}
- 负载均衡配置(这里实际上由启动类@LoadBalanced实现负载均衡,下面这个类就是看看)
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import org.springframework.stereotype.Component;
@Component
public class MyRule implements IRule {
@Override
public Server choose(Object key) {
return null;
}
@Override
public void setLoadBalancer(ILoadBalancer lb) {
}
@Override
public ILoadBalancer getLoadBalancer() {
return null;
}
}
- 消费者接口
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
/**
* 思考 ribbon是怎么将 http://provider/hello 路径请求成功的
* http://127.0.0.1:8080/hello
* 1.拦截这个请求
* 2.截取主机名称
* 3.借助eureka来做服务发现 list<>
* 4.通过负载均衡算法 拿到一个服务ip port
* 5.reConstructURL
* 6.发起请求
*
* @param serviceName
* @return
*/
@GetMapping("testRibbon")
public String testRibbon(String serviceName){
// 正常来讲 需要 拿到ip和port 以及 路径 才可以用
// http://provider/hello
String result = restTemplate.getForObject("http://" + serviceName + "/hello", String.class);
// 只要你给restTemplate 加了ribbon的注解 项目中这个对象发起的请求 都会走ribbon的代理
// 如果你想使用原生的restTemplate 就需要重新创建一个对象
// RestTemplate myRest = new RestTemplate();
// String forObject = myRest.getForObject("http://localhost:8888/aaa", String.class);
return result;
}
// 轮训的算法 怎么去实现
// 两台机器 A B
// A
// B
// A
// B
// 代码实现轮训的算法 List<机器>
// 请求次数
// int index = 1 % size list.get(index);
// % 取模 取余好处是一个周期函数 让得到的结果 总是小于 除数的
// 1 / 2 1 % 2
// 1%2=1
// 2%2=0
// 3%2=1
// 4%2=0
// 全局顶一个int i = 0
// i++ 线程不安全的
// i % size
// 怎么能做一个线程安全的轮训算法 加锁 效率极低 CAS 自旋锁 没有线程的等待和唤醒的开销
// CAS 优点 性能好 java层面无锁的状态 但是在jvm层面 有锁的cmpxchg
// CAS 缺点 会导致短暂时间内 CPU 飙升 还有ABA 问题
/**
* 核心是负载均衡
* @param serviceName
* @return
*/
@GetMapping("testRibbonRule")
public String testRibbonRule(String serviceName){
ServiceInstance choose = loadBalancerClient.choose(serviceName);
return choose.toString();
}
}
结果
消费者调用生产者
总结
更多推荐
已为社区贡献2条内容
所有评论(0)