负载均衡原理
负载均衡流程
首先回忆前面利用userService发起请求时的地址:
是真实可用的地址吗?
不是,这点我们通过浏览器访问就知道不是一个真实的地址,所以它一定是被经过了某些操作和处理才能够顺利访问到我们的user-service。
这就是Ribbon组件来解决的,处理流程如下:
接下里深入源码中了解细节:
首先是@LoadBalanced这个注解,它就标记了RestTemplate发起的请求会被Ribbon组件拦截和处理了。
而拦截的动作就是下面这个负载均衡拦截器类来完成的:
该类实现了ClientHttpRequestIntecepter接口,可以再看看这个接口里面有啥:
上面的文档注释说明了这个接口定义的方法就是为了拦截Http请求的,而我们的RestTemplate正好就是一个发送http请求的客户端。
这个接口里面定义了一个方法:
所以上面的那个实现类一定会实现这个方法:
打断点后进行测试:
可以看见这个方法会去拿到请求中的URI,然后又拿到主机名:
接下来就是我们之前说的要去找Eureka拿注册好的那些服务地址了。
可以看见接下来该方法就将刚刚拿到的东西交给了一个叫loadBalancer:
而这个loadBalancer就是我们的Ribbon组件中的内容。
进入excute方法:
继续跟入:
继续往下走:
就会发现拿到了一个动态服务列表负载均衡的对象,在这个对象中就有我们注册好了的服务列表:
所以现在就该进行负载均衡了,负载均衡的做法也就是上面的getServer方法,我们进去看看:
下面有个chooseServer方法,我们继续进入看看:
可以看见这里调用了父类的chooseServer方法,继续跟进,然后查看在父类方法中内容是什么样的:
可以看见有上面这行代码,其中有个rule规则,这个rule又是IRule接口类型:
该接口有诸多实现类,可以看见其中有个RandomRule随机规则类,RoundRobinRule轮询调度规则类,这个有兴趣再去看它的算法叭。然后继续往下执行之后就会拿到一个服务地址后就可以进行微服务的访问了。
总结如下:
负载均衡策略
通过上节课的学习,我们明白了IRule接口决定了负载均衡的策略。
现在我们就来学习IRule里面有什么实现,我们将来如何根据业务需要修改里面的实现。
下图是IRule的继承关系图:
ZoneAvoidanceRule是默认的实现类。
那么现在我们要去修改负载均衡的规则,该如何做?
下面是第一种方式:
我们现在默认的是轮询机制,即同一个服务的实例一人执行一次。
测试,我们访问101、102、103、104,访问四次:
可以看见每个实例各自执行了两次,即8081端口执行一次,然后8082端口执行一次,然后又8081执行一次,再8082执行一次。
然后现在要自定义负载均衡策略的话,就去需要发起请求的配置类中写上配置如下即可:
现在我们再去连续访问四次看看:
可以看见8081只被访问了一次,而8082被访问了3次。
这种配置方式是作用于全局的,order服务中一旦配了这种方案,则以后不管是现在是user服务还是商品服务,都是采用这种配置过后了的负载均衡策略,即这里的随机策略。
第二种方式则是在配置文件中进行操作,而这种方式则是可以只针对于某一个微服务而言的:
我们来做一下这件事。
我们去orderservice中的配置文件里面,进行负载均衡策略的配置:
userservice: #所需要进行负载均衡策略改变的服务名称
ribbon: #Ribbon组件
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机负载均衡的规则
重启之后(注意之前的Bean方式要注释掉),继续访问101、102、103、104,结果如下:
可以看见是随机访问的。
饥饿加载与懒加载
先测试重启OrderService,然后我们进行访问(注意这里是重启之后的第一次):
第一次访问使用了550ms,再请求一次:
发现只有25ms了。
这就是因为懒加载的原因,想加速就像上面的图片里面那样在orderservice里面进行配置即可。
ribbon:
eager-load:
enabled: true #开启饥饿加载
# clients: userservice #指定饥饿加载的服务名称,写在clients后面则是只对userservice开启
clients:
- userservice # 有更多服务需要开启时则应该如下写
# - xxxxservice
重启访问第一次看看:
可以看见以及快很多了。