编写高性能Java代码的最佳实践,如何构建高扩展

来源:http://www.aobaot.com 作者:技术 人气:178 发布时间:2019-11-09
摘要:转自:北京尚学堂IT学院(一点号)返回搜狐,查看更多 翻译:雁惊寒 避免或分发状态 40 努力实现无状态 实现状态会限制扩展性,增大成本 41 尽可能在浏览器端维护会话 一方面降低

转自:北京尚学堂IT学院(一点号)返回搜狐,查看更多

翻译:雁惊寒

避免或分发状态

  40 努力实现无状态

  实现状态会限制扩展性,增大成本

  41 尽可能在浏览器端维护会话

  一方面降低服务器压力,另一方面任何的请求可以发送给任何的服务器。

  42 利用分布式缓存存放状态

  使用独立的缓存层,利于扩展。有很多分布式的缓存方案,比如memcached。

这样,无论是在驱动端还是在数据库端,性能都可能得到显著地提升。 * PreparedStatement*是一个非常棒的的批处理命令,一些数据库系统只支持预处理语句的批处理。

架构质量从一开始设计就要考虑进去,质量不能靠测试来解决。测试只能发现研发过程中带来的问题。

监控应用程序

其他原则

  46 慎用第三方解决方案扩展

  企业如果出现问题,那么寻找第三方能够解决燃眉之急。但是却不是长久之计,因为解决方案的提供商有很多客户,你的危机并不是他们的危机,所以不可能在关键时刻,尽职尽责。因此企业还是应该有一定的掌控力(这个词真是高大上!)。

  47 清除、归档和成本合理的存储

  有一些不必要的数据,就应该定期的删除。一些略有价值的数据进行定期的归档直接删除。一些很有价值的数据,应该进行备份以及快速访问。

  48 删除事务处理中的商业智能

  应该把产品系统与业务系统分离,提高产品的扩展性。

  避免业务扩展时,受到系统架构的限制。

  49 设计能够监控的应用

  应该设计全局的监控策略,保证回答

  ”发生了 问题了吗?“

  ”哪里发生了问题?“

  ”发生了什么问题?“

  ”会发生问题吗?“

  ”能自动修复吗?“

威尼斯国际平台app 1

  50 要能胜任

  应该在每个设计中涉及到最优秀的架构,不能完全依赖第三方的解决方案。

  一个简单优秀的架构,都是小而精的,如果单纯的依靠开源解决架构,虽然解决了问题,却会导致应用的臃肿。

我们将使用这个程序作为参考来运行负载测试,并在接下来的章节中监控各种应用指标。

以下内容节选自:世界级软件架构大师 Martin Abbott 亲研架构秘籍《突破技术领导力》

为此,Java的ExecutorService是线程池的基础,它提供了一个高级API来定义线程池的语义并与之进行交互。

化简方程

  1 不要过度的设计

  过度的设计相当于给系统增加了复杂度与维护的成本。而这些过度的设计,在正常的使用中,却没有太大的作用。往往是设计者自己认为很重要或者锦上添花的功能,实际用处不大。

  2 设计时考虑到扩展性

  在设计时要遵循一下的设计原则:设计时考虑20倍的容量,实现时考虑3倍的容量,部署时考虑1.5的容量。一面项目扩大时,临时扩展造成的困难。

  3 把方案一简再简

  应该遵循帕累托法则,20%的设计做了80%的工作,所以80%的时间,都应该放在这20%的设计上。

  一个产品主要的功能其实都集中在几个点上,把这几个点设计好了,其他的都是些附加的功能而已。所以这核心的业务一定要保证足够的简洁易用。

  4 减少DNS查询

  每个不同的域下的文件,加载时都需要查询DNS。比如cnblogs.com与i.cnblogs.com就属于不同的域。那么在查询DNS的时候,就会查询两次。当业务量很大时,就会造成一定的影响。

  5 尽可能减少对象

  由于对象在浏览器访问时,需要加载。所以可以考虑减少请求文件的数量(数量与浏览器并发加载数有关),把一些对象尽量的合并。比如图标类的文件,可以合并成一个大的图片。合理的文件数量,会加速浏览器的访问加载。

  6 使用同一品牌的网络设备

  由于一个http请求,可能通过很多物理设备。比如负载均衡器,交换机,路由器。所以尽量使用同一品牌的设备,会避免一些意外的情况。

为此,Java的ExecutorService是线程池的基础,它提供了一个高级API来定义线程池的语义并与之进行交互。

根据不同服务或(和)用户使用的量级来分割应用和数据库。虽然它会给程序带来一些轻量的复杂度,但在规模上这样做更易于扩展。

在开始优化应用程序的性能之前,我们需要理解诸如可扩展性、性能、可用性等方面的非功能需求。

