相信很多朋友都在本身公司使用Spring Cloud框架来构建微服务架构,毕竟如今这是很是火的一门技术。java
若是只是用户量不多的传统IT系统,使用Spring Cloud可能还暴露不出什么问题。程序员
若是是较多用户量,高峰每秒高达上万并发请求的互联网公司的系统,使用Spring Cloud技术就有一些问题须要注意了。面试
先不空聊原理、理论,来说一个真实的例子,这是个人一个朋友在创业互联网公司发生过的真实案例。redis
朋友A的公司作互联网类的创业,组建了一个小型研发团队,上来就用了Spring Cloud技术栈来构建微服务架构的系统。数据库
一段时间没日没夜的加班,好不容易核心业务系统给作出来了,平时正常QA测试没发现什么大毛病,感受性能还不错,一切都很完美。缓存
而后系统就这么上线了,一开始用户规模很小,注册用户量小几十万,日活几千用户。服务器
天天都有新的数据进入数据库的表中,就这么日积月累的,没想到数据规模竟然慢慢吞吞增加到了单表几百万。网络
这个时候呢,看起来也没太大的毛病,就是有用户反映,系统有些操做,会感受卡顿几秒钟,会刷不出来页面。数据结构
这是为啥呢?架构
若是你们对微服务框架有点了解的话,应该知道,好比Feign + Ribbon组成的服务调用框架,是有接口调用超时这一说的,有一些参数能够设置接口调用的超时时间。
若是你调用一个接口,好几秒刷不出来,人家就超时异常返回,用户就刷不出来页面了。
通常碰到这种事情,一大坨屎同样的SQL摆在那儿,写SQL的人过一个月本身都看不懂了,80%的工程师看着都不肯意去花时间重写和优化。
一是修改的人力成本过高,二是谁敢负担这责任呢?
系统跑的好好的,就是慢了点而已,结果你硬是乱改一通,重构,把系统核心业务流程搞挂了怎么办?
因此,那些兄弟第一反应是:增长超时时间啊!接口慢点能够,可是别超时不响应啊!
我们让接口执行个几秒把结果返回,用户不就能够刷出来页面了!不用重构系统了啊!轻松+愉快!
如何增长呢?很简单,看下面的参数就知道了:
你们应该知道,Spring Cloud里通常会用hystrix的线程池来执行接口调用的请求。
因此设置超时通常设置两个地方,feign和ribbon那块的超时,还有hystrix那块的超时。其中后者那块的超时通常必须大于前者。
Spring Cloud玩儿的好的兄弟,可千万别看着这些配置发笑,由于我确实见过很多Spring Cloud玩儿的没那么溜的哥们,真的就这么干了。
好了,日子在继续。。。
优化了参数后,看上去效果不错,用户虽然以为有的页面慢是慢点,可是起码过几秒能刷出来。
这个时候,日活几千的用户量,压根儿没什么并发可言,高峰期每秒最多一二十并发请求罢了。
你们看看下面这张图,感觉一下现场氛围:
随着时间的推移,公司业务高速发展……
那位兄弟的公司,在系统打磨成熟,几万用户试点都ok以后,老板立马拿到一轮几千万的融资。
公司上上下下意气风发啊!紧接着就是组建运营团队,地推团队,全国大范围的推广。
总之就是三个字:推!推!推!
这一推不打紧!研发人员在后台系统发现,本身的用户量蹭蹭蹭的直线增加。
注册用户增加了几十倍,突破了千万级别,日活用户也翻了几十倍,在活动之类的高峰期,竟然达到了上百万的日活用户量!
幸福的烦恼。。。
为何这么说?由于用户量上来后,悲剧的事情就发生了。
高峰期每秒的并发请求竟然达到了近万的程度,研发团队的兄弟们哪里敢怠慢!在这个过程当中,先是紧张的各类扩容服务,一台变两台,两台变四台。
而后数据库主从架构挂上去,读写分离是必须的,不然单个数据库服务器哪能承载那么大的请求!多搞几个从库,扛一下大量的读请求,这样基本就扛住了。
正准备坐下来喝口茶、松口气,更加悲剧的事情就发生了。
在这个过程当中,那些兄弟常常会发现高峰期,系统的某个功能页面,忽然就整个hang死了,就是无法再响应任何请求!全部用户刷新这个页面所有都是没法响应!
这是为何呢?缘由很简单啊!一个服务A的实例里,专门调用服务B的那个线程池里的线程,总共可能就几十个。每一个线程调用服务B都会卡住5秒钟。
那若是每秒钟过来几百个请求这个服务实例呢?一会儿那个线程池里的线程就所有hang死了,无法再响应任何请求了。
你们来看看下面这张图,再直观的感觉一下这个无助的过程!
这个时候咋办?兄弟们只能祭出程序员最古老的法宝,重启机器!
遇到页面刷不出来,只能重启机器,至关于短暂的初始化了一下机器内的资源。
而后接着运行一段时间,又卡死,再次重启!真是使人崩溃啊!用户们的体验是极差的,老板的心情是愤怒的!
画外音:
其实这个问题自己不大,但若是对Spring Cloud没有高并发场景的真实经验,确实可能会跟这帮兄弟同样,搞出些莫名其妙的问题。
好比这个公司,明明应该去优化服务接口性能,结果硬是调大了超时时间。结果致使并发量高了,对那个服务的调用直接hang死,系统的核心页面刷不出来,影响用户体验了,这怪谁呢?
无法子了,那帮兄弟们只能找人求助。下面就是做者全程指导他们完成系统优化的过程。
第一步
关键点,优化图中核心服务B的性能。互联网公司,核心业务逻辑,面向C端用户高并发的请求,不要用上百行的大SQL,多表关联,那样单表几百万行数据量的话,会致使一下执行好几秒。
其实最佳的方式,就是对数据库就执行简单的单表查询和更新,而后复杂的业务逻辑所有放在java系统中来执行,好比一些关联,或者是计算之类的工做。
这一步干完了以后,那个核心服务B的响应速度就已经优化成几十毫秒了,是否是很开心?从几秒变成了几十毫秒!
第二步
那个超时的时间,也就是上面那段ribbon和hystrix的超时时间设置。
奉劝各位同窗,不要由于系统接口的性能过差而懒惰,搞成几秒甚至几十秒的超时,通常超时定义在1秒之内,是比较通用以及合理的。
为何这么说?
由于一个接口,理论的最佳响应速度应该在200ms之内,或者慢点的接口就几百毫秒。
若是一个接口响应时间达到1秒+,建议考虑用缓存、索引、NoSQL等各类你能想到的技术手段,优化一下性能。
不然你要是胡乱设置超时时间是几秒,甚至几十秒,万一下游服务偶然出了点问题响应时间长了点呢?那你这个线程池里的线程立马所有卡死!
这两步解决以后,其实系统表现就正常了,核心服务B响应速度很快,并且超时时间也在1秒之内,不会出现hystrix线程池频繁卡死的状况了。
第三步
事儿还没完,你要真以为两步就搞定了,那仍是经验不足。
若是你要是超时时间设置成了1秒,若是就是由于偶然发生的网络抖动,致使接口某次调用就是在1.5秒呢?这个是常常发生的,由于网络的问题,接口调用偶然超时。
因此此时配合着超时时间,通常都会设置一个合理的重试,以下所示:
设置这段重试以后,Spring Cloud中的Feign + Ribbon的组合,在进行服务调用的时候,若是发现某台机器超时请求失败,会自动重试这台机器,若是仍是不行会换另一台机器重试。
这样因为偶尔的网络请求形成的超时,不也能够经过自动重试避免了?
第四步
其实事儿还没完,若是把重试参数配置了,结果你竟然就放手了,那仍是没对人家负责任啊!
你的系统架构中,只要涉及到了重试,那么必须上接口的幂等性保障机制。
不然的话,试想一下,你要是对一个接口重试了好几回,结果人家重复插入了多条数据,该怎么办呢?
其实幂等性保证自己并不复杂,根据业务来,常见的方案:
相似这样的方案还有一些。总之,要保证一个接口被屡次调用的时候,不能插入重复的数据。
有图有真相!老规矩,最后给你们上一张图,最终优化后的系统表现大概是长下面这样子的。
若有收获,请帮忙转发,点个关注。您的鼓励是做者最大的动力,谢谢!
分享一份面试宝典《Java核心知识点整理.pdf》“,覆盖了JVM、锁、高并发、反射、Spring原理、微服务、Zookeeper、数据库、数据结构等等”,还有Java208道面试题(含答案)加入群(Java填坑之路)659655594 便可免费获取到!