Ribbon负载均衡
流水不争先,争得是滔滔不绝
负载均衡原理
Spring Cloud底层是利用了一个叫Ribbon的组件,来实现负载均衡功能的。流程如下图:
跟踪源码
那么为什么用RestTemplate发出的请求明明是http://userservice/user/,却变成了http://localhost:8081呢?
很明显是有什么根据服务名称,获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor
,这个类会对有@LoadBalanced
注解的类发送HTTP请求时进行拦截,然后从Eureka中根据服务id(也就是服务名称)获取服务列表,再利用负载均衡算法得到真实的服务地址信息,用真实的ip和端口替换服务名称。
1.LoadBalancerInterceptor
|
|
可以看到这里的intercept方法,拦截了用户的HttpRequest请求,然后做了几件事:
- request.getURI():获取请求uri,比如order-service发送的
http://userservice/user/102
请求 - originalUri.getHost():获取uri路径的主机名,也就是服务名userservice
- this.loadBalancer.execute():处理服务和用户请求
这里的this.loadBalancer
是LoadBalancerClient
类型,我们继续跟入。
2.LoadBalancerClient
|
|
代码是这样的:
- getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。
- getServer(loadBalancer, hint):利用内置的负载均衡算法,从服务列表中选择一个服务。
3.负载均衡策略IRule
在上面的代码中,可以看到获取服务是通过一个getServer
方法来做负载均衡,继续跟入进去:
|
|
继续进入chooseServer方法,发现:
选择服务的是这个rule,而这个rule的默认值是一个RoundRobinRule
:
再看这个RoundRobinRule
类的介绍:
到这里,整个负载均衡的流程就很清楚了。
4.总结
基本流程:
- 拦截带有
@LoadBalanced
注解RestTemplate
的请求http://userservice/user/1 - RibbonLoadBalancerClient从请求url中获取服务名称,也就是userservice
- DynamicServerListLoadBalancer根据userservice到eureka拉取服务列表
- eureka返回列表,localhost:8081、localhost:8082
- IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081
- RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求
负载均衡策略
Ribbon的负载均衡规则是一个叫做IRule的接口来定义的,每一个子接口都是一种规则
不同规则的含义如下:
默认的实现是ZoneAvoidanceRule,一种轮询方案。
1.修改负载均衡策略
通过定义IRule实现可以修改负载均衡规则,有两种方式:
1、代码方式:定义一个新的IRule,这种方法会给所有发送的微服务请求指定负载均衡规则
|
|
2、配置文件方式:给某个微服务指定负载均衡规则
|
|
饥饿加载
Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。
而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面的配置可以开启饥饿加载:
|
|
|
|