Ribbon快速入门
简介:通过RestTemplate和Ribbon帮我们发起一个远程调用,同时完成负载均衡的任务
沿用上次Eureka服务器代码,创建一个新的空maven模块,里面新建三个springboot模块分别为consumer、provider-a、provider-b,由消费者通过ribbon调用提供者a或b的方法
三个springboot项目依赖还是使用springboot 2.3.12.RELEASE和springcloud Hoxton.SR12
provider-a和provider-b配置文件和controlle代码,controller返回字符串区分到底调用哪个提供者的接口,配置文件只需要修改端口,其他保持一致,两个提供者是同一应用的不同实例,还有启动类需要添加@EnableEurekaClient注解。 @RestController
public class ProviderController {
@GetMapping("hello")
public String hello(){
return "我是提供者aaa的接口";
}
}
@RestController
public class ProviderController {
@GetMapping("hello")
public String hello(){
return "我是提供者bbb的接口";
}
}
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}
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}
消费者consumer配置文件、controller代码、启动类代码,RestTemplate起到发请求的作用,使用@LoadBalanced注解后,项目中restTemplate发起的请求都会走ribbon的代理 @RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
/**
* ribbon将http://provider/hello路径变成http://127.0.0.1:8080/hello
* 1.拦截请求
* 2.截取主机名称
* 3.借助eureka来做服务发现list<>
* 4.通过负载均衡算法 拿到一个服务ip port
* 5.reConstructURL 重构url
* 6.发起请求
* @param serviceName
* @return
*/
@GetMapping("testRibbon")
public String testRibbon(String serviceName){
//需要拿到ip 端口和路径
String result = restTemplate.getForObject("http://" + serviceName + "/hello", String.class);
return result;
}
}
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}
@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();
}
}
启动上次的EurekaServer和本次三个springboot全部启动后, 注意:最好先启动提供者,因为消费者启动后会先去注册中心拉去服务列表,所以如果先启动消费者,等一会再访问即可 访问 localhost:8082/testRibbon?serviceName=provider 这里就是访问消费者的controller,他会通过ribbon轮询访问提供者a和提供者b,刷新页面就会发现交替访问a或b 负载均衡算法:随机 轮询 权重 iphash 轮询算法如何实现? int index = 请求次数 % size list.get(index) %取余好处是一个周期函数,让得到的结果总是小于除数。 假设size=2,可以全局定义一个i,每次请求进来,i+1。1%2=1,2%2=0,3%2=1,4%2=0。这样每次交替访问0和1。但是int i =0 线程不安全,可能导致0 1被调用的次数有差异。 怎么做线程安全的轮询算法? 加锁效率低 cas自旋锁 优点:java层面无锁的状态, 性能好 没有线程等待和唤醒的开销,缺点:会导致短暂时间内cpu飙升 还有ABA问题 轮询源码,可以通过loadBalancerClient.choose()找到源码chooseRoundRobinAfterFiltering方法,RoundRobin就是轮询的意思,eligible.size()也就是集合大小,再进incrementAndGetModulo方法 /**
* 核心是负载均衡
* @param serviceName
* @return
*/
@GetMapping("testRibbonRule")
public String testRibbonRule(String serviceName){
//choose方法里面就是负载均衡算法
ServiceInstance choose = loadBalancerClient.choose(serviceName);
return choose.toString();
}
public Optional
List
return eligible.size() == 0 ? Optional.absent() : Optional.of(eligible.get(this.incrementAndGetModulo(eligible.size())));
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextIndex.get();
next = (current + 1) % modulo;
} while(!this.nextIndex.compareAndSet(current, next) || current >= modulo);
return current;
}
如何修改负载均衡算法?
修改配置文件,对每个服务设置负载均衡算法 # 访问不同的服务可以使用不同的算法规则
provider: # 服务提供者的应用名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 算法的全限定类名
修改java代码,全局配置负载均衡算法 /**
* 全局配置负载均衡算法
* 往容器中放一个rule对象
* 访问任何提供者都是这个算法
* @return
*/
@Bean
public IRule myRule(){
return new RandomRule();
}
其他配置项 ribbon:
eager-load:
enabled: true # ribbon需要去eureka获取服务列表 false是懒加载(默认false)
eureka:
enabled: true
http: # 使用ribbon 用的restTemplate发请求(封装的) java.net.HttpUrlConnection发请求(java原生 不支持连接池)
client: # 发请求的工具很多 httpClient 支持连接池 效率高 如果想使用 改为true
enabled: false
okhttp: # 移动端使用比较多的请求工具 轻量级的请求 需要改为true
enabled: false
推荐链接
发表评论