- 浏览: 70649 次
- 性别:
- 来自: 武汉
最新评论
-
spring_springmvc:
spring mvc demo教程源代码下载,地址:http: ...
springmvc -
mrhuangok:
文章条理清晰,帮了我大忙。
springmvc -
kunsyliu:
...
get加密 -
JeffreyJia:
为什么使用JMS 就必须使用 MDB呢?没有必要吧?
基于Spring打造简单高效通用的异步任务处理系统
大家看看,我觉得写的挺好。
http://www.linuxeden.com/html/news/20120621/126133.html
关于性能优化这是一个比较大的话题,在《由12306.cn 谈谈网站性能技术 》中我从业务和设计上说过一些可用的技术以及那些技术的优缺点,今天,想从一些技术细节上谈谈性能优化,主要是一些代码级别的技术和方法。本文的东西是我的一些经验和知识,并不一定全对,希望大家指正和补充。
在开始这篇文章之前,大家可以移步去看一下酷壳以前发表的《代码优化概要 》,这篇文章基本上告诉你——要进行优化,先得找到性能瓶颈! 但是在讲如何定位系统性能瓶劲之前,请让我讲一下系统性能的定义和测试,因为没有这两件事,后面的定位和优化无从谈起。
一、系统性能定义
让我们先来说说如何什么是系统性能。这个定义非常关键,如果我们不清楚什么是系统性能,那么我们将无法定位之。我见过很多朋友会觉得这很容易,但是 仔细一问,其实他们并没有一个比较系统的方法,所以,在这里我想告诉大家如何系统地来定位性能。 总体来说,系统性能就是两个事:
- Throughput ,吞吐量。也就是每秒钟可以处理的请求数,任务数。
- Latency , 系统延迟。也就是系统在处理一个请求或一个任务时的延迟。
一般来说,一个系统的性能受到这两个条件的约束,缺一不可。比如,我的系统可以顶得住一百万的并发,但是系统的延迟是2 分钟以上,那么,这个一百万 的负载毫无意义。系统延迟很短,但是吞吐量很低,同样没有意义。所以,一个好的系统的性能测试必然受到这两个条件的同时作用。 有经验的朋友一定知道,这两个东西的一些关系:
- Throughput 越大, Latency 会越差。因为请求量过大,系统太繁忙,所以响应速度自然会低。
- Latency 越好,能支持的 Throughput 就会越高。因为 Latency 短说明处理速度快,于是就可以处理更多的请求。
二、系统性能测试
经过上述的说明,我们知道要测试系统的性能,需要我们收集系统的Throughput 和Latency 这两个值。
- 首先,需要定义 Latency 这个值,比如说,对于网站系统响应时间必需是 5 秒以内(对于某些实时系统可能需要定义的更短,比如 5ms 以内,这个更根据不同的业务来定义)
- 其次,开发性能测试工具,一个工具用来制造高强度的 Throughput ,另一个工具用来测量 Latency 。对于第一个工具,你可以参考一下 “十个免费的 Web压力测试工具 ” , 关于如何测量 Latency ,你可以在代码中测量,但是这样会影响程序的执行,而且只能测试到程序内部的 Latency ,真正的 Latency 是整个系统 都算上,包括操作系统和网络的延时,你可以使用 Wireshark 来抓网络包来测量。这两个工具具体怎么做,这个还请大家自己思考去了。
- 最后,开始性能测试。你需要不断地提升测试的 Throughput ,然后观察系统的负载情况,如果系统顶得住,那就观察 Latency 的值。这样,你就可以找到系统的最大负载,并且你可以知道系统的响应延时是多少。
再多说一些,
- 关于 Latency ,如果吞吐量很少,这个值估计会非常稳定,当吞吐量越来越大时,系统的 Latency 会出现非常剧烈的抖动,所以,我 们在测量 Latency 的时候,我们需要注意到 Latency 的分布,也就是说,有百分之几的在我们允许的范围,有百分之几的超出了,有百分之几的完全不 可接受。也许,平均下来的 Latency 达标了,但是其中仅有 50% 的达到了我们可接受的范围。那也没有意义。
- 关于性能测试,我们还需要定义一个时间段。比如:在某个吞吐量上持续 15 分钟。因为当负载到达的时候,系统会变得不稳定,当过了一两分钟 后,系统才会稳定。另外,也有可能是,你的系统在这个负载下前几分钟还表现正常,然后就不稳定了,甚至垮了。所以,需要这么一段时间。这个值,我们叫做峰 值极限。
- 性能测试还需要做 Soak Test ,也就是在某个吞吐量下,系统可以持续跑一周甚至更长。这个值,我们叫做系统的正常运行的负载极限。
性能测试有很多很复要的东西,比如:burst test 等。 这里不能一一详述,这里只说了一些和性能调优相关的东西。总之,性能测试是一细活和累活。
三、定位性能瓶颈
有了上面的铺垫,我们就可以测试到到系统的性能了,再调优之前,我们先来说说如何找到性能的瓶颈。我见过很多朋友会觉得这很容易,但是仔细一问,其实他们并没有一个比较系统的方法。
3.1 )查看操作系统负载
首先,当我们系统有问题的时候,我们不要急于去调查我们代码,这个毫无意义。我们首要需要看的是操作系统的报告。看看操作系统的CPU 利用率,看看 内存使用率,看看操作系统的IO ,还有网络的IO ,网络链接数,等等。Windows 下的perfmon 是一个很不错的工具,Linux 下也有很多相关的 命令和工具,比如:SystemTap ,LatencyTOP ,vmstat, sar, iostat, top, tcpdump 等等 。通过观察这些数据,我们就可以知道我们的软件的性能基本上出在哪里。比如:
1 )先看CPU 利用率,如果CPU 利用率不高,但是系统的Throughput 和Latency 上不去了,这说明我们的程序并没有忙于计算,而是忙 于别的一些事,比如IO 。(另外,CPU 的利用率还要看内核态的和用户态的,内核态的一上去了,整个系统的性能就下来了。而对于多核CPU 来说,CPU 0 是相当关键的,如果CPU 0 的负载高,那么会影响其它核的性能,因为CPU 各核间是需要有调度的,这靠CPU0 完成)
2 )然后,我们可以看一下IO 大不大,IO 和CPU 一般是反着来的,CPU 利用率高则IO 不大,IO 大则CPU 就小。关于IO ,我们要看三个事,一个是磁盘文件IO ,一个是驱动程序的IO (如:网卡),一个是内存换页率。这三个事都会影响系统性能。
3 )然后,查看一下网络带宽使用情况,在Linux 下,你可以使用iftop, iptraf, ntop, tcpdump 这些命令来查看。或是用Wireshark 来查看。
4 )如果CPU 不高,IO 不高,内存使用不高,网络带宽使用不高。但是系统的性能上不去。这说明你的程序有问题,比如,你的程序被阻塞了。可能是因为等那个锁,可能是因为等某个资源,或者是在切换上下文。
通过了解操作系统的性能,我们才知道性能的问题,比如:带宽不够,内存不够,TCP 缓冲区不够,等等,很多时候,不需要调整程序的,只需要调整一下硬件或操作系统的配置就可以了。
3.2 )使用Profiler 测试
接下来,我们需要使用性能检测工具,也就是使用某个Profiler 来差看一下我们程序的运行性能。如:Java 的JProfiler/TPTP /CodePro Profiler ,GNU 的gprof ,IBM 的PurifyPlus ,Intel 的VTune ,AMD 的CodeAnalyst ,还有Linux 下的 OProfile/perf ,后面两个可以让你对你的代码优化到CPU 的微指令级别,如果你关心CPU 的L1/L2 的缓存调优,那么你需要考虑一下使用 VTune 。 使用这些Profiler 工具,可以让你程序中各个模块函数甚至指令的很多东西,如:运行的时间 ,调用的次数,CPU 的利用率,等等。这些东西对我们来 说非常有用。
我们重点观察运行时间最多,调用次数最多的那些函数和指令。这里注意一下,对于调用次数多但是时间很短的函数,你可能只需要轻微优化一下,你的性能就上去了(比如:某函数一秒种被调用100 万次,你想想如果你让这个函数提高0.01 毫秒的时间 ,这会给你带来多大的性能)
使用Profiler 有个问题我们需要注意一下,因为Profiler 会让你的程序运行的性能变低,像PurifyPlus 这样的工具会在你的代码 中插入很多代码,会导致你的程序运行效率变低,从而没发测试出在高吞吐量下的系统的性能,对此,一般有两个方法来定位系统瓶颈:
1 )在你的代码中自己做统计,使用微秒级的计时器和函数调用计算器,每隔10 秒把统计log 到文件中。
2 )分段注释你的代码块,让一些函数空转,做Hard Code 的Mock ,然后再测试一下系统的Throughput 和Latency 是否有质的变化,如果有,那么被注释的函数就是性能瓶颈,再在这个函数体内注释代码,直到找到最耗性能的语句。
最后再说一点,对于性能测试,不同的Throughput 会出现不同的测试结果,不同的测试数据也会有不同的测试结果。所以,用于性能测试的数据非常重要,性能测试中,我们需要观测试不同Throughput 的结果。
四、常见的系统瓶颈
下面这些东西是我所经历过的一些问题,也许并不全,也许并不对,大家可以补充指正,我纯属抛砖引玉。关于系统架构方面的性能调优,大家可移步看一下《由12306.cn 谈谈网站性能技术 》,关于Web 方面的一些性能调优的东西,大家可以看看《Web开发中需要了解的东西 》一文中的性能一章。我在这里就不再说设计和架构上的东西了。
一般来说,性能优化也就是下面的几个策略:
- 用空间换时间。各种 cache 如 CPU L1/L2/RAM 到硬盘,都是用空间来换时间的策略。这样策略基本上是把计算的过程一步一步的保存或缓存下来,这样就不用每次用的时候都要再计算一遍, 比如数据缓冲, CDN ,等。这样的策略还表现为冗余数据,比如数据镜象,负载均衡什么的。
- 用时间换空间。有时候,少量的空间可能性能会更好,比如网络传输,如果有一些压缩数据的算法(如前些天说的 “Huffman 编码压缩算法 ” 和 “rsync 的核心算法 ” ),这样的算法其实很耗时,但是因为瓶颈在网络传输,所以用时间来换空间反而能省时间。
- 简化代码。最高效的程序就是不执行任何代码的程序,所以,代码越少性能就越高。关于代码级优化的技术大学里的教科书有很多示例了。如:减 少循环的层数,减少递归,在循环中少声明变量,少做分配和释放内存的操作,尽量把循环体内的表达式抽到循环外,条件表达的中的多个条件判断的次序,尽量在 程序启动时把一些东西准备好,注意函数调用的开销(栈上开销),注意面向对象语言中临时对象的开销,小心使用异常(不要用异常来检查一些可接受可忽略并经 常发生的错误), …… 等等,等等,这连东西需要我们非常了解编程语言和常用的库。
- 并行处理。如果 CPU 只有一个核,你要玩多进程,多线程,对于计算密集型的软件会反而更慢(因为操作系统调度和切换开销很大), CPU 的 核多了才能真正体现出多进程多线程的优势。并行处理需要我们的程序有 Scalability ,不能水平或垂直扩展的程序无法进行并行处理。从架构上来说, 这表再为 —— 是否可以做到不改代码只是加加机器就可以完成性能提升?
总之,根据2 :8 原则来说,20% 的代码耗了你80% 的性能,找到那20% 的代码,你就可以优化那80% 的性能。 下面的一些东西都是我的一些经验,我只例举了一些最有价值的性能调优的的方法,供你参考,也欢迎补充。
4.1 )算法调优。算法非常重要,好的算法会有更好的性能。举几个我经历过的项目的例子,大家可以感觉一下。
- 一个是过滤算法,系统需要对收到的请求做过滤,我们把可以被 filter in/out 的东西配置在了一个文件中,原有的过滤算法是遍历过滤配置,后来,我们找到了一种方法可以对这个过滤配置进行排序,这样就可以用二分折半的方法来过滤,系统性能增加了 50% 。
- 一个是哈希算法。计算哈希算法的函数并不高效,一方面是计算太费时,另一方面是碰撞太高,碰撞高了就跟单向链表一个性能(可参看 Hash Collision DoS 问题 )。 我们知道,算法都是和需要处理的数据很有关系的,就算是被大家所嘲笑的 “ 冒泡排序 ” 在某些情况下(大多数数据是排好序的)其效率会高于所有的排序算法。哈 希算法也一样,广为人知的哈希算法都是用英文字典做测试,但是我们的业务在数据有其特殊性,所以,对于还需要根据自己的数据来挑选适合的哈希算法。对于我 以前的一个项目,公司内某牛人给我发来了一个哈希算法,结果让我们的系统性能上升了 150% 。(关于各种哈希算法,你一定要看看 StackExchange上的这篇关于各种 hash算法的文章 )
- 分而治之和预处理。以前有一个程序为了生成月报表,每次都需要计算很长的时间,有时候需要花将近一整天的时间。于是我们把我们找到了一种 方法可以把这个算法发成增量式的,也就是说我每天都把当天的数据计算好了后和前一天的报表合并,这样可以大大的节省计算时间,每天的数据计算量只需要 20 分钟,但是如果我要算整个月的,系统则需要 10 个小时以上( SQL 语句在大数据量面前性能成级数性下降)。这种分而治之的思路在大数据面前对性能有很帮 助,就像 merge 排序一样。 SQL 语句和数据库的性能优化也是这一策略,如:使用嵌套式的 Select 而不是笛卡尔积的 Select ,使用视图,等等。
4.2 )代码调优。从我的经验上来说,代码上的调优有下面这几点:
- 字符串操作。这是最费系统性能的事了,无论是 strcpy, strcat 还是 strlen ,最需要注意的是字符串子串匹配。所以,能用整型最好用整型。举几个例子,第一个例子是 N 年前做银行的时候,我的同事喜欢把 日期存成字符串(如: 2012-05-29 08:30:02 ),我勒个去,一个 select where between 语句相当耗时。另一个例子是,我以前有个同事把一些状态码用字符串来处理,他的理由是,这样可以在界面上直接显示,后来性能调优的时候,我 把这些状态码全改成整型,然后用位操作查状态,因为有一个每秒钟被调用了 150K 次的函数里面有三处需要检查状态,经过改善以后,整个系统的性能上升了 30% 左右。还有一个例子是,我以前从事的某个产品编程规范中有一条是要在每个函数中把函数名定义出来,如: const char fname[]=”functionName()”, 这是为了好打日志,但是为什么不声明成 static 类型的呢?
- 多线程调优。有人说, thread is evil ,这个对于系统性能在某些时候是个问题。因为多线程瓶颈就在于互斥和同步的锁上,以及线程上下文切换的成本,怎么样的少用锁或不用锁是根本(比如: 多版本并发控制 (MVCC)在分布式系统中的应用 中 说的乐观锁可以解决性能问题),此外,还有读写锁也可以解决大多数是读操作的并发的性能问题。这里多说一点在 C++ 中,我们可能会使用线程安全的智能指针 AutoPtr 或是别的一些容器,只要是线程安全的,其不管三七二十一都要上锁,上锁是个成本很高的操作,使用 AutoPtr 会让我们的系统性能下降得很 快,如果你可以保证不会有线程并发问题,那么你应该不要用 AutoPtr 。我记得我上次我们同事去掉智能指针的引用计数,让系统性能提升了 50% 以上。对 于 Java 对象的引用计数,如果我猜的没错的话,到处都是锁,所以, Java 的性能问题一直是个问题。另外,线程不是越多越好,线程间的调度和上下文切换 也是很夸张的事,尽可能的在一个线程里干,尽可能的不要同步线程。这会让你有很多的性能。
- 内存分配。不要小看程序的内存分配。 malloc/realloc/calloc 这样的系统调非常耗时,尤其是当内存出现碎片的时候。我 以前的公司出过这样一个问题 —— 在用户的站点上,我们的程序有一天不响应了,用 GDB 跟进去一看,系统 hang 在了 malloc 操作上, 20 秒都没有返 回,重启一些系统就好了。这就是内存碎片的问题。这就是为什么很多人抱怨 STL 有严重的内存碎片的问题,因为太多的小内存的分配释放了。有很多人会以为用 内存池可以解决这个问题,但是实际上他们只是重新发明了 Runtime-C 或操作系统的内存管理机制,完全于事无补。当然解决内存碎片的问题还是通过内存 池,具体来说是一系列不同尺寸的内存池(这个留给大家自己去思考)。当然,少进行动态内存分配是最好的。说到内存池就需要说一下池化技术。比如线程池,连 接池等。池化技术对于一些短作业来说(如 http 服务) 相当相当的有效。这项技术可以减少链接建立,线程创建的开销,从而提高性能。
异步操作。我们知道 Unix 下的文件操作是有 block 和 non-block 的方式的,像有些系统调用也是 block 式的, 如: Socket 下的 select , Windows 下的 WaitforObject 之类的,如果我们的程序是同步操作,那么会非常影响性能,我们可以改成 异步的,但是改成异步的方式会让你的程序变复杂。异步方式一般要通过队列,要注间队列的性能问题,另外,异步下的状态通知通常是个问题,比如消息事件通知 方式,有 callback 方式,等,这些方式同样可能会影响你的性能。但是通常来说,异步操作会让性能的吞吐率有很大提升( Throughput ),但是 会牺牲系统的响应时间( latency )。这需要业务上支持
发表评论
-
jcl与jul、log4j1、log4j2、logback的集成原理
2017-12-01 15:59 527jcl与jul、log4j1、log4j2、logbac ... -
slf4j与jul、log4j1、log4j2、logback的集成原理
2017-12-01 15:52 423收藏 jd ... -
预编译分析
2017-11-29 10:26 652一.背景: 用Mybatis+my ... -
预编译
2017-11-29 09:57 706PreparedStatement 在说PreparedS ... -
Spring Boot应用的后台运行配置
2017-11-21 14:26 538Spring Boot应用的后台运行配置 酱油一篇,整 ... -
编码
2017-11-21 14:25 521几种常见的编码格式 为什么要编码 不知道大家有没有想过一 ... -
Spring Boot应用的后台运行配置
2017-11-29 09:58 736Spring Boot应用的后台运行配置 酱油一篇, ... -
spring boot 注解
2017-11-01 10:58 343@EnableAutoConfiguration和@Spr ... -
支付话题
2015-09-09 11:45 1439本文档适用人员:交易领域的产品研发人员 提纲: 银 ... -
深入分析 Java 中的中文编码问题
2014-12-19 10:21 600在 IBM Bluemix 云平台上开发并部署您的下一个应 ... -
hashmap死循环
2014-11-24 10:45 754疫苗:Java HashMap的死循环 在淘宝内 ... -
jquery
2014-02-07 09:03 760当你准备使用jQuery,我强烈建议你遵循下面这些指南: ... -
减轻页面压力
2014-01-26 09:04 603网站快速加载,是提供 ... -
linux 命令
2014-01-23 09:20 400一.linux快捷键 Ctrl+C : 终止当前命令 C ... -
mina
2013-10-15 12:49 1355<!--StartFragment --> ... -
spring 线程池
2013-10-12 14:35 683Spring 线程池使用 Spring ... -
性能监控
2013-07-08 10:34 790spring,真是一个好东西;性能,真是个让人头疼又不 ... -
java ftp
2013-06-24 11:05 876在项目中使用到FTP功能,于是采用类似Spring的各种 ... -
json
2013-06-21 14:01 719JSON小结【json-lib】 j ... -
基于Spring打造简单高效通用的异步任务处理系统
2013-05-21 14:24 3924背景 随着应用系统功 ...
相关推荐
Linux性能调优是系统管理员和开发人员优化Linux系统性能的重要技能。它涉及对系统资源和应用程序的分析、监控、和调整,以实现更高的效率和响应速度。本篇学习笔记详细介绍了性能分析的步骤、优化工具、性能指标的...
《Oracle性能调优最佳攻略(OCP版)》详细阐述了Oracle性能调优的策略与实践,包括调优方法论、基本调优工具和DB时间模型等关键知识点。 首先,调优方法论提出了性能调优的主体——谁来调优。数据库管理员(DBA)、...
`WebLogic平台下J2EE调优攻略.doc`则可能深入讨论了如何针对J2EE应用程序进行性能优化,包括调整线程池、内存分配、垃圾收集策略等关键环节。 `WebLogic服务器性能参数.doc`文档可能会列出并解释WebLogic服务器的...
本文将详细介绍MySQL数据库性能调优的方法和技术,包括操作系统层面的优化、文件系统的选择、硬件配置建议、SQL语句优化技巧以及数据库内部配置的调整等。 #### 二、操作系统优化 1. **内核参数调整**: - 调整...
《Spark调优攻略上册》是一本专注于企业级大规模数据计算引擎Spark的调优指南,旨在帮助读者深入了解Spark的优化策略。该书不仅涵盖了Apache Spark的基础知识,还涉及了Data Lake和阿里云EMR团队研发的Jindo-Spark在...
### JVM调优攻略 #### 一、概述 《JVM调优攻略》是一份详尽的文档,旨在帮助开发者理解并掌握Java虚拟机(JVM)的优化技巧。本指南不仅适用于初学者,对于有一定基础的开发人员来说也同样具有很高的参考价值。文档中...
### BEA WebLogic平台下J2EE调优攻略详析 #### 重要性与背景 在当前数字化转型的大背景下,企业对于IT系统的依赖日益加深,尤其是J2EE(Java 2 Platform, Enterprise Edition)框架因其成熟性和灵活性,在企业级...
例如,“性能调优攻略”可能详细阐述了这些策略,“性能调优命令详解”可能包含了数据库管理系统中用于监控和调整性能的相关命令,“性能调优原则—IO篇”可能强调了I/O子系统优化的重要性,因为这是数据库性能的...
在BEA WebLogic平台上进行J2EE调优是提高应用程序性能和稳定性的重要步骤。这篇文章将带你深入了解如何在各个层面上优化你的系统。 首先,我们从应用程序本身的调优开始。通用代码调优涉及到优化代码逻辑,减少不必...
### BEA WebLogic平台下J2EE调优攻略 #### 前言 随着J2EE软件在各行各业中的广泛应用,系统调优变得越来越受到软件开发者和应用服务器提供商的关注。最终用户对系统的高效与稳定性有着极高的期待,因此,J2EE调优...
Oracle数据库性能优化是确保系统高效运行的关键环节,尤其是在大数据量和高并发的环境中。...对于大型企业来说,建立完善的数据库性能监控和调优体系,定期进行性能评估和调整,是保障信息系统稳定高效运行的基础。
本书由表及里地深入分析了造成oracle 数据库性能缓慢的各种原因,然后给出标本兼治的性能调优方案。作者将多年的实践经验和个人智慧与读者分享,帮助读者诊治影响数据库性能的各种疑难杂症。 《oracle database 11g...
本文主要探讨了SQL调优和索引管理两个核心方面。 首先,Oracle数据库的优化器是性能优化的核心组件,它负责选择执行SQL语句的最佳路径。优化器有三种模式:RULE(基于规则)、COST(基于成本)和CHOOSE(选择性)。...