横向扩展设计

  10 设计横向的扩展方案

  扩展包括横向、纵向。横向就是通过复制克隆应用,利用小型机集群扩展。纵向就是提高服务器的硬件以及网络设施。

  通过很多的案例都可以发现,单纯的升级硬件实现的纵向扩展,仅仅能解决一点点现实压力。而通过横向的集群扩展,却能够自由的实现伸缩。

  11 采用经济型系统

  与上面的原则类似,采用高价格的服务器,并不能保证日后的良好性能。应该使用普通的小型机集群扩展。

  12 横向扩展数据中心

  数据中心有很多的设计方案,比如

  热冷站配置:使用热站提供服务,当热站崩溃时,使用冷站继续服务。

威尼斯国际平台app 2

  推荐使用多个实时站点,成本更低,动态调用。缺点是增加了运维的难度。

  13 利用云技术进行设计

  云计算的有点就是虚拟化,可以在业务峰值时,弹性的扩充设备。并且在日常处理用,归还该扩展。

  缺点是提高了应用于虚拟环境的耦合。后面提到利用物理设备,隔离业务,在虚拟化的云计算中,可能会对业务隔离错误排查造成一定的干扰。

如果没有经过真实场景的测试,这些数字很难估计。

1. 尽可能多地使用异步的通信方式

字符串连接是一个非常常见的操作,也是一个低效率的操作。简单地说,使用+=来追加字符串的问题在于每次操作都会分配新的String。

从错误中吸取教训

  27 积极的学习

  一个公司有学习的氛围,才会衍生出更好的产品。学习的内容一方面包括客户的业务知识,一方面来自技术和运维领域。

  28 不要依靠QA发现失误

  雇佣测试或者质量保证人员,最大的目的是为了检测产品的正确性。它能减少成本,提高开发人员的开发速度,因为开发人员不需要时刻关注代码的正确性,可以交给QA来测试。

  但是QA只负责发现问题,如何避免为题还是得依靠开发人员。

  29 没有回退的设计是失败的设计

  这里的回退,指的是产品发布的回退。如果碰上某些版本的BUG,可能需要交付之前可运行的版本,此时没有回退,就无法交付产品了。

  这里推荐学习持续集成的相关内容。

  30 讨论失败并从中吸取教训

  不应该在同一个问题上失败两次,每次失败多进行总结是不可缺少的。

这些指标可以通过使用多种监视工具监测到,它们对分析性能瓶颈和性能调优有着非常大的作用。

6. 使用切片(Sharding)技术

威尼斯国际平台app ,容错设计与故障控制

  36 采用隔离故障的”泳道“

  服务与数据的划分有很多种,比如容器,集群,池,分片,泳道。泳道意味着每个业务有自己的领域,不能跨泳道调用。

  37 不要信任单点故障

  有很多系统设计成单点模式,当整个系统只是用该模块时,当出现单点故障,整个系统也就崩溃了。

  38 避免系统串联

  比如一个系统有很多的组件组成,每个组件99.9%的安全性,当串联3个组件时,整个系统的可用性就变成了99.7%。

  39 确保能够启用/禁用功能

  对于某些共享库,第三方服务,应该提供开启或者关闭的功能。

谨慎使用正则表达式

3. 使用多层次的缓存

例如,大多数的持久化框架都支持缓存。 Spring MVC等Web框架还可以使用Spring中内置的缓存支持,以及基于ETags的强大的HTTP级缓存。

不要做重复的工作

  17 不要立即检查刚做过的工作

  比如刚刚写如了数据,不要立即读取。虽然有些客户需要保证数据的完整,不能丢失。但是可以通过日志等记录,写完查这种做法,还是不推荐。

  18 停止重定向

  重定向会消耗一定的延迟,计算资源。应该尽量避免

  19 放松时序约束

  大多数的关系型数据库讲究ACID属性,扩展时就造成一定的困扰。因此某些业务适当的放松时序约束,可以提高网站的性能。

  比如某站在预定酒店时,用户预定后,会等待酒店的审核。比如某宝,在提款时,进行范围时间的确认。这种就是扩大了时序约束,进而提高网站性能以及事务安全。

喜欢小编轻轻点个关注哦!

4. 监控应用程序性能

根据“ Gatling的第一步 ”所述,用下面的代码创建一个名为EmployeeSimulation的scala文件:

本篇通过阅读《高扩展性网站的50条原则》,总结出以下内容。

一方面博主没有实际的架构经验,另一方面知识面也不够宽阔,所以只能系统的总结书中的要点,并根据自己的理解做些归纳。

Stop-the-world垃圾收集的周期是影响大多数面向客户端应用程序响应和整体Java性能的大问题。但是,目前的垃圾收集器大多解决了这个问题,并且通过适当的优化和大小的调整,能够消除对收集周期的感知。

一定要在产品部署前,执行负载与性能测试。虽然这不会发现所有问题(这也是为什么我们需要回滚 Rollback的能力),但它很值得做。

持久化处理应尽可能地执行批量操作。 JDBC批处理允许我们在单次数据库交互中发送多个SQL语句。

积极利用缓存

  20 利用CDN

  可以利用CDN保存客户的数据和内容。大概的过程是,用户在进行网站访问时,转到CDN的服务器,CDN执行DNS查询,把用户请求分摊到不同的服务器。有很多的CDN服务商提供这种服务。

  21 使用过期头

  针对不同的对象类型,使用过期头,减少对象请求。常见的HTTP对应属性为:public no-cahe max-age等等

  22 缓存Ajax调用

  正确修改Http头Last-Modified Cache-Control Expires等属性。

  23 利用页面缓存

  缓存响应之前的冬天请求,降低web服务器的负载。

  24 利用应用缓存

  比如针对某些特殊的用户,缓存其请求数据。

  25 利用对象缓存

  适用于反复查询使用的数据对象。比如一个购物网站,缓存器热销产品数据。

  26 把对象缓存放在自己的层上

  使用单独的缓层,易于扩展和维护。

现在内存的价格很低,而且越来越低,从磁盘或通过网络来检索数据的性能代价仍然很高。缓存自然而然的变成了在应用程序性能方面不能忽视的关键。

5. 复制数据库

public String stringAppendLoop() {
    String s = "";
    for (int i = 0; i < 10000; i++) {
        if (s.length() > 0)
            s += ", ";
        s += "bar";
    }
    return s;
}

public String stringAppendBuilderLoop() {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
        if (sb.length() > 0)
            sb.append(", ");
        sb.append("bar");
    }
    return sb.toString();
}

主要内容

  本书从多个方面围绕高扩展性提出了50条建议,一个高扩展性的网站会随着业务的发展、用户的增加,自由的扩展架构,从而轻松的应付网站的快速发展。下面看看本书的具体内容:

威尼斯国际平台app 3

威尼斯国际平台app 4

威尼斯国际平台app 5

现在内存的价格很低,而且越来越低,从磁盘或通过网络来检索数据的性能代价仍然很高。缓存自然而然的变成了在应用程序性能方面不能忽视的关键。

使用正确的工具

  14 合理使用数据库

  目前有许多的数据库版本,比如传统的关系型数据库Oracle、MySQl,还有比较新的非关系型数据库NoSql,比如MongoDB,以及内存数据库FastDB,还有专门针对SSD固态硬盘的Aerospike等等。

  但是到了选型的时候,还是要一句个人的业务需求来定。看你的数据库要求的是速度,还是安全性等等。

  15 防火墙,到处都是防火墙

  防火墙可以对一些无效的访问进行拦截过滤。通常把一些CSS,静态文件,图片,JS等不采用防火墙,而关键的业务涉及到个人信息时采用。合理的设计防火墙,也会对网站的性能产生一定的影响。

  16 积极的利用日志文件

  利用各种日志以及工具,实时的监控业务。不仅仅是监控服务器的内存CPU,还应该监控业务上的数据。比如splunk(提供日志的搜集,存储,搜索,图形化展示)。

持久化处理应尽可能地执行批量操作。 JDBC批处理允许我们在单次数据库交互中发送多个SQL语句。

威尼斯国际平台app 6

其他JVM语言(如Scala)已经在编译器级 支持 尾递归代码的优化,当然,对于这种优化目前也存在着一些争议。

异步通信和消息总线

  43 尽可能使用异步通信

  异步通信,可以确保每个服务和层之间的独立性,这样易于早呢更加系统的扩展性和减小耦合度。

  44 确保消息总线能够扩展

  尽量采用Y轴或者Z轴扩展,即按业务需求和功能扩展。因为单纯的复制或者克隆,反而会增加各个消息订阅者的监听数目。按照业务隔离,可以分离业务压力。

  45 避免让消息总线过度拥挤

  衡量价值与消息的成本。

威尼斯国际平台app 7

估计内存缓存所需的空间,例如,由应用程序加载的内部缓存数据结构,比如从数据库缓存的数据、从文件中读取的数据等等。

10. 不能回滚注定失败

数据库复制和分片 是提高吞吐量非常好的方法,我们应该充分利用这些经过实践检验的架构模式,以扩展企业应用的持久层。

分布工作

威尼斯国际平台app 8

  7 X轴,横向复制

  这种事最简单的服务扩充,通过克隆或者复制实现,比如你的应用放在多个服务器上进行服务。常见的比如集群,负载均衡等等,数据库的读写分离。

  8 Y轴,拆分不同的东西

  大型系统中,拆分不同的功能,比如注册、购买、查询、云盘。等等

  9 Z轴,拆分不同的相似的东西

  比如按照用户的级别,或者用户的地理位置等等拆分。

