Showing posts with label Performance. Show all posts
Showing posts with label Performance. Show all posts

Wednesday, May 4, 2016

Java Performance Monitoring



http://tutorials.jenkov.com/java-performance/jmh.html
When you build your JMH benchmarks, Maven will always generate a JAR file named benchmarks.jar in the target directory (Maven's standard output directory).
The benchmarks.jar file contains everything needed to run your benchmarks. It contains your compiled benchmark classes as well as all JMH classes needed to run the benchmark.
If your benchmarks has any external dependencies (JAR files from other projects needed to run your benchmarks), declare these dependencies inside the Maven pom.xml, and they will be included in thebenchmarks.jar too.

Since benchmarks.jar is fully self contained, you can copy that JAR file to another computer to run your JMH benchmarks on that computer.

https://antoniogoncalves.org/2015/01/15/micro-benchmarking-with-jmh-measure-dont-guess/
http://stackoverflow.com/questions/28936559/run-micro-benchmark-in-application-servers-jmh
 * <p>{@link Benchmark} demarcates the benchmark payload, and JMH treats it specifically
 * as the wrapper which contains the benchmark code. In order to run the benchmark reliably,
 * JMH enforces a few stringent properties for these wrapper methods, including, but not
 * limited to:</p>
@Benchmark is the annotation demarcating the piece of code JMH should treat as benchmark body. It is not a magic annotation which measures any given method elsewhere in the program. And, you are not supposed to call @Benchmark methods on your own.
What you want is not benchmark, it's a tracing/monitoring/profiling solution which can instrument and account all the stages the request gets through. JMH is not such a solution, you should look elsewhere.

Saturday, January 9, 2016

大型网站的灵魂——性能



http://www.csdn.net/article/2014-09-30/2821940
用户访问网站的整个流程:用户输入网站域名,通过DNS解析,找到目标服务器IP,请求数据经互联网达到目标服务器,目标服务器收到请求数据,进行处理(执行程序、访问数据库、文件服务器等)。处理完成,将响应数据又经互联网返回给用户浏览器,浏览器得到结果进行计算渲染显示给用户。
我们把整个过程,分为三段路径:
  • 第一段在用户和浏览器端,主要负责发出用户请求,以及接受响应数据进行计算渲染显示给用户;
  • 第二段在网络上,负责对请求数据、响应数据的传输;
  • 第三段在网站服务器端,负责对请求数据进行处理(执行程序、访问数据库、文件等),并将结果返回;

第一路径

第一路径花费的时间包括输入域名发起请求的时间和浏览器收到响应后计算渲染的时间。
输入域名发起请求,实质过程是:
  1. 用户在浏览器输入要访问的网站域名;
  2. 本地DNS请求网站授权的DNS服务器对域名进行解析,并得到解析结果即IP地址(并将IP地址缓存起来)。
  3. 向目标IP地址发出请求。
从这个过程我们可以看到,优化的地方主要是减少DNS解析次数,而如果用户浏览器设置了缓存,则再第二次访问相同域名的时候就不会去请求DNS服务器,直接用缓存中的IP地址发出请求。因此这个过程主要取决于浏览器的设置。现在主流的浏览器默认设置了DNS的预取功能(DNS Prefetch),当然你也可以主动告知浏览器我的网站需要做DNS预取:
<meta http-equiv="x-dns-prefetch-control" content="on" />
浏览器将数据进行计算渲染的过程:
  1. 浏览器解析响应数据;
  2. 浏览器创建DOM树;
  3. 浏览器下载CSS样式,并应用到DOM树,进行渲染;
  4. 浏览器下载JS文件,开始解析执行;
  5. 显示给用户。
从这个过程,我们可以找出不少可以优化的地方。首先我们可以尽量控制页面大小,使得浏览器解析的时间更短;并且将多个CSS文件、JS文件文件合并压缩减少文件下载的次数和大小;另外注意将CSS放在页面前面,JS访问页面后面,这样便于页面首先能渲染出来,再执行js脚本,对于用户来说有更好的体验。最后我还可以设置浏览器缓存,下次访问时从缓存读取内容,减少http请求。
<meta http-equiv="Cache-Control" content="max-age=5" />
该代码说明了浏览器启用了缓存并在5秒内不会再次访问服务器。注意缓存的设置需要结合你的业务特性来适当配置。
以下是京东商城的HTML简图:
css样式放在html前面,并且进行了合并。
大多数的JS文件放在页尾。 

第二路径

第二路径在网络上,花费的时间同样包括请求数据的传输时间和响应数据的传输时间,这个两个时间取决于数据传输的速度,这里我们要讲一个名词“带宽”。什么是带宽,我们经常说带宽10M,20M是什么意思?我的带宽20M,这意味着什么?我们知道带宽速度分为上行、下行速度,也就是上传和下载的速度。带宽20M对于用户来说则是下载速度20M(20×1024×1024比特率),换算成字节20M/8=2.5M。也就是说20M的带宽下载速度理论可达2.5M/s,而对于家庭用户而言上传速度一般比下载速度小的多,大约是不到十分之一。而对于网站服务器(企业用户)来说,则不然,一般上行速度等于下载速度。这也是运营商根据实际需求分配的,毕竟用户的主要需求是下载数据,而不是上传数据。
整个流程从传输方式看就是:用户发送请求数据(上传),网站服务器接受请求数据(下载),网站服务器返回响应数据(上传),用户接受响应数据(下载)。对于用户来说,上传数据是很小的(Url参数),而下载数据是较大的(响应数据);对于服务器来说,下载数据是很小的(url参数),上传数据是较大(响应数据)。理解了这个,我们可以解释为什么有时用户反映为什么自己的带宽足够,但打开某些网站仍然很慢,就是因为尽管用户的下载速度很快,但网站服务器的上传速度很慢,这就像一个抽水管和一个出水管,不管抽水管再大,但出水管很小,同样抽到的水量是有限的。了解了这个原理我们来看怎么提高数据传输的速度,首先用户的上传、下载速度我们是无法决定的,我们能决定的是网站服务器的上传、下载速度,所以我们可以做的是适当的增加服务器带宽(带宽是很贵的,盲目的增加只会增加不必要成本)。购买合适的带宽需要根据网站业务特性、规模以及结合运维人员的经验来选择。通常可以考虑的算法,即根据一次响应数据的大小,乘以PV数,除以对应的高峰时间段,从而大致估算出网站带宽的需求。
下面我们继续进一步研究第二路径:
上图表示用户访问网站服务器时网络的大致情况,从图上可以看出假设网站服务器从电信网络接入,而用户A作为电信的宽带用户,则可以通过电信骨干网快速的访问到网站服务器。用户B,用户C作为移动和联通用户需要通过运营商的互联互通经过较长路径才能访问到服务器。
针对这种情况,我们可以采取以下方法来优化:
  1. 在各运营商发达的地区的IDC(互联网数据中心,可以理解成机房)部署网站服务器,各运营商的用户即可通过各自的骨干网访问服务器。
  2. 购买代理服务,也就是原来联通用户需要通过联通骨干网——>联通互联互通路由器——>电信骨干网——>网站服务器的过程。通过代理服务,代理服务器直连到电信骨干网,访问网站服务器。
  3. 在主要地区城市购买CDN服务,缓存对应的数据,用户可先从最近的CDN运营商获取请求数据。

第三路径

第三路径主要是网站服务器内部处理的过程,当中包括执行程序、访问文件、数据库等资源。
这是对于我们来说最可以发挥的地方:
  • 使用缓存,根据需要使用本地缓存或分布式缓存;
  • 使用异步操作,这种方式不仅可以提高性能,也提高了系统的扩展性;
  • 代码优化;
  • 存储优化;
缓存
如果缓存数据较少,可以利用OSCache实现本地缓存:
当缓存数据过多时,利用Memcached实现分布式缓存: 
Memcached实现分布式缓存,缓存服务器之间是互不通信的,也就是我们可以方便的通过增加Memcached服务器对系统进行扩展。 
异步操作 
使用同步请求的方式,在高并发的情况下,会对数据库造成很大的压力,也会让用户感觉响应时间过长。异步请求方式,则可以快速的对用户做出响应,而具体的数据库操作请求,则通过消息队列服务器发送给数据库服务器,做具体的插入操作。插入操作的结果则已其他方式通知客户端。例如一般在订票系统当中,出票行为就是异步完成,最终的出票结果会以邮件或其他方式告知用户。
代码优化
这里就不在详细描述,另一篇随笔《怎样编写高质量的java代码》对代码质量和风格做过大致的介绍,有兴趣可以看一下。
存储优化
大型网站中海量的数据读写对磁盘造成很大压力,系统最大的瓶颈还是在磁盘的读写。可以考虑使用磁盘阵列、分布式储存来改善存储的性能。

性能的指标和测试

上面通过解析用户访问网站的过程来思考怎么提高用户感知的性能,对于用户来言性能就是快和慢。但对于我们来说,不能这样简单描述,我们需要去量化他,用一些数据指标去衡量它。这里讲到几个名词:响应时间、并发量、吞吐量。
  • 响应时间:就是用户发出请求到收到响应数据的时间;
  • 并发量:就是系统同时能处理多少用户请求;
  • 吞吐量:就是单位时间内系统处理的请求数量;
为了通俗的了解这三个概念,我们以高速公路的收费站为例子:响应时间是指一辆车经过收费站的时间,也就是车辆从进入收费站、付钱、开闸、离开收费站的时间;并发量是指这个收费站同时能通行多少辆车,可以理解为收费站的出口数量。吞吐量是指:在一段时间内,这个收费站通往了多少了车。
这个例子不晓得恰不恰当。
对于性能测试来说,基本也是围绕这些方面来测试,下图说明了性能测试的过程:
左图表示响应时间和并发用户量的二维坐标图,从图上可以看出,并发用户量在一定量增加时,响应时间很短,并且没有太大的起伏,这表示系统目前处于日常运行期,可以很快处理用户请求(A点之前);随着并发量的增加,系统处于请求高峰期,但仍然可以有序的处理用户请求,响应时间较日常有所增加(A、B之间);当并发量增加到一定数量时,超过了系统的负载能力,系统处于濒临崩溃的边缘(B、C之间),响应时间严重过长,直到系统崩溃。
右图表示吞吐量与并发用户量的二维坐标图,可以看出,随着并发用户量的增加,吞吐量逐渐增加;在并发量到达一定量时,由于系统处理能力达到最大,吞吐量增加放缓;当并发量超过系统负载时(E点),系统处理能力开始下降,不能再请求增加的用户请求,吞吐量反而降低。

Tuesday, October 6, 2015

Java Performance Misc



http://stackoverflow.com/questions/5483047/why-is-creating-a-thread-said-to-be-expensive
Java thread creation is expensive because there is a fair bit of work involved:
  • A large block of memory has to be allocated and initialized for the thread stack.
  • System calls need to be made to create / register the native thread with the host OS.
  • Descriptors needs to be created, initialized and added to JVM internal data structures.
It is also expensive in the sense that the thread ties down resources as long as it is alive; e.g. the thread stack, any objects reachable from the stack, the JVM thread descriptors, the OS native thread descriptors.
All these things are platform specific, but they are not cheap on any Java platform I've ever come across.

A Google search found me an old benchmark that reports a thread creation rate of ~4000 per second on a Sun Java 1.4.1 on a 2002 vintage dual processor Xeon running 2002 vintage Linux. A more modern platform will give better number
his numbers still indicate a 150+ fold improvement if you use a thread pool versus creating/starting a new thread each time. (And he makes the point that this is all relative ...)

(The above assumes "native threads" rather than "green threads", but modern JVMs all use native threads for performance reasons. Green threads are possibly cheaper to create, but you pay for it in other areas.)
http://tipsandtricks.runicsoft.com/General/Performance.html

http://ashwini47-tts.blogspot.com/2012/05/top-20-programming-tips-for-performance.html
Primitive types are faster than classes encapsulating types. Avoid the costs of object creation and manipulation by using primitive types for variables when prudent. Memory can be reduced and variable access times can be improved.
long is 64-bit while int is 32-bit data type. 32-bit operations are executed faster than 64-bit on 32-bit systems.
Use static final when creating constants. When data is invariant, declare it as static and final. By reducing the number of times variables need to be initialized and giving better optimization information to the JVM, performance can be improved.

17. When possible, declare methods as final
Declare methods as final whenever possible. Final methods can be handled better by the JVM, leading to improved performance.

http://stackoverflow.com/questions/4279420/does-use-of-final-keyword-in-java-improve-the-performance
To my mind you should use final based on clear design and readability rather than for performance reasons. If you want to change anything for performance reasons, you should perform appropriate measurements before bending the clearest code out of shape - that way you can decide whether any extra performance achieved is worth the poorer readability/design. (In my experience it's almost never worth it; YMMV.)
Theoretically, declaring a parameter final is not going to make a difference: the compiler is allowed to be smart enough to figure out that your method does not change the limit parameter, and optimize the code that it generates as if the parameter were declared final without the actual declaration.
The biggest difference that you are going to get by declaring method parameter final is the ability to reference that parameter in anonymous classes.
Another useful consequence is that people who maintain your code after you would know that keeping that parameter unchanged was your conscious decision, not a coincidence.
http://blog.csdn.net/it_man/article/details/8225477
  2. 尽量避免随意使用静态变量

  要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如
  3. 尽量避免过多过常的创建Java对象

  尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。

  4. 尽量使用final修饰符

  带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String.为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%.

  5. 尽量使用局部变量

  调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。
  12. 尽量合理的创建HashMap

  当你要创建一个比较大的hashMap时,充分利用另一个构造函数

  public HashMap(int initialCapacity, float loadFactor)

  避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。
  15. 尽量在finally块中释放资源

  20. 尽量避免使用二维数组

  二维数据占用的内存空间比一维数组多得多,大概10倍以上。

  21. 尽量避免使用split

  除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

  22. ArrayList & LinkedList

  一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。

  23. 尽量使用System.arraycopy ()代替通过来循环复制数组

  System.arraycopy() 要比通过循环来复制数组快的多

  24. 尽量缓存经常使用的对象

  尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。

  25. 尽量避免非常大的内存分配

  有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。

  26. 慎用异常

  当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。

  如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作--尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。

  (1)。 用Boolean.valueOf(boolean b)代替new Boolean()

  包装类的内存占用是很恐怖的,它是基本类型内存占用的N倍(N>2),同时new一个对象也是性能的消耗
  (2)。 用Integer.valueOf(int i)代替new Integer()

  (3)。 用StringBuffer的append方法代替"+"进行字符串相加。

  (4)。 避免过深的类层次结构和过深的方法调用。

  (4)。 避免过深的类层次结构和过深的方法调用。

  因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。

  (5)。 变量只有在用到它的时候才定义和实例化。

  这是初学者最容易犯的错,合理的使用变量,并且只有在用到它的时候才定义和实例化,能有效的避免内存空间和执行性能上的浪费,从而提高了代码的效率。

  (6)。 避免在循环体中声明创建对象,即使该对象占用内存空间不大。

  这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码:

  Java代码

  for (int i = 0; i < 10000; ++i) {

  Object obj = new Object();

  System.out.println("obj= " + obj);

  }

  上面的做法会浪费较大的内存空间。正确的做法如下所示:

  Java代码

  Object obj = null;

  for (int i = 0; i < 10000; ++i) {

  obj = new Object();

  System.out.println("obj= "+ obj);

  }

  采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象引用,浪费大量的内存空间,而且增大了垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。

  (7)。 如果if判断中多个条件用'||'或者'&&'连接,请将出现频率最高的条件放在表达式最前面。

  这个小技巧往往能有效的提高程序的性能,尤其是当if判断放在循环体里面时,效果更明显。

  1.JVM管理两种类型的内存:堆内存(heap),栈内存(stack),堆内在主要用来存储程序在运行时创建或实例化的对象与变量。而栈内存则是用来存储程序代码中声明为静态(static)(或非静态)的方法。

  2.JVM中对象的生命周期,创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段

  4.软引用的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。它可以用于实现一些常用资源的缓存,实现Cache的功能

  5.弱引用对象与Soft引用对象最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象,GC总是进行回收。

  6.共享静态变量存储空间

  7.有时候我们为了提高系统性能,避免重复耗时的操作,希望能够重用一些创建完成的对象,利用对象池实现。类似JDBC连接池。

  8.瞬间值,序列化对象大变量时,如果此大变量又没有用途,则使用transient声明,不序列化此变量。同时网络传输中也不传输。

  9.不要提前创建对象
  (3) 如果需要使用经常用到的图片展,可以使用软引用。

  (4) 注意集合数据类型,包括数组,树等数据,这些数据结构对GC来说,回收更为复杂,

  (5) 尽量避免在类的默认构造器中创建,初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费。

  (6) 尽量避免强制系统做垃圾内存回收。

  (7) 尽量避免显式申请数组空间。

  (8) 尽量在合适的场景下使用对象池技术以提高系统性能,缩减系统内存开销。

  11.当做数组拷贝操作时,采用System.arraycopy()方法完成拷贝操作要比采用循环的办法完成数组拷贝操作效率高

  12. 尽量避免在循环体中调用方法,因为方法调用是比较昂贵的。

  13. 尽量避免在循环体中使用try-catch 块,最好在循环体外使用try--catch块以提高系统性能。

  14. 在多重循环中,如果有可能,尽量将最长的循环放在最内层,最短的循环放在最外层,以减少循环层间的变换次数。

  15. 在需要线程安全的情况下,使用List list = Collections.synchronizedList(new ArrayList());
  19. 系统I/O优化,采用缓冲和压缩技术。优化性能。

  20. 避免在类在构造器的初始化其他类

  21 尽量避免在构造中对静态变量做赋值操作

  22. 不要在类的构造器中创建类的实例

  23. 组合优化继承

  24. 最好通过Class.forname() 动态的装载类

  25. JSP优化,采用out 对象中的print方法代替println()方法

  26 .采用ServletOutputStream 对象代替JSPWriter对象

  27. 采用适当的值初始化out 对象缓冲区的大小

  28. 尽量采用forward()方法重定向新的JSP

  29. 利用线程池技术处理客户请求

  30.Servlet优化

  (1) 通过init()方法来缓存一些静态数据以提高应用性能。

  (2) 用print() 方法取代println()方法。

  (3) 用ServletOutputStream 取代 PrintWriter.

  (4) 尽量缩小同步代码数量

  31. 改善Servlet应用性能的方法

  (1)不要使用SingleThreadModel

  (2)使用线程池ThreadPool

  32. EJB优化

  实体EJB:

  (1)实体EJB中常用数据缓存与释放

  (2)采用延迟加载的方式装载关联数据

  (3)尽可能地应用CMP类型实体EJB

  (4)直接采用JDBC技术处理大型数据

  33. 优化JDBC连接

  (1)设置合适的预取行值

  (2)采用连接池技术

  (3)全合理应用事务

  (4)选择合适的事务隔离层与及时关闭连接对象

  34. PreparedStatemetn只编译解析一次,而Statement每次都编译解析。

  35. 尽可能地做批处理更新

  36. 通过采用合适的getXXX方法提高系统性能

  37. 采用设计模式。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts