springcloud-Ribbon负载均衡服务调用
Posted yellowstreak
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springcloud-Ribbon负载均衡服务调用相关的知识,希望对你有一定的参考价值。
Ribbon入门介绍
- 是什么
- Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具.
- Ribbon主要功能是提供客户端的软件负载均衡算法和服务调用.
- Ribbon客户端组件提供一系列完整的配置项如连接超时, 重试等. 简单的说, 就是在配置文件中列出Load Balancer后所有的机器, Ribbon会自动帮我们基于某种规则(如简单轮询, 随机连接)去链接这些机器, 我们很容易使用Ribbon实现自定义的负载均衡算法.
- 负载均衡
- 简单的说就是将用户的请求平摊到多个服务上, 从而达到系统的高可用, 常见的负载均衡有软件nginx, LVS, 硬件F5等.
- Ribbon负载均衡 VS Nginx负载均衡
- Nginx是服务器负载均衡, 客户端所有请求都会交给nginx, 然后由nginx实现转发请求, 即负载均衡是由服务端实现的.
- Ribbon是客户端负载均衡, 在调用微服务接口的时候, 会在注册中心上获取注册信息服务列表之后缓存到JVM本地, 从而在本地实现RPC远程服务调用技术.
- 集中式LB
- 在服务的消费方和提供方之间使用独立的LB设施(如Nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方.
- 进程内LB
- 将LB逻辑集成到消费方, 消费方从服务注册中心获知哪些地址可用, 然后自己再从这些地址中选出一个合适的服务器.
- Ribbon就属于进程内LB, 它只是一个类库, 集成于消费方进程, 消费方通过它来获取到服务提供方的地址.
Ribbon负载均衡演示
- 所谓Ribbon, 简单的说就是负载均衡 + RestTemplate
- 架构说明
- Ribbon在工作时分两步
- 第一步先选择Eureka Server, 它优先选择在同一个区域内负载较少的server.
- 第二步再根据用户指定的策略, 在从server取到的服务注册列表中选择一个地址.
- 策略有多种可选, 如轮询, 随机, 根据响应时间加权.
- 这里需要注意, Ribbon其实就是一个软负载均衡的客户端组件, 它可以和其他所需请求的客户端结合使用, 这里仅用Eureka举例.
- POM分析
- 我们只加入了eureka的依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
- 而在Eureka中是有Ribbon的依赖的
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.1.RELEASE</version> <scope>compile</scope> </dependency>
- 详细讲解RestTemplate
Ribbon核心组件IRule
- IRule接口: 根据特定算法从服务列表中选取一个要访问的服务
- 有7种负载均衡策略
- 切换负载均衡策略
- 我们要写的自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下, 否则我们自定义的配置类就会被所有的Ribbon客户端共享, 达不到特殊化定制的目的了.
- 我们新建package及配置类
- 配置类代码
@Configuration public class MySelfRule { @Bean public IRule myRule() { //将负载均衡策略改为随机 return new RandomRule(); } }
- 主启动类上要加@RibbonClient注解
- name属性: 服务提供者(负载均衡请求的接收方)
- configuration属性: 指明我们的配置类
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class) @EnableEurekaClient @SpringBootApplication public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } }
- 测试: http://localhost/consumer/payment/get/1
Ribbon负载均衡算法
- 负载轮询算法原理
- rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标.
- 集群总数量: 2台. (List = 2 instance)
- 第一次: 1 % 2 = 1
- 第二次: 2 % 2 = 0
- 第三次: 3 % 2 = 1
- ......
- 如果重启了, 那么会从1重新开始.
- 手写一个负载轮询算法
- 在8001/8002微服务的controller添加如下方法
@GetMapping("/payment/lb") public String getPaymentLB() { return serverPort; }
- 80订单微服务改造
- 去掉@LoadBalanced注解
- LoadBalancer接口
public interface LoadBalancer { ServiceInstance instances(List<ServiceInstance> serviceInstances); }
- MyLB
@Component public class MyLB implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger(0); public final int getAndIncrement() { int current; int next; do { current = this.atomicInteger.get(); next = current >= 2147483000 ? 0 : current+1; } while(!this.atomicInteger.compareAndSet(current, next)); return next; } @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
- controller方法
@Resource private RestTemplate restTemplate; @Resource private LoadBalancer loadBalancer; @Resource private DiscoveryClient discoveryClient; @GetMapping("/consumer/payment/lb") public String getPaymentLB() { List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if(instances == null || instances.size() <= 0) { return null; } ServiceInstance serviceInstance = loadBalancer.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri+"/payment/lb", String.class); }
- 测试: http://localhost/consumer/payment/lb
以上是关于springcloud-Ribbon负载均衡服务调用的主要内容,如果未能解决你的问题,请参考以下文章