一、ribbon 负载均衡原理
1.客户端负载均衡,通过LoadBalancerclient来实现,ILoadBalancer 通过配置IRule 和IPin 来实现
2.ILoadBalancer 通过每10s 获取一次Eureka 注册地址,获取到注册列表后按照IRule 注册规则进行负载均衡
二、核心原理拦截器
1.ribbon 的核心其实就是代理,通过拦截器的方式
2.拦截器实现的功能1:通过对请求的拦截,获取url ,解析hostname 通过hostname 再到Eureka 拿取真实的ip 端口,建立连接发送数据
3.拦截器实现的功能2:拿到目标服务的列表后,按照Rule规则选择具体的目标服务,从而实现负载均衡
三、代码的实现过程
spring启动过程
1.通过@Bean向spring中注入RestTemplete 对象
2.通过@LoadBanlance 注解,实现RestTemplete 注入拦截器,将自定义的拦截器注入RestTemplete 的拦截器链中
http调用过程
1.调用RestTemplete 调用目标服务交口(hostname+接口名称),RestTemplete 的拦截器会拦截该方法,从而对接口修改和增强,把url地址改为(ip+端口+接口名称)
2.完成规则获取以及ip端口准备后,就开始连接目标服务发送数据,连接是通过httpclient 实现,通过工厂类获取httpclient 连接对象
四、源代码
MyConfig 实现启动时给RestTemplete 绑定拦截器
@Configuration
public class MyConfig {
// 需要使用 Autowired 注解注入所有被 @MyLoadBalanced 定义的 RestTemplate 配置 ,因为使用了 @Configuration
// (required=false) 非必须的, 有没有都可以注入,正常运行
@Autowired(required=false)
@MyLoadBalanced
private List<RestTemplate> tpls = Collections.emptyList();
@Bean
public SmartInitializingSingleton lbInitializing() {
return new SmartInitializingSingleton() {
public void afterSingletonsInstantiated() {
// System.out.println(tpls.size());
for (RestTemplate restTemplate : tpls) {
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
interceptors.add(new MyInterceptor());
//interceptors.add(new MyInterceptor2());
restTemplate.setInterceptors(interceptors);
}
}
};
}
}
MyInterceptor 拦截器类,实现url转化及规则处理
public class MyInterceptor implements ClientHttpRequestInterceptor {
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
System.out.println("####这是自定义拦截器####");
System.out.println("***********旧的 URI:" + request.getURI());
HttpRequest newRequest = new MyRequest(request);
System.out.println("&&&&&&&&&&&&新的 URI:" + newRequest.getURI());
return execution.execute(newRequest, body);
}
MyRequest 封装的新的httpRequest类(ip+端口)
public class MyRequest implements HttpRequest {
HttpRequest sourceRequest;
public MyRequest(HttpRequest sourceRequest){
this.sourceRequest = sourceRequest;
}
public HttpHeaders getHeaders() {
return sourceRequest.getHeaders();
}
public HttpMethod getMethod() {
return sourceRequest.getMethod();
}
public URI getURI() {
try {
URI newUri = new URI("http://localhost:8086/hello");
return newUri;
} catch (URISyntaxException e) {
e.printStackTrace();
}
return sourceRequest.getURI();
}
}
MyController 客户端controller
@RestController
@Configuration
public class MyController {
@Resource(name="tplA")
RestTemplate restTemplate;
@RequestMapping(value="/call", method=RequestMethod.GET)
public String call(){
return restTemplate.getForObject("http://hello-service/call4", String.class);
}
@RequestMapping(value="/hello", method=RequestMethod.GET)
public String hello(){
return "hello word";
}
}
RestTplApp 启动类,把restemplete 注入spring容器以及配置负载均衡标记
@SpringBootApplication
public class RestTplApp {
public static void main(String[] args) {
SpringApplication.run(RestTplApp.class, args);
}
@Bean
//@MyLoadBalanced
RestTemplate tplA(){
return new RestTemplate();
}
@Bean
@MyLoadBalanced
RestTemplate tplB(){
return new RestTemplate();
}
}
五、ribbon的负载均衡算法
1.RoundRobinRule轮询(默认的算法)
2.RandomRule 随机
3.AvailabilityFilteringRule 优先过滤一部分算法,被过滤的是多次访问故障处于断路器状态的服务,以及并发连接数量超过阈值的服务,然后执行轮询算法
4.WeightedResponseTimeRule 响应时间权重算法,响应时间越短,权重越大,被调用的机会越大
5.RetryRule 轮询算法重试,如果轮询失败,则在有限时间内重试
6.BestAvailableRule 并发量算法,优先过滤掉熔断的服务,然后再选择并发量最小的连接
7.ZoneAvoidanceRule 复合算法,计算server的可用性,从而选取最有
六、ribbon 负载算法代码配置
//配置负载均衡的策略为随机,默认算法为轮询算法
@Bean
public IRule myRule()
{
//return new RoundRobinRule();
return new RandomRule();
}
源码地址:https://github.com/197wj/Ribbon