数据库复制和分片是提高吞吐量非常好的方法,我们应该充分利用这些经过实践检验的架构模式,以扩展企业应用的持久层。

根据用户划分来创建硬件隔离的“泳道 Swim Lanes”。这可以防止因为某个客户所产生的问题而影响其他客户,同时有助于诊断问题和代码发布。

这样,无论是在驱动端还是在数据库端, 性能都可能得到显著地提升 。 * PreparedStatement*是一个非常棒的的批处理命令,一些数据库系统(例如Oracle)只支持预处理语句的批处理。

数据库原则

  关系型数据库的ACID属性:

  原子性:一个事务要么全执行,要么都不执行,

  一致性:事务开始和结束时,所有数据状态要一致,

  隔离性:事务的表现,是事务对数据库唯一的操作,

  持久性:事务完成,操作不能更改。

  31 注意代价高的关系

  应该在设计阶段完善的设计表的结构,等开发开始时,在增加某些列,可能会花费很高的代价。

  32 使用正确的数据库锁

  数据库有很多锁的概念,比如隐式锁、显式锁、行锁、页锁、范围锁、表锁、数据库锁等等。

  不合理的使用锁,会影响网站的吞吐量。

  33 不要使用多阶段提交

  比如两阶段提交:先表决,在提交。这回降低扩展性,因为在其提交事务完成前,是不能作其他操作的。

  34 不要使用select for update

  因为FOR UPDATE从句会导致锁定行,降低事务处理的速度。

  35 不要选择所有的数据

  比如select * from xxx;

  这种做法第一是不开与数据的扩展,比如本来有四列数据,业务处理代码直接写死。当增加了一列数据时,就会导致出错;另外就是会查询出不必要的数据。

  或者inset into xxx values(xxxx);

  这是当列信息不匹配时,也会出错。

Retrace会自动监控应用程序,并跟踪数十种常见框架及其依赖关系的使用情况,包括SQL、MongoDB、Redis、Elasticsearch等等。Retrace能帮助我们快速确定应用程序为什么会出现如下性能问题:

架构扩展性的13条最佳实践

运行负载测试

参考

  【1】《高扩展性网站的50条原则》

语句缓存是另一种提高持久层性能的方法,这是一种鲜为人知但又容易掌握的性能优化方法。

同步调用会同时将两种不同服务的可用性捆绑在一起。如果其中一者产生错误或是堵塞,另一者也会受到影响。

原文: How to Improve the Performance of a Java Application

Gatling负载测试

尽可能使用OLTP(on-line transaction processing,联机事务处理 )数据库作为存储设备。因为要确保ACID属性,关系型数据库在扩展型方面会有很多挑战。你的交易越依赖关系型数据库系统(RDBMS)提供的功能,那么系统在扩展时你投入的负载就越大。建议从数据库中将主要的业务逻辑(例如存储过程)都移到应用程序或服务内。当系统需要做大规模扩展时,应该通过应用或服务来扩展, 而不是通过SQL。

说起来容易,做起来难,而且了解应用程序当前的性能也非常重要。这就是我们接下来要关注的问题。

示例应用程序

对于每一层、每一个服务,都要清楚它有多大容量。使用 扩展峰值(Scalability Summits) 来规划容量的增长需求。

【编辑推荐】

如果你不得不在计算密集的代码段中使用正则表达式,那么需要缓存Pattern的引用而避免重复编译:

确保所有版本的代码都有回滚能力,在准生产或者QA环境演练,必要时在生产环境中用它来解决客户的问题。如果没有经历过无法回滚代码的痛,还继续冒险地“修改-发布”代码,那么你会在未来某个时刻体会到这种痛苦。

作者:Eugen Paraschiv

说起来容易,做起来难,而且了解应用程序当前的性能也非常重要。这就是我们接下来要关注的问题。

首先要站在客户的角度去分析你的程序性能。从外部网络进行监控测试,可以模拟真实的用户体验。同时,还可以根据查询和事务操作上执行次数和耗时数据,来监控程序的内部工作情况。

负载测试和应用程序监控对于确定应用程序的一些关键性能瓶颈非常有用。但同时,我们需要遵循良好的编码习惯,以避免在对应用程序进行监控的时候出现过多的性能问题。

对应用程序的API进行负载测试有助于发现及其细微的并且难以发现的错误,如数据库连接耗尽、高负载情况下的请求超时、因为内存泄漏而导致堆的高使用率等等。

在多个层上尽可能地使用缓存,如数据库前的对象缓存(例如:memcached),或是页面内容缓存(例如:squid),边缘缓存(例如:Akamai)。

