请求发给consumer,consumer调用provider-a和provider-b,达到负载均衡的效果
下面三个服务都作为eureka-client向eureka-server注册
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ProviderController {@GetMapping("hello")public String hello(){return "我是提供者aaaa的接口";}}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ProviderController {@GetMapping("hello")public String hello(){return "我是提供者bbbb的接口";}}
controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;@RestController
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate 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/helloString 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 问题/*** 核心是负载均衡,算法包括轮询、随机、权重、iphash* @param serviceName* @return*/@GetMapping("testRibbonRule")public String testRibbonRule(String serviceName){ServiceInstance choose = loadBalancerClient.choose(serviceName);return choose.toString();}}
启动类:在启动类对restTemplate的bean加上注解@LoadBalanced,这样整个服务内使用restTemplate调用时就能达到负载均衡的效果;
myRule()会定义负载均衡算法,不定义就是轮询,这里是随机算法
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
@EnableEurekaClient
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}/*** 这个RestTemplate 已经变了* LoadBalanced 他就会被ribbon来操作* @return*/@Bean@LoadBalancedpublic RestTemplate restTemplate111(){return new RestTemplate();}/*** 往容器中放一个rule对象* 你访问任何一个提供者 都是这个算法* @return*/@Beanpublic IRule myRule(){return new RandomRule();}}
配置文件:application.yml
server:port: 8082
spring:application:name: consumer
eureka:client:service-url:defaultZone: http://localhost:8761/eurekainstance:hostname: localhostprefer-ip-address: trueinstance-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: truehttp: # 我们使用ribbon 用的restTemplate发请求 底部是java.net.HttpUrlConnection 发的请求 很方便 但是它不支持连接池client: # 发请求的工具有很多 httpClient 它支持连接池 效率更好 如果你想改请求的工具 记得加这个依赖即可enabled: falseokhttp: # 这个也是请求工具 移动端用的比较多 轻量级的请求enabled: false
http://localhost:8082/testRibbon?serviceName=provider
这是consumer接口的url,serviceName是provider的服务名,对应provider-a和provider-b
再次发送请求:
Ribbon 总结(后面的代码中 不会出现 ribbon)
Ribbon 是客户端实现负载均衡的远程调用组件,用法简单
ILoadBalancer 接口:起到承上启下的作用
iloadBalancer loadbalance = iloadBalancers.get(“user-service”)
List servers = Loadbalance.getReachableServers();//缓存起来
Server server = loadbalance .chooseServer(key) //key 是区 id,–》IRule 算法
chooseServer 下面有一个 IRule 算法
IRule 下面有很多实现的负载均衡算法
你就可以使用 eureka+ribbon 做分布式项目