ImageVerifierCode 换一换
格式:DOCX , 页数:23 ,大小:35.94KB ,
资源ID:2871792      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/2871792.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Java 应用 优化手记.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Java 应用 优化手记.docx

1、Java 应用 优化手记现在单台服务器tps可以支撑到1000并发,前端和后端压力基本平衡。根据经验和不停的测试获得的,可能有不准确的地方,并不适用于所有java应用。1 java优化仅仅是一些设计经验和编程技巧。1.1 Hibernatelsmp对数据库操作采用hibernate封装对象。但是hibernate会在后台做一些我们不知道事情。hibernate有自己的cache机制,二级缓存需要配置默认不开启,一级缓存(查询缓存)是默认开启的,原来使用hibernate多数是查询oracle,因为是访问的介质是磁盘,所以hibernate的查询缓存可以起到提升查询速度的效果,但是lsmp使用的

2、是timesten内存型数据库,访问速度比oracle要快的多,所以可以关闭hibernate查询缓存。1.1.1 hibernate封装对象测试时发现,程序设计时hibernate映射对象会关联其它表,比如用户表关联了用户详细信息表,这样做的好处是方便我们查询对象,里面已经封装了我们需要的所有信息,但如果我们不需要关联的信息呢?在查询时hibernate会自动将关联查询一起封装为sql语句,这样等于做了2次select操作,影响查询效率。在低负载的情况下不明显,随着压力的增加会越来越明显。解决办法:删除映射关联或将关联设置为延迟加载。在开发的时候对于数据库的访问应该有明确的需求分析。1.1.

3、2 createQuery与createNativeQuery这个问题暂时还没有明确,当hibernate使用createQuery时查询效率就会越来越低,使用createNativeQuery时就不会下降,初步判断为:hibernate更新自己的查询缓存影响了查询速度,依据是查询不同的信息时,速度越查越慢,但是查询刚才已经查询过的数据,速度是恒定的。createNativeQuery需要自己封装sql语句,返回的也是基础数据类型或许没有经过hibernate的一级缓存。当然这些只是猜测。1.2 ConcurrentHashMapConcurrentHashMap是Java 5中支持高并发、高

4、吞吐量的线程安全HashMap实现。按照java官方的解释,ConcurrentHashMap是由线程并发专家编写的专门用于高并发情况下的Map。ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。lsmp使用ConcurrentHashMap作为cache,每次购彩操作中,都会先将购彩对象存入cache中,再

5、发送给生产系统落单,当每张彩票从生产系统正确落单返回给business后,再到cache中找到刚才的彩票对象,完成后面的购彩操作,将对象从cache中删除。由于存在超时问题,就起了一个线程定时扫描cache,每次扫描都会遍历整个cache,将彩票对象的生命周期减一(int型数据),当减到0时,此彩票对象超时;也就是说每次定时任务都会将cache中所有对象操作一遍,要么减少生命周期操作,要么超时操作。但是测试时发现在高并发下,经常会出现cache中数据丢失数据的问题,症状为:在压力测试进行10分钟左右,开始出现购彩信息从生产系统正常落单回来后,在cache中找不到对应的彩票对象,造成购彩失败的情

6、况。低压力情况下也会发生这个问题但错误少,压力越高出错的数据就越多。经过分析怀疑是cache操作过于频繁造成的,每次定时任务都会对cache中所有数据进行全量更新操作,并且购彩操作还在进行,购彩完成操作也在进行,长时间高并发的进行get操作的同时进行put+remove操作,ConcurrentHashMap的锁控制机制失效了。根据上面的分析对代码进行了修改,将彩票对象的生命周期从int修改为long(System.currentTimeMillis()),每次定时任务处理cache时(10秒一次),只是将彩票对象从cache中get出来,然后与系统当前时间(System.currentTim

7、eMillis())进行减法操作,查看结果是否大于或等于设置的超时时间,如果没有超时则遍历下一条。这时对于cache中的数据只进行get操作并没有改变对象的内容,优化代码之前这里每次都要将生命周期减一然后再重新put到cache中,get不影响锁控制的,只有发现超时的对象才进行remove,cache的访问压力变小了;但是购彩成功的彩票后依然会实时对cache进行remove操作,cache依然长时间处于put+remover操作,错误数量虽然下降了但并没有消失。再次优化代码,完成购彩成功后只将cache中彩票对象的状态标志位改为“购彩完成”,不实时删除cache中的数据;修改定时任务增加“判

8、断彩票状态”功能,当定时任务遍历cache时,会判断当前彩票对象“是否超时”+“是否已经完成购彩”,如果都不是则遍历下一条,如果超时或已完成购彩则从cache中remove。也就是说定时任务执行时彩票对象 从cache中统一remove。这样对于cache的访问就变为:一直进行put操作,购彩成功后修改状态位重新put回cache,这时cache中的数据只增加没减少,并且cache中的对象不会发生并发访问(因为彩票号都是唯一的);当定时任务执行时(10秒一次)才集中进行remove操作,并且将remove被定义为synchronized。定时任务的间隔时间比较长(10秒一次),所以不会导致Co

9、ncurrentHashMap的锁控制机制失效的问题。再次测试后发现,每次定时任务执行时,cache的性能会大幅下降,所以果断的去掉了remove的synchronized,但是确保代码中只有一个地方可以对cache进行remove操作,入口也是唯一的(单例模式)。测试结果:在tps:900的情况下运行8小时,全部成功,无失败记录。定时任务可以在3秒内完成整个任务(quartz启动任务+rmi发送接收消息+cache遍历)。对于高并发cache操作的一些总结:1. cache是放在内存中的,速度快易丢失,会对提高编码难度,特别是高并发下,管理不好会造出数据不同步,所以再使用之前先考虑清楚:“你