Java 7中的Fork/Join框架也值得提一下,因为它提供了一些工具来尝试使用所有可用的处理器核心以帮助加速并行处理。为了提高并行执行效率,框架使用了一个名为ForkJoinPool的线程池来管理工作线程。

使用一些流行的库,比如Apache Commons Lang也是一个很好的选择,特别是在字符串的操作方面。

2. 使用用户泳道来隔离错误

  • 应用程序平均响应时间
  • 系统必须支持的平均并发用户数
  • 在负载高峰期间,预期的每秒请求数

在下一章节中,我们将来看一些最佳实践。

9. 在部署前执行负载与性能测试

找到最慢的那个点

要获得有关应用程序需求的最好最可靠的方法是对应用程序执行实际的负载测试,并在运行时跟踪性能指标。我们之前讨论的基于Gatling的测试就是一个很好的方法。

复制数据库可以帮助还原数据,同时把读取的负载分配到多个实例。

在下一章节中,我们将来看一些最佳实践。

欢迎工作一到五年的Java工程师朋友们加入Java技术交流:585550789

8. 在服务器上小批量地部署新代码

介绍

特定的HTTP Web服务宕了,还是变慢了?

12. 问题根源分析

配置记录器

横向扩展

  1. 从一开始就重视质量工作
class EmployeeSimulation extends Simulation {
    val scn = scenario("FetchEmployees").repeat(10000) {
        exec(
          http("GetEmployees-API")
            .get("http://localhost:8080/employees")
            .check(status.is(200))
        )
    }
    setUp(scn.users(200).ramp(100))
}

应用程序平均响应时间

确保有强大的学习文化,当问题出现时,一定要确保找到问题根源, 才能最终修复问题。

对应用程序的API进行负载测试有助于发现及其细微的并且难以发现的错误,如数据库连接耗尽、高负载情况下的请求超时、因为内存泄漏而导致堆的高使用率等等。

我们将使用一个简单的Spring Boot Web应用程序作为示例,在这篇文章中有相关的介绍。这个应用程序可用于管理员工列表,并对外公开了添加和检索员工的REST API。

7. 尽可能少的使用关系型数据库RDBMS特性

如果你不得不在计算密集的代码段中使用正则表达式,那么需要缓存Pattern的引用而避免重复编译:

架构改进

原标题:架构干货:来听听架构大师 Martin Abbott 怎么说

摘要:本文首先介绍了负载测试、基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践。最后研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。以下是译文。

现在我们把它重写为尾递归:

11. 容量规划 / 扩展峰值

我们将使用一个简单的Spring Boot Web应用程序作为示例,在 这篇文章 中有相关的介绍。这个应用程序可用于管理员工列表,并对外公开了添加和检索员工的REST API。

字符串连接是一个非常常见的操作,也是一个低效率的操作。简单地说,使用+=来追加字符串的问题在于每次操作都会分配新的String。

责任编辑:

性能指标

系统必须支持的平均并发用户数

尽可能小批量地在服务器上部署新代码,而不要让整个站点关闭。这要求所有代码都要向后兼容,因为在部署时你会有两个版本的代码同时运行。这种方法可以帮助我们方便地找到应用质量或者L&P测试(负载性能测试)所遗漏的问题,同时最小化对客户的影响。

选择合适的垃圾收集器

对大多数的现代框架和库来说,这方面还是支持得很好的,而且会变得越来越好。 Spring生态系统有一个完整的项目集,专门用于解决这个特定的应用程序架构领域,其他大多数的框架也都有类似的支持。

如果应用程序使用了大量的线程,那么使用线程池会更加有用,因为线程池允许这些昂贵的对象被重用。

找到最慢的那个点

现在我们把它重写为尾递归:

避免创建和销毁过多的线程

Retrace代理和要监控的Java应用程序启动后,我们就可以到Retrace仪表板上单击AddApp按钮添加应用了。添加应用完成之后,Retrace将开始监控应用程序了。

在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法。我们首先将介绍如何定义可度量的性能指标,然后看看有哪些工具可以用来度量和监控应用程序性能,以及确定性能瓶颈。

  • 某个SQL语句是否会拖慢系统的速度?
  • Redis突然变慢了吗?
  • 特定的HTTP Web服务宕了,还是变慢了?

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

JDBC批处理

另一方面,Hibernate则更加灵活,它允许我们只需修改一个配置即可快速切换为批处理操作。

使用一些流行的库,比如 Apache Commons Lang 也是一个很好的选择,特别是在字符串的操作方面。

在这篇文章中,我们围绕着提升Java应用的性能探讨了许多概念。我们首先介绍了负载测试、基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践。最后,我们研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。

线程的创建和处置是JVM出现性能问题的常见原因,因为线程对象的创建和销毁相对较重。

找出性能瓶颈

使用StringBuilder来连接字符串

威尼斯国际平台app 9

避免创建和销毁过多的线程

