SpringCloud快速学习(2)——
软件系统开发定制个人的动力节点视频学习笔记 视频地址: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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- yml
server: port: 8080spring: application: name: providereureka: 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}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 启动类
@SpringBootApplication@EnableEurekaClientpublic class ProviderAApplication { public static void main(String[] args) { SpringApplication.run(ProviderAApplication.class, args); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 开放接口
@RestControllerpublic class ProviderController { @GetMapping("hello") public String hello(){ return "我是提供者aaaa的接口"; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- yml
server: port: 8081spring: application: name: providereureka: 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}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 启动类
@SpringBootApplication@EnableEurekaClientpublic class ProviderBApplication { public static void main(String[] args) { SpringApplication.run(ProviderBApplication.class, args); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 开放接口
@RestControllerpublic class ProviderController { @GetMapping("hello") public String hello(){ return "我是提供者bbbb的接口"; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- yml
server: port: 8082spring: application: name: consumereureka: 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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 启动类
@SpringBootApplication@EnableEurekaClientpublic 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(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 负载均衡配置(这里实际上由启动类@LoadBalanced实现负载均衡,下面这个类就是看看)
import com.netflix.loadbalancer.ILoadBalancer;import com.netflix.loadbalancer.IRule;import com.netflix.loadbalancer.Server;import org.springframework.stereotype.Component;@Componentpublic class MyRule implements IRule { @Override public Server choose(Object key) { return null; } @Override public void setLoadBalancer(ILoadBalancer lb) { } @Override public ILoadBalancer getLoadBalancer() { return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 消费者接口
@RestControllerpublic 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(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
结果
消费者调用生产者