springcloud ribbon实现原理
一、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