例如,下面的图形展示了在一段给定的时间内速度最慢的组件。

规模的缩放

我们来看一个头递归的例子:

导致出现StackOverFlowError错误的递归代码逻辑是Java应用程序中另一种常见的问题。如果无法去掉递归逻辑,那么尾递归作为替代方案将会更好。

监控应用程序

结论 在这篇文章中,我们围绕着提升Java应用的性能探讨了许多概念。我们首先介绍了负载测试、基于APM工具的应用程序和服务器监控,随后介绍了编写高性能Java代码的一些最佳实践。最后,我们研究了JVM特定的调优技巧、数据库端的优化和架构方面的调整。

连接池

static final Pattern HEAVY_REGEX = Pattern.compile("(((X)*Y)*Z)*");

JDBC性能

代码级别的优化

线程的创建和处置是JVM出现性能问题的常见原因,因为线程对象的创建和销毁相对较重。

因此,像Retrace这样功能全面的监控工具是解锁应用程序性能潜力的第一步。而第二步则是在你的系统上重现真实使用场景和负载。

static final Pattern HEAVY_REGEX = Pattern.compile*Z)*");

我们来看一个头递归的例子:

上面代码中使用的StringBuilder对性能的提升非常有效。请注意,现代的JVM会在编译或者运行时对字符串操作进行优化。

连接池

这里建议使用HikariCP JDBC,这是一个非常轻量级并且速度极快的JDBC连接池框架。

威尼斯国际平台app 10

在我们的这个例子中,具体的场景将是“启动200个用户,每个用户发出一万个请求。”

要获得有关应用程序需求的最好最可靠的方法是对应用程序执行实际的负载测试,并在运行时跟踪性能指标。我们之前讨论的基于Gatling的测试就是一个很好的方法。

其他JVM语言已经在编译器级支持尾递归代码的优化,当然,对于这种优化目前也存在着一些争议。

分析器、堆转储和详细的GC日志记录工具对此有一定的帮助作用。再一次注意,这些都需要在真实场景的负载模式下进行监控。

只要底层的JDBC驱动程序支持,你就可以在客户端或数据库端(语法树甚至执行计划)中缓存PreparedStatement。

另一方面,Hibernate则更加灵活,它允许我们 只需修改一个配置即可快速切换为批处理操作。

我们还将看到一些常见的Java代码优化方法以及最佳编码实践。最后,我们将看看用于提升Java应用程序性能的JVM调优技巧和架构调整。

关系型数据库是Java应用程序中另一个常见的性能问题。为了获得完整请求的响应时间,我们很自然地必须查看应用程序的每一层,并思考如何让代码与底层SQL DB进行交互。

计划要把多少个不同的应用程序部署到单个JVM进程中,例如EAR文件、WAR文件、jar文件的数量是多少?

Retrace还提供了监视基于JVM应用程序的内存、线程和类的小部件。除了应用程序本身的指标之外,它还支持监视托管应用程序的服务器的CPU和IO使用情况。

让我们从众所周知的事实开始,即数据库连接是昂贵的。 连接池机制是解决这个问题非常重要的第一步。

让我们从众所周知的事实开始,即数据库连接是昂贵的。 连接池 机制是解决这个问题非常重要的第一步。

Gatling的模拟测试脚本是用Scala编写的,但该工具还附带了一个非常有用的图形界面,可用于记录具体的场景,并生成Scala脚本。

谨慎使用正则表达式

请注意,性能优化是一个很宽泛的话题,而本文只是对JVM探索的一个起点。

要使用Retrace进行Java应用程序的开发,首先需要在Stackify上申请 免费试用 账号。然后,将我们自己的 Spring Boot 应用程序配置为Linux服务。我们还需要在托管应用程序的服务器上安装Retrace代理,按照 这篇文章 所述的操作即可。

在负载高峰期间,预期的每秒请求数

private int factorial(int n, int accum) {
    if (n == 0) {
        return accum;
    } else {
        return factorial(n - 1, accum * n);
    }
}
public int factorial(int n) {
    return factorial(n, 1);
}

负载测试工具和应用程序性能管理解决方案常用于跟踪和优化Java应用程序的性能。要找出性能瓶颈,主要就是对各种应用场景进行负载测试,并同时使用APM工具对CPU、IO、堆的使用情况进行监控等等。

