上一小节大家手把手创建了一个Ribbon消费者,顺带初步了解了LoadBalancer,这一节将带大家看一个LoadBalancer的加载问题。
上课前我们先复习一下程序猿三大定理,这节课将围绕定理三展开
- 其它程序员都是傻X
- 别人写的代码都跟shit一样
- 一定是你的环境问题
一定是环境问题
就比如程序员定理三,老师每天都要靠这条定理指导工作:
测试妹子:老师你写的接口怎么又timeout了?报个bug先
半仙老师:一定是你机器问题,在我机器上就没有问题
测试妹子:可是我换了台机子,一启动还是超时啊
半仙老师:这肯定是环境问题唉,肯定你配置不对
测试妹子:可是所有配置都一样啊?
半仙老师:这种随机问题不可能是代码问题,本地又不能重现,以后碰到保留现场再来找我。
就这样,一个疑似的bug就这么被放过了,这到底是不是个问题呢?Ribbon的“环境问题”?
有时候身边被女人环绕也是一件麻烦事,最近越来越多的测试妹子围着我报同样的问题“老师你接口超时了,可过会儿又好了”。我对自己产生了深深地怀疑,难道,真的是我代码问题?
凭着老法师的经验,本地无法重现,那就去服务器log里寻找蛛丝马迹。不巧还真被我找到这么一条疑似异常,在超时请求之前有这么一条log: ```shell INFO [main] com.netflix.loadbalancer.DynamicServerListLoadBalancer - DynamicServerListLoadBalancer for client eureka-consumer initialized
这行log意思是,Ribbon客户端已经完成了LoadBalancer的初始化。初始化是没问题的,但问题是初始化发生的时间,为什么偏偏发生在首次超时之前呢?<br />这就要从Ribbon的懒加载说起了,原来Ribbon是在第一次方法调用的时候才去初始化LoadBalancer。这样看来,第一个方法请求不仅仅包含HTTP连接和方法的响应时间,还包括了LoadBalancer的创建耗时。假如你的方法本身就比较耗时的话,而且超时时间又设置的比较短,那么很大可能这第一次http调用就会失败。其实还有很多框架也实现了类似的懒加载功能,比如Hibernate的lazy-fetch,懒加载在大部分情况下可以节省系统资源开销,但某些情况下反而导致服务响应时间被延长。<br />之所以这类问题难以发现的原因,在于它无法稳定重现,比如只能通过重启来重现,对这种问题往往直接从生产环境的log入手去分析是比较有效的手段。
<a name="eqCLd"></a>
### 番外篇
在生产环境里log是很重要的,十多年前没有好的log搜索工具,线上排查问题时甚至要把好几G的log专门上传到特殊的机器做搜索。因此为了避免这种繁琐的线上排错体验,那个年代的程序员都练就了一套肉眼编译器的功夫,又叫人肉代码走查。
<a name="FR5Cv"></a>
## 怎么让Ribbon勤快起来
既然LoadBalancer首次加载发生在第一次调用的时候,那么我们让Ribbon在调用以前就初始化好了。接下来我们就开启Ribbon的狂暴模式-饥饿加载
```shell
ribbon.eager-load.enabled=true
ribbon.eager-load.clients=ribbon-consumer
第一个参数开启了Ribbon的饥饿加载模式,第二个属性指定了需要应用饥饿加载的服务名称。完成上面配置并再次重启服务,就会发现LoadBalancer初始化日志在方法调用之前就打印出来了。
小结
大家在实际开发中,一定要秉承“机器是不会出错的”这个观点,所有所谓的环境问题,或者偶然不可重现的问题,必定都有一个导致问题的根本原因。就像有很多超自然现象无法用现有的人类科学解释,如果你的技术积累没有到一定程度,这类“环境问题”对自己来说就是一个玄学。大家以后工作中肯定还会遇到很多这类问题,不要做“懒加载”,我们要勤快的刨根问底把问题解决掉,解决别人无法解决的问题,这就是使你从团队中脱颖而出的有效途径。
刚才我们深入探讨了程序猿第三定理,学习了Ribbon的懒加载和饥饿加载。下一小节将带大家去领略Ribbon最强大的功能,负载均衡策略!