如何优化系统以及提升系统稳定性(java)

        最近几个月花了很大精力稳定性以及优化上面,打算继续写一下如何提升稳定性和系统调优。中间有一些是参照公司一些大牛的PPT,有一些是自己的思考和实践。可能不会涉及到具体的细节,但是优化过程中的思路基本都会涉及到。

       

         性能调优一般的思路是什么?

        这里其实在最开始想做优化的时候,也是摸不着头脑,但是想了下,其实性能调优,首先要找到瓶颈在哪里?然后针对瓶颈做优化,再压测看结果,后面具体做的过程也就是这样来的。所以分为三步:一、需找性能瓶颈,二、针对瓶颈做优化,三、压测看优化的效果,逐步迭代,最终达到性能的要求。

 

        性能的要求是啥?

        这个主要看制定的性能基线是啥,例如需要的单机QPS和RT是多少。之后基于这个目标,把系统的吞吐量和响应时间搞上来。这时候可能需要一个性能模型,也可以理解为系统水位评估,即通过一系列的数字,描述目前系统的水位是多少,极限的情况下,能够承受的压力是多少。这个过程可能更多的是非技术性的。但是这步非常重要。

 

        哪有那些压测方式?

        其实不要被压测吓住了。自己写一个多线程压测接口或者方法也是压测,也可以发现瓶颈。

        一、单机多线程压测,这里可以使用自己搞的线程池,压接口看看QPS和RT的情况(这时候再配合本地的visualvm来看一些热点的方法等);

        二、如果是web请求,可以尝试使用ab或者httpload的方式制造压力;(http://iamzhongyong.iteye.com/blog/1757180 单元测试压测和工具的使用)

        三、线上能不能压测?答案肯定是可以的,目前两种思路,一种是复制线上请求到另外一台机器(例如tcpcopy可以实现这种复制),一种是请求转发,把请求转发到特定的机器上,这两种方式各有利弊,目前这两种都有尝试。线程压测的好处是能够反映真实的情况,真实的数据,真实的业务模型,比较客观。

        四、线下搭建系统,这个系统可能包含了你这个系统所依赖的所有系统了,然后在线下制造数据,模拟请求(例如loadrunner等工具),好处是不干扰线上的正常使用,坏处是造数据的成本有点高,且和线上真实的业务模型有出入。

        五、线上全链路压测,从入口的系统开始,把这个业务涉及到的核心系统,全部覆盖,在最前端来模拟用户的请求,然后制造压力。这种方式好处是非常可观,能够反映真实的情况,确实是成本很高。

 

        如果寻找系统的依赖情况?

        应用系统一般依赖的资源会比较多,例如数据库,例如缓存系统,例如其他应用系统,这时候有个问题,如何识别他们呢?可能你的第一反应是看代码,但是其实业务系统一般非常复杂,看代码会搞死人的。这时候其实一个链路分析的系统不可少,说说简单,一个链路的分析系统还是很有难度的。一般是基于系统的调用日志以及一些端口等去做的分析,基于系统自己留下的数据,把系统的依赖搞出来。例如Google Dapper、Twitter Zipkin。在最前端的请求中,设置一个流水号ID,然后把这个ID传递到后端依赖的系统中,然后打日志,之后分析日志,然后把依赖的数据统计出来。基于这个依赖情况,能够很客观的反应系统的情况。

 

        超时时间的设置?

        这里可能觉得这个事情太小了,但是实际上有很多超时时间设置不合理导致的血的教训。如果超时时间不做评估,核心的调用依赖在出现问题的时候,可能会出现连锁反应。具体的数值设置,取决于业务的情况以及依赖的要求,如果不知道设置多少,设置3秒即可。

 

        为什么说可能最多的是业务逻辑调优?

        在最开始优化的时候,我也想通过调整一个JVM的参数来提升1倍的性能,或者升级一下linux的内核来提升。但是实际上,大多数的优化还是业务逻辑的优化。例如业务逻辑的调用顺序,以及是否有多余的调用,是否有多余的循环,是否有一些调用可以简化的。这些都要具体问题具体分析。但是,重点觉得一定在这里。

 

        服务器如果做到更加简单和单一?

        这里提一个概念就是服务治理,可能服务治理是一个很大的话题,目前我也是处于一个很菜的阶段,这里就提一个“服务隔离”,一个系统A可能同时提供了web的请求和接口的请求,一般情况下每台机器都会承载web和接口的请求,这时候就没有办法单一了,可能稳定性方面不符合我们的期望。怎么做呢?把不同的请求做隔离。例如专门搞几台机器来承载所有的web请求,单独搞几台机器承载接口的请求,做好分组和隔离。这样就能保证机器做的事情更加单一。简单了,也自然就减少了一些问题隐患。

 

        多个机房的情况下本地调用优先?

        A应用系统调用B应用系统,A的机器分布在F1、F2、F3机房中,B集群的也分布在F1、F2、F3机房中,这时候如果A和B的调用,出现扩机房的情况,就会比同机房调用有更大的开销,所以,可以采用本地调用优先的策略,既A集群中F2机房的机器调用B集群,仅仅会调用F2的机房,这样能够很好的减少网络开销。当然也有坑了,例如A集群中F2机器承载了80%的请求,B集群仅仅有50%,这时候就有隐患了。

 

        每次请求都动态渲染页面,这种情况咋搞?

        答案很简单“页面静态化”,具体的静态化方案比较多,例如页面的元素放入CDN中,或者放入到分布式缓存中,放到这些地方之后,获取非常快,要远远好于每次都去做页面的渲染。但是同时也要考虑缓存的清理问题。

 

        如果做系统的过载保护?

        java系统发展到现在,过载保护已经研究的比较多了,这里就不多说了,之前的两篇文章列在这里。http://iamzhongyong.iteye.com/blog/1742829 , http://iamzhongyong.iteye.com/blog/1982113

 

        如果做业务的平滑降级?

        业务模块,可能包含多个功能,在系统出现问题的时候,例如无法再做多余的业务计算,仅仅需要保留核心业务,这时候咋办?开关关掉。比较常见的办法就是在java系统中搞个单例,然后通过外部的请求修改这个开关。http://iamzhongyong.iteye.com/blog/1897694 这里文章有个介绍。

 

        异步化改造如何做?

        目前的互联网架构,其实是离不开异步化的,异步,就是不阻塞当前的请求。例如我在用户登录之后,需要把用户的积分加一下,这步没有必要阻塞用户的登录过程,完全可以异步去做,如果做异步呢?我总结的几个思路:

        一、利用线程池去做,在主线程中做核心的业务逻辑,多余的可以异步去做的,可以把任务放入线程池,由线程池自行去做;

        二、利用协程等工具做异步,当然目前java的协程还不是很成熟(http://iamzhongyong.iteye.com/blog/1916740);

        三、再就是结合目前的消息系统,在做异步的地方,发消息,然后另外一个地方接收这个消息,做处理,实现异步;

 

        至此,over,可能大多数的都是思路,每一点做起来其实都不是很容易。优化和稳定,更多的在于细节,魔鬼在细节啊。

 

 

猜你喜欢

转载自iamzhongyong.iteye.com/blog/1991103