文章目录
- 1. 作用:负载均衡
- 2. 应用实战
- 2.1 provider-a代码
- 2.2 provider-b代码
- 2.3 consumer代码
- 2.4 api工具向consumer发送请求查看对provider的调用情况
- 3. ribbon总结
- 3.1 Ribbon 源码核心
- 3.2 如何实现负载均衡的呢?
1. 作用:负载均衡
2. 应用实战
请求发给consumer,consumer调用provider-a和provider-b,达到负载均衡的效果
下面三个服务都作为eureka-client向eureka-server注册
2.1 provider-a代码
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的接口";
}
}
2.2 provider-b代码
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的接口";
}
}
2.3 consumer代码
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 {
@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 问题
/**
* 核心是负载均衡,算法包括轮询、随机、权重、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
@LoadBalanced
public RestTemplate restTemplate111(){
return new RestTemplate();
}
/**
* 往容器中放一个rule对象
* 你访问任何一个提供者 都是这个算法
* @return
*/
@Bean
public IRule myRule(){
return new RandomRule();
}
}
配置文件:application.yml
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}
# 访问不同的服务可以使用不同的算法规则,在启动类配置了,这里就不用配置了
#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
2.4 api工具向consumer发送请求查看对provider的调用情况
http://localhost:8082/testRibbon?serviceName=provider
这是consumer接口的url,serviceName是provider的服务名,对应provider-a和provider-b
再次发送请求:
3. ribbon总结
Ribbon 总结(后面的代码中 不会出现 ribbon)
Ribbon 是客户端实现负载均衡的远程调用组件,用法简单
3.1 Ribbon 源码核心
ILoadBalancer 接口:起到承上启下的作用
- 承上:从 eureka 拉取服务列表
- 启下:使用 IRule 算法实现客户端调用的负载均衡
设计思想:每一个服务提供者都有自己的 ILoadBalancer
userService—》客户端有自己的 ILoadBalancer
TeacherService—》客户端有自己的 ILoadBalancer
在客户端里面就是 Map<String,ILoadBalancer> iLoadBalancers
Map<String,ILoadBalancer> iLoadBalancers 消费者端
服务提供者的名称 value (服务列表 算法规则 )
3.2 如何实现负载均衡的呢?
iloadBalancer loadbalance = iloadBalancers.get(“user-service”)
List servers = Loadbalance.getReachableServers();//缓存起来
Server server = loadbalance .chooseServer(key) //key 是区 id,–》IRule 算法
chooseServer 下面有一个 IRule 算法
IRule 下面有很多实现的负载均衡算法
你就可以使用 eureka+ribbon 做分布式项目