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 chooseRoundRobinAfterFiltering(List servers, Object loadBalancerKey) {

List eligible = this.getEligibleServers(servers, loadBalancerKey);

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

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。