public int factorial(int n) {
    if (n == 0) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

导致出现StackOverFlowError错误的递归代码逻辑是Java应用程序中另一种常见的问题。如果无法去掉递归逻辑,那么尾递归作为替代方案将会更好。

我们将使用这个程序作为参考来运行负载测试,并在接下来的章节中监控各种应用指标。

代码级别的优化

除了能够提升Java的性能,通过集群进行横向扩展也有其他的好处,添加新的节点能产生冗余,并更好的处理故障,从而提高整个系统的可用性。

在开始优化应用程序的性能之前,我们需要理解诸如可扩展性、性能、可用性等方面的非功能需求。

示例应用程序

当然,在应用的拓扑结构中引入一个独立的缓存系统确实会增加架构的复杂度,所以,应当充分利用当前使用的库和框架现有的缓存功能。

请注意,性能优化是一个很宽泛的话题,而本文只是对JVM探索的一个起点。

Java 7中的Fork/Join框架也值得提一下,因为它提供了一些工具来尝试使用所有可用的处理器核心以帮助加速并行处理。为了提高并行执行效率,框架使用了一个名为ForkJoinPool的线程池来管理工作线程。

例如,下面的图形展示了在一段给定的时间内速度最慢的组件。

关系型数据库是Java应用程序中另一个常见的性能问题。为了获得完整请求的响应时间,我们很自然地必须查看应用程序的每一层,并思考如何让代码与底层SQL DB进行交互。

对大多数的现代框架和库来说,这方面还是支持得很好的,而且会变得越来越好。 Spring生态系统有一个完整的 项目集 ,专门用于解决这个特定的应用程序架构领域,其他大多数的框架也都有类似的支持。

有关不同垃圾收集器的更多信息,请查看这个指南。

定义场景

配置记录器

如果没有经过真实场景的测试,这些数字很难估计。

在启动记录器之前,我们需要定义一个场景,表示用户在浏览Web应用时发生的事情。

这里建议使用 HikariCP JDBC ,这是一个非常轻量级(大约130Kb)并且速度极快的JDBC连接池框架。

分析器、堆转储和详细的GC日志记录工具对此有一定的帮助作用。再一次注意,这些都需要在真实场景的负载模式下进行监控。

Gatling的模拟测试脚本是用Scala编写的,但该工具还附带了一个非常有用的图形界面,可用于记录具体的场景,并生成Scala脚本。

无论我们在单个实例中准备了多少硬件,都会有不够用的时候。简而言之,扩展有着天生的局限性,当系统遇到这些问题时,横向扩展是处理更多负载的唯一途径。这一步肯定会相当的复杂,但却是扩展应用的唯一办法。

威尼斯国际平台app 11

估计应用程序将创建的线程数。

有关不同垃圾收集器的更多信息,请查看这个 指南 。

Gatling是进行负载测试最好的工具之一,它提供了对HTTP协议的支持,是HTTP服务器负载测试的绝佳选择。

避免递归

JDBC批处理

我们还将看到一些常见的Java代码优化方法以及最佳编码实践。最后,我们将看看用于提升Java应用程序性能的JVM调优技巧和架构调整。

威尼斯国际平台app 12

这些指标可以通过使用多种监视工具监测到,它们对分析性能瓶颈和性能调优有着非常大的作用。

堆大小的调优

当然,在应用的拓扑结构中引入一个独立的缓存系统确实会增加架构的复杂度,所以,应当充分利用当前使用的库和框架现有的缓存功能。

威尼斯国际平台app 13

横向扩展

性能指标

在我们的这个例子中,具体的场景将是“启动200个用户,每个用户发出一万个请求。”

在运行时可能会加载多少个Java类,包括第三方API的类?

Retrace会自动监控应用程序,并跟踪数十种常见框架及其依赖关系的使用情况,包括SQL、MongoDB、Redis、Elasticsearch等等。Retrace能帮助我们快速确定应用程序为什么会出现如下性能问题:

结论

下面这个例子是一个简化了的但却很典型的循环。前面使用了原始的连接方式,后面使用了构建器:

要使用Retrace进行Java应用程序的开发,首先需要在Stackify上申请免费试用账号。然后,将我们自己的Spring Boot应用程序配置为Linux服务。我们还需要在托管应用程序的服务器上安装Retrace代理,按照这篇文章所述的操作即可。

无论我们在单个实例中准备了多少硬件,都会有不够用的时候。简而言之,扩展有着天生的局限性,当系统遇到这些问题时,横向扩展是处理更多负载的唯一途径。这一步肯定会相当的复杂,但却是扩展应用的唯一办法。

下面这个例子是一个简化了的但却很典型的循环。前面使用了原始的连接方式,后面使用了构建器:

只要底层的JDBC驱动程序支持,你就可以在客户端(驱动程序)或数据库端(语法树甚至执行计划)中缓存PreparedStatement。

因此,像Retrace这样功能全面的监控工具是解锁应用程序性能潜力的第一步。而第二步则是在你的系统上重现真实使用场景和负载。

在运行模拟脚本之后,Gatling会生成一份非常有用的、可用于分析的HTML报告。

例如,大多数的持久化框架都支持缓存。 Spring MVC等Web框架还可以使用Spring中内置的缓存支持,以及基于ETags的强大的HTTP级缓存。

JDBC性能

负载测试和应用程序监控对于确定应用程序的一些关键性能瓶颈非常有用。但同时,我们需要遵循良好的编码习惯,以避免在对应用程序进行监控的时候出现过多的性能问题。

找出性能瓶颈

某个SQL语句是否会拖慢系统的速度?

为生产系统确定合适的JVM堆大小并不是一件简单的事情。要做的第一步是回答以下问题以预测内存需求:

Redis突然变慢了吗?

上面代码中使用的StringBuilder对性能的提升非常有效。请注意,现代的JVM会在编译或者运行时对字符串操作进行 优化 。

在运行模拟脚本之后,Gatling会生成一份非常有用的、可用于分析的HTML报告。

语句缓存

Stackify的Retrace是一个成熟的APM解决方案。它的功能很丰富,对确定应用程序的性能基线很有帮助。 Retrace的关键组件之一是它的代码分析功能,它能够在不减慢应用程序的情况下收集运行时信息。

以下是典型Web应用程序常用的一些性能指标:

正则表达式在很多场景中都非常有用,但它们往往具有非常高的性能成本。了解各种使用正则表达式的JDK字符串方法很重要,例如String.replaceAll()、String.split()。

要执行负载测试,请运行以下命令:

为生产系统确定合适的JVM堆大小并不是一件简单的事情。要做的第一步是回答以下问题以预测内存需求:

Stop-the-world(STW)垃圾收集的周期是影响大多数面向客户端应用程序响应和整体Java性能的大问题。但是,目前的垃圾收集器大多解决了这个问题,并且通过适当的优化和大小的调整,能够消除对收集周期的感知。

缓存

语句缓存是另一种提高持久层性能的方法,这是一种鲜为人知但又容易掌握的性能优化方法。

除了能够提升Java的性能,通过集群进行横向扩展也有其他的好处,添加新的节点能产生冗余,并更好的处理故障,从而提高整个系统的可用性。

JVM调优 堆大小的调优

使用StringBuilder来连接字符串

在启动记录器之前,我们需要定义一个场景,表示用户在浏览Web应用时发生的事情。

避免递归

负载测试工具和应用程序性能管理(APM)解决方案常用于跟踪和优化Java应用程序的性能。要找出性能瓶颈,主要就是对各种应用场景进行负载测试,并同时使用APM工具对CPU、IO、堆的使用情况进行监控等等。

以下是典型Web应用程序常用的一些性能指标:

$GATLING_HOME/bin/gatling.sh-sbasic.EmployeeSimulation

规模的缩放

Gatling 是进行负载测试最好的工具之一,它提供了对HTTP协议的支持,是HTTP服务器负载测试的绝佳选择。

根据“Gatling的第一步”所述,用下面的代码创建一个名为EmployeeSimulation的scala文件:

Gatling负载测试

语句缓存

  • 计划要把多少个不同的应用程序部署到单个JVM进程中,例如EAR文件、WAR文件、jar文件的数量是多少?
  • 在运行时可能会加载多少个Java类,包括第三方API的类?
  • 估计内存缓存所需的空间,例如,由应用程序(和第三方API)加载的内部缓存数据结构,比如从数据库缓存的数据、从文件中读取的数据等等。
  • 估计应用程序将创建的线程数。

如果应用程序使用了大量的线程,那么使用线程池会更加有用,因为线程池允许这些昂贵的对象被重用。

架构改进 缓存

威尼斯国际平台app 14

在这篇文章中,我们将讨论几个有助于提升Java应用程序性能的方法。我们首先将介绍如何定义可度量的性能指标,然后看看有哪些工具可以用来度量和监控应用程序性能,以及确定性能瓶颈。

Retrace还提供了监视基于JVM应用程序的内存、线程和类的小部件。除了应用程序本身的指标之外,它还支持监视托管应用程序的服务器的CPU和IO使用情况。

Stackify的 Retrace 是一个成熟的APM解决方案。它的功能很丰富,对确定应用程序的性能基线很有帮助。 Retrace的关键组件之一是它的 代码分析 功能,它能够在不减慢应用程序的情况下收集运行时信息。

JVM调优

正则表达式在很多场景中都非常有用,但它们往往具有非常高的性能成本。了解各种使用正则表达式的JDK字符串方法很重要,例如String.replaceAll()、String.split()。

定义场景

Retrace代理和要监控的Java应用程序启动后,我们就可以到Retrace仪表板上单击AddApp按钮添加应用了。添加应用完成之后,Retrace将开始监控应用程序了。

选择合适的垃圾收集器

本文由威尼斯国际发布于技术,转载请注明出处:编写高性能Java代码的最佳实践,如何构建高扩展

关键词:

上一篇:魅族今年还有3款新品,魅族终于亮王牌

下一篇:没有了

最火资讯