10、确定有必要使用cache吗?如果确定要用那么cache要承受多大的压力?如何解决数据不同步的问题?”2. 对于cache中的对象,能少修改就少修改,能不修改就不修改。3. 对于ConcurrentHashMap来说get操作不影响锁,可以放心并发使用。4. 对于生命周期来说,时间戳比递减数值的好用,它不需要频繁修改cache中对象的内容,缺点是精度不够,可以通过增加定时任务的执行频率来提高精度。5. 尽量避免长时间对cache进行put+remove操作,如果实在避免不了,就将其中一个改为批量操作。6. 在高并发下ConcurrentHashMap确实比HashMap好,用HashMap测试时

11、购彩数据错的一塌糊涂。但是ConcurrentHashMap的系统开销比HashMap大不少。7. 专用的cache比ConcurrentHashMap好用。1.3 session超时session管理是web开发中很重要的一环,我们将session放入容器,到了超时时间,web server会自动删除,也可以手动删除,一般情况下开发人员会在用户退出时调用删除session代码,但是如果用户没有点击退出,只是关闭了浏览器,那只能等到session超时了,小网站一般不会有问题,但网站访问量非常大呢?session必须要用,那么是不是可以只往里放必要的东西,毕竟内存是有限的。如果一定要放很多东西,

12、能不能压缩下内容再放进去,办法其实很多。同理我们在编程的时候有没有把各种极限情况都考虑进去呢?就像 Doug Linder说的:“一个好的程序员应该是那种过单行线都要往两边看的人。”1.4 对象生存周期编程时很多程序员习惯于先把要用到的对象声明出来,然后再写逻辑,这个习惯不错,不过java对于每个new出来的对象,都会分配内存空间并且消耗部分cpu资源。我走查代码时,发现不少童靴new出对象放在那里,执行了好几行代码后(其中包括查询数据库这样比较耗时的操作),才用到这个对象,期间java是不会回收这个对象的,因为它的生命周期还没到,内存在这段时间被浪费了,当然在一个毫秒内浪费几十个字节的内存无

13、所谓,不过如果这个方法在一秒钟内被调用了几百万次呢?1.5 流水线现在的cpu架构是按流水线执行的,比如执行for循环,for里面的代码会编译为一个顺序的流水线执行,如果在for循环中加入一条System.out语句,System.out要输出信息并且不属于流水线,因为System.out需要jdk调用操作系统的IO接口,破坏了流水线操作,cpu会将流水线的指令集按顺序一条条压入堆栈(先进后出),等IO完毕后在从堆栈中顺序读取指令恢复流水线操作。我因为测试需要,在购彩代码中加入了一句System.out测试语句,结果忘了删除,在极限压力测试下,后台报了大量线程处于blocked状态(线程阻塞)

14、,而这些线程都指向这条System.out语句;删除这条语句后再测试系统正常,压测1小时内没发现有blocked的线程。所以我比别人更痛恨在svn上看到System.out。1.6 高低搭配编程时经常碰到速度不匹配的代码,比如短信接口,发短信的速度慢,如果把这个接口放到购彩这样要求并发很高的代码中,就会造出极大的性能降低,这时有两个方法,第一修改短信接口,使之处理速度达到或接近购彩接口的速度(这几乎不可能);第二就需要将短信接口改为异步,购彩不再依赖短信回执信息。1.7 方法间相互调用我们天天写各种方法、接口;调用别人给我们的各种方法、接口,但是很少有人说方法之间的调用也是耗时的,虽然耗时极短

15、,但确实是消耗了的,当然这不能说我们把所有操作都要写在一个方法内,必要的结构有利于开发和维护,但是方法和接口泛滥不是一个好习惯,从中找到一个平衡不是一件容易的事情。1.8 伊格尔森定律你自己的代码如果超过6个月不看,再看的时候和别人写的一样。1.9 调试Edsger W. Dijkstra说过:“如果调试是除虫的过程,那么编程就一定是把臭虫放进来的过程”。我发现很多童靴总想着开发新东西和热衷于用新技术,但很少人喜欢去调试代码,我说的调试不是像测试人员那样按照步骤一个一个功能点测试,而是更接近于白盒测试,必要时要修改bug保证测试可以顺利完成。这项工作是十分枯燥的;调试是烦人的、苦恼的;被各种b

16、ug轮来轮去、被各种低级错误气得直揪头发,但是你却可以在调试中发现很多东西、学到很多东西,别人的思想,自己的思想。可以说没有比调试代码更能提高程序员水平的方法了。特别是再有性能要求的时候,比如这段代码要求并发达到1000,但是程序执行没有错误,就是速度上不去,怎么办?找问题呗,哪里是瓶颈?测试日志语句到底打在哪一行?往上一行和往下一行会给测试日志带来什么改变?哪里可以处理的再快一点?哪里的代码质量不高?你要一步一步去分析、去测试。如果这样你的水平还不能提高,那我也没什么好说的了。Brain W.Kernighan说过:“调试代码的难度是首次编写这些代码的两倍,因此,如果你在编写代码的时候就已经发挥了全部的聪明才智,那么按照常理,你将无法凭借自己的智慧去调试这些代码。”所以如果你能调试出比现有代码更牛叉的代码,只能说明你比写代码的人更加牛叉!(个人观点)2 OS优化现在使用的是64位linux,li

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1