您的位置:首页 > 编程语言 > Java开发

Java程序为什么需要调优(《大话Java性能优化》第一章第一节)

2016-08-20 09:32 281 查看
2011年1月,新加坡飞往杭州的航班。飞行时间很长,大约6个小时,坐在四周的人很快熟悉了,互相攀谈起来。有一位小姑娘,16、7岁的摸样,长得很漂亮,默默地坐在座位上,当有热心的阿姨问起她的情况,她带着疲倦自我介绍起来,“我在新加坡念初三,那所学校一点都不好,我在成都是最好的初中毕业的,也考上了成都最好的高中,但是,我的父母,他们一定要我来新加坡复读初三,让我考新加坡的高中,我一点都不喜欢这里,这里的同学看不起我们这些大陆学生,经常上课找大陆来的老师麻烦,经常辱骂我们,我烦透了!!!”。对,这不是自我介绍,这是人接近奔溃边缘的歇斯底里。也就是在当时,我做出了决定,我绝不会让我的女儿这样远离我,一个人在很年幼的时候就必须独立面对生活的困难,绝不。不论她的父母出于什么原因让她去国外念书,我所看到的,是让一个不适合承受压力的人承担了巨大的压力,这就像本书我想要和大家讨论的话题—“性能优化”,我们不能随意地指出性能优化的方案,就像随意指派由那位小姑娘来完成全家的决定一样。我们必须经过严密的研究、测试及验证,明确真正的性能瓶颈原因后才能开始着手。
随着互联网业务的不断拓展、繁荣,越来越多的系统架构开始参照互联网+企业的系统架构方式。笔者认为,任何技术都离不开对业务需求的支撑,所以开始研究程序性能问题之前,我们需要先了解系统业务逻辑。
12306[1]这个网站一直被全国人民所诟病,它确实存在一些问题,但是这些看似简单的问题,其背后牵扯着复杂的系统架构设计,这些设计最终是为业务需求服务的,即12306的职责是为旅客的需求服务的,而我们设计的程序又是为12306服务的,所有的意识归到最终就是服务意识。我们来看一下12306的业务,12306需要支持海量并发查询,查时间、查车次、查座位、查铺位,同时,对应的下单过程也伴随着海量并发的数据库操作。据说,淘宝在双十一期间也只有几百万用户,而春运期间抢购火车票是全国人民的统一活动,瞬时访问数量有千万级别甚至是亿级别的,据说12306的高峰访问是10亿PV[2],这些访问主要集中在早8点到10点,每秒PV在高峰时上千万。
再来看看其他的业务系统,奥运会期间的奥运票务系统采用的是抽奖的方式,不存在先来先得抢购需求,由于是事后抽奖,事前只负责收集信息,所以不需要保证数据一致性,这也就没有高强度并发锁的需求,很容易通过水平扩展方式克服性能瓶颈。B2C[3]网站一般实时性要求不高,比如下单,用户提交下单后,订单并不是马上被处理的,而是等待一定时间后,用户才会收到订单是否确认的通知,这样就确保了数据不需要立即被处理,没有了数据高并发同步的需求。也就是说,在高并发要求下的数据一致性是通常情况下的性能瓶颈点,也是技术难点之一。

1.1为什么需要调优

经历了多年的发展,Java已由一门单纯的计算机编程语言,演变为一套强大的技术体系平台。根据不同的技术规范,Java设计者们将Java划分为3种结构独立但却又彼此依赖的技术体系分支,分别是Java SE、Java EE和Java ME,其中Java EE被广泛使用在企业级领域,出了包括Java API组件外,还扩充有Web组件、事务组件、分布式组件、EJB组件、消息组件等,并持续到现在。综合Java EE的这些技术,开发人员可以构建出一个具备高性能、结构严谨的企业级应用,并且JavaEE也是用于构建SOA架构的首选平台。
Java的持续发展要感谢Google,正是Google将Java作为Andriod操作系统的应用层编程语言,使得Java可以在PC时代、移动互联网时代都得到迅猛发展,可以用于手持移动设备、嵌入式设备、个人电脑、高性能的集群服务器或大型机。
前面提起过,高并发情况下的数据高度实时一致性需求是很难实现的。对于一个网站来说,并发浏览网页造成的高负载较容易处理,高并发的查询负载也可以处理,但是实时下单是最难处理的,因为下单需要访问当前的库存量,对于12306网站来说,库存量就是指火车票的库存,据说苹果CEO库克[1]正是因为处理好了库存问题才得以继任乔帮主的宝座。目前来看,很多B2C网站的下单都是通过异步方式来实现的,这样的做法可以避免数据高度一致性要求。
淘宝模式相较于传统B2C网站有一个优势,即它不需要查询库存。B2C网站拥有自己的仓库,每次下单前,都需要首先查找距离客户最近的仓库是否有库存,这样的计算量累计后会很大。试想,你在上海买一本书,如果上海附近的仓库没货,我们需要先计算哪个仓库离上海最近,又有这本书。淘宝网站由于本身商业模式的原因,它不需要去实时检查库存,反而对于性能扩展较为容易。
的确我们可以通过Nginx[2]来搞定每秒10万的静态请求,只要有足够的带宽、I/O,服务器的并发计算能力够强,可以很容易地处理并发连接数10万。但是如果我们引入了大量的业务逻辑,那就不是单纯的访问问题了,该解决方案也就成了浮云。
除了业务需求、程序运行方式之外,程序本身是由基础编程技术、系统架构、网络技术、操作系统、硬件服务器等诸多组件组成的。
计算机专家在问题求解时非常重视表达式简洁性的价值。Unix的先驱者KenThompson曾经说过非常著名的一句话:“丢弃1000行代码的那一天是我最有成效的一天之一。”这对于任何一个需要持续支持和维护的软件项目来说,都是一个当之无愧的目标。早期的Lisp贡献者Paul Graham甚至将语言的简洁性等同为语言的能力。这种对能力的认识让我们把可以编写紧凑、简介的代码作为许多现代软件项目选择语言的首要标准。
任何程序都可以通过重构,去除多余的代码或无用的占位符,如空格,变得更加简短,不过某些语言天生就善于表达,也就特别适合于简短程序的编写。APL语言的设计理念是利用特殊的图形符号让程序员用很少量的代码就可以编写功能强大的程序。这类程序如果实现得当,可以很好地映射成标准的数学表达式。简洁的语言在快速创建小脚本时非常的高效,特别是在目的不会被简洁所掩盖的简洁明确的问题域中。
相比于其他程序设计语言,Java语言的冗长已经名声在外。其主要原因是由于程序开发社区中所形成的惯例,在完成任务时,很多情况下,要更大程度地考虑描述性和控制。例如,长期来看,长变量名会让大型代码库的可读性和可维护性更强。描述性的类名通常会映射为文件名,在向已有系统中增加新功能时,会显得很清晰。如果能够一直坚持下去,描述性名称可以极大简化用于表明应用中某一特定的功能的文本搜索。这些实践让Java在大型复杂代码库的大规模实现中取得了极大的成功。
相对于传统的32位虚拟机,64位虚拟机所具备的最大优势就是可以访问大内存,32位虚拟机做的最大可用内存空间被限定在了4GB,并且Java堆区的大小如果是在Windows平台下最大只能设置到1.5GB,而在Linux平台下最大也只能设置到2GB-3GB的上限,也就是说,Java堆区的内存大小设置还需要依赖于具体的操作平台。既然32位虚拟机无法满足大内存消耗的应用场景,那么64位虚拟机的出现则是顺理成章的,64位虚拟机之所以能够访问大内存,是因为其采用了64位的指针架构,这也是寻址访问大内存的关键要素。
在JDK1.6Update14版本之前,64位虚拟机的综合性能表现实际上是不如32位虚拟机的,这主要是因为OOPS(Ordinary Object Pointers,普通对象指针)从32位膨胀到64位后,CPU Cache Line中的可用OOPS变少,这样一来就会直接影响并降低CPU的缓存使用率,这就是64位虚拟机在性能上之所以落后于32位虚拟机的主要原因。其次由于部署在64位虚拟机上的性能都需要用到大内存,尤其是互联网项目,经常需要使用多达几十乃至几百GB的内存,这对于传统的32位虚拟机将无法承载,只能依靠64位虚拟机去支撑。但是管理这么大的内存开销对于GC来说将会是一场非常严峻的考验,甚至很有可能去导致GC在执行内存回收期间消耗更长的时间,同时也意味着工作线程的等待时间将会延长。随着如今64位虚拟机的逐渐成熟,指针压缩将会通过对齐补白等操作将64位指针压缩为32位,以此改善CPU缓存使用率达到提升64位虚拟机运行性能的目的。
对于小型项目来说,简洁性则更受青睐,某些语言非常适于短脚本编写或者在命令提示符下的交互式探索编程。Java作为通用性语言,则更适用于编写跨平台的工具。在这种情况下,“冗长Java”的使用并不一定能够带来额外的价值。虽然在变量命名等方面,代码风格可以改变,不过从历史情况来看,在一些基本的层面上,与其他语言相比,完成同样的任务,Java语言仍需更多的字符。为了应对这些限制,Java语言一直在不断地更新,以包含一些通常称为“语法糖”的功能。用这些习语可以实现更少的字符表示相同功能的目标。与其对应的更加冗长的配对物相比,这些习语更受程序开发社区的欢迎,通常会被社区作为通用用法快速地采用。
现代CPU架构将多核、多硬件执行线程技术推向前台,这意味着我们可以利用更多的CPU资源做更多的工作。然而,要利用好这些额外的CPU资源,运行于其上的程序必须要能够接受并行工作要求。通俗点讲,这些程序需要按照多线程的方式构造或设计才能充分利用额外的硬件线程。
最近这几年,服务器端网络使用的基础通信技术并没有取得太大的进步。服务器端大多设在绝不允许服务中断的关键任务环境中,新技术很难渗透,也很难植根于这样的环境。但正因如此,服务器端的多余部分才得以被剔除,逐渐地形成了非常精简单纯的风格。网络的基础技术可以说已经成型了,然而在网络上运行的网络设备和服务器的技术仍然踩着现在进行时的节奏在持续不断地爆发性发展,由此出现了虚拟技术和网络存储技术等基于网络的创新技术。如今,它们已经在系统中不可或缺。随着这些技术的发展,人们追求的网络形态和网络设计的方式也在时刻发生着变化,基础架构工程师和服务器工程师必须能灵活应对这些变化才行,对应地,软件设计程序员也需要有针对性地做出应对措施。
虚拟化技术是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来。此举打破了实体结构间的不可切割的障碍,使用户可以用比原本的形态更好的方式来应用这些资源。一般所指的虚拟化资源包括计算能力和资料存储介质,这些资源的虚拟部分不受现有资源的架设方式、地域或物理形态所限制。虚拟化技术在带来成本节省和运维便利的同时,也带来了一些新的挑战,对架构师、运维人员、程序员等角色提出了新的要求。在解决了物理设施的虚拟化问题之后,我们的目光可能就会转移到应用程序本身上来,因为这才是真正为用户体现支付价值的关键所在。部署在虚拟化环境上的Java应用与物理环境上的应用存在明显的区别。
综上所述,性能优化本身对于程序性能是至关重要的,同时性能优化也是一门综合性课程,虽然本书针对的是Java程序的性能优化,但是依然需要考虑综合性因素。作者认为,随着IT技术的蓬勃、快速发展,性能调优已经不单纯是代码级别的调优,它是一个对综合性知识的深入理解需求,我们只有结合多方面的技术才能真正找到合理的解决方案。这也是本书除了深入介绍Java程序调优、JVM调优等之外,坚持引入服务器、网络、云计算、虚拟化等多维技术点的原因。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息