【问题标题】:spring mvc + wildfly + postgresql performance tunningspring mvc + wildfly + postgresql 性能调优
【发布时间】:2018-02-07 18:59:51
【问题描述】:

我花了很多时间试图找出导致我的应用程序运行缓慢的原因,也许有人会帮助我检查问题所在。

版本:

spring mvc: 4.2.5.RELEASE

hibernate: 4.3.11.Final

spring-data-jpa: 1.8.2.RELEASE

wildfly: 10

PostgreSQL Server: 9.4

OS: Debian GNU/Linux 7.9 (wheezy)

Server configuration: VPS, 1 proc, 4GB RAM

关于我的应用:

具有静态JSP 登录页面、信息页面和登录的简单Web 应用程序重定向到私人区域。公共页面是静态的,在登录期间首先查询数据库,然后尝试获取登录用户的内容。

有什么问题:

当我浏览配置如下的页面时:

<http auto-config="true"> 
        <intercept-url pattern="/" access="permitAll"/>
        <intercept-url pattern="favicon.ico" access="permitAll"/>
        <intercept-url pattern="/login/**" access="permitAll"/>
        <intercept-url pattern="/info" access="permitAll"/>
...
</http>

没有问题,一切都在他的飞行中加载,没有停顿。它工作顺利。 当我在 /login 上发帖(将我重定向到 /main),然后当我在每个配置如下的站点上导航时:

<intercept-url pattern="/main/**" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/statistic/**" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />

有时会出现一些极端的延迟,甚至长达 1 分钟。

休眠配置

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- Configure the entity manager factory bean -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="pl.portal.model"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="jpaProperties">
            <props>
                <!-- <prop key="hibernate.dialect">pl.portal.sql.ProjectPsqlDialect</prop> -->
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
                <prop key="hibernate.jdbc.use_streams_for_binary">false</prop>
                <prop key="hibernate.connection.useUnicode">true</prop>
                <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
                <prop key="hibernate.connection.characterSet">UTF-8</prop>

            </props>
        </property>
    </bean>

谁能给我一个提示如何确定导致延迟的原因?在我的浏览器中检查 webinspect -> /admin,大小 7,89KB,大小:54 秒(每个 js 或 css 不超过 100 毫秒)

编辑2: 删除了线程转储的无效片段,粘贴了在应用程序上调用操作/admin 后启动的线程的完整转储。线程耗时 61 秒

Thread dump

visualvm 控制台上的线程:

【问题讨论】:

  • 一种廉价的方法来发现它在等待你的一个缓慢响应时执行 Java 线程转储。执行慢速操作的线程可能会显示一个长堆栈跟踪,指向应用程序的慢速部分。
  • 另一种相对便宜的方法是使用 VisualVM 和线程采样 (dzone.com/articles/visualvm-12-great-java)。顺便提一句。在linux上做线程转储可以通过kill -QUIT YOUR_PROCESS_PIDjstack YOUR_PROCESS_PID实现。
  • 顺便说一句。如果这是一个新项目,我强烈建议摆脱旧的和泄漏的 DBCP 并使用 HikariCP(或至少切换到 DBCP2)。
  • 使用visualVM分析什么是耗时的。
  • 您可以使用VisualVM来监控线程状态(所有线程同时)。在线程选项卡中,如果您看到一些红色区域,则表示您的线程已被阻止。一看到你的线程长时间处于阻塞状态就做一个线程转储并分析一下。

标签: performance hibernate spring-mvc optimization wildfly


【解决方案1】:

造成这种延迟的原因有很多,下面列出了一些最常见的原因。

  1. 线程正在等待锁定。
  2. 数据库性能问题。
  3. CPU 密集型任务。
  4. 网络延迟
在您的情况下,可以排除网络服务器和客户端之间的

网络延迟,因为您提到静态页面和页面资源(如 CSS)的服务器响应时间以毫秒为单位。

对于其余的事情,像 VisualVM 这样的远程管理系统是找出导致延迟的原因以及哪个进程占用大量 CPU 时间的最佳工具。您也可以使用 JProfiler 之类的商业分析器,但 VisualVm 也可以完美地完成这项工作。

要连接到 ViusalVM,您需要有权访问您的服务器并在 JAVA_OPTS 或任何您的选项中添加 JMX options 并重新启动 Web 应用程序。

等待锁定的线程 - 可能有一段代码你有一个同步方法来锁定静态字段。如果该方法假设处理数据库查询大约需要 5 秒。并且有 10 个请求排队。那么最后一个请求将在 50 秒或更长时间内处理完毕。

如何检测这种瓶颈情况?

你可以通过代码找出所有获取锁的地方并添加一些调试日志。但是,如果问题不在您的代码中并且可能来自某些第三方库怎么办?

我曾经遇到过这样一种情况,当日志文件翻转时,Logger(log4j 库)会阻塞所有线程(大约 10 秒)。代码审查无法检测到这种情况。

分析器来救援。 VisualVM 可能是检测由线程锁定引起的延迟的最佳分析器。这是你可以做的。

  1. 监控线程。
  2. 当您看到许多线程处于阻塞状态时。
  3. 进行线程转储。
  4. 分析线程转储以查看导致此问题的函数并相应地解决问题。

CPU 密集型任务 - 如果一个进程占用大量 CPU 时间,它也可能导致延迟。同样,您可以使用 VisualVM 的 sampler 并找出哪个线程占用的 CPU 时间最多。

希望这能帮助您找到延迟的原因!

【讨论】:

  • 我已经编辑了我的问题,从需要很长时间的线程中提供线程转储。我不知道怎么读:/
  • @Mithrand1r。怎么知道这是耗时最长的线程?您能否在外部链接中附上完整的线程转储。此外,您可能必须在需要大量时间的请求中添加更多日志。例如,在您收到请求时、在 DB 调用之前、在您从 DB 获得响应之后、在您发回响应之前添加一个日志。使用这些日志条目中的时间戳,您将能够确定哪个部分花费的时间最多。
  • 我可以从附加的单线程线程转储中得知 - 线程在线程转储时正在读取 JDBC 查询的响应。也许数据库查询占用了很多时间。
  • 检查了线程转储,一切看起来都很好。当线程任务完成时,您似乎已经进行了线程转储。由于您在编辑中提到的线程处于等待状态而不是可运行状态。
  • 你能添加一些我之前提到的日志吗?在各个点添加日志,例如。就在调用“/admin”请求方法之后。在任何 IO 操作之前和之后,例如数据库查询。就在将您的方法的响应发送回浏览器之前。确保每个日志条目都有一个时间戳。您可以对其进行分析以查看哪个区域花费的时间最多,并缩小对该区域的关注。例如,在您执行数据库查询之前,时间戳为 13:00:00,而在获得该查询的响应后,时间戳为 13:01:00(1 分钟),这是有问题的。
【解决方案2】:

关于如何分析性能,您可以重点关注几个方面:

  1. 数据库
  2. 网络
  3. 应用层
  4. 内存

监控 DB 很简单,可以使用 RDBMS 监控工具,例如 Query Monitor for DB2 或其他取决于供应商的工具。

分析 BNetwork,有许多不同的工具,但您需要做的是弄清楚您的延迟是多少,以及您的网络速度是多少。

我相信我们可以假设在您的情况下,网络是好的,或者至少不太可能出现问题。

要分析的第三件事是您的应用程序层,这是您需要适当的分析工具的地方。您可以使用免费的且随 jdk 一起提供的 visualVM,或者您也可以使用付费的 yourkit。但是你可以得到一个试用版。

您还可以使用分析工具分析内存。

执行 CPU 采样 后,您将能够找出您的应用程序的哪些区域导致了延迟。 Yourkit 还能够从应用程序层监控执行的 SQL。这样,您将在一次测量中获得 SQL 速度 + 执行它的延迟 + 传输结果集的时间。

常见的性能调整选项有:

休眠。使用批处理加载集合,不要加入关系,而是支持 FetchStrategy.SELECT。

确保您不执行任何笛卡尔积等。

【讨论】:

    【解决方案3】:

    根据我的经验,您可能有数据库锁定问题。有一个 sql 将您的表锁定了一段时间。您的代码正在等待,然后锁被释放,您的代码继续。您可以monitor db locks 来查找在您的代码挂起时哪个 sql 锁定了您的表。

    【讨论】:

      【解决方案4】:

      服务器配置:VPS、1 个进程、4GB RAM

      您可以访问服务器吗?也尝试运行 top 命令并查看 CPU 使用率。您只有一个 proc,也许正在运行一些巨大的东西。

      开始查找性能问题的典型方法:

      条件 1 你可以连接 profiler 去做吧。 jvisualvm、jconsole、NetBeans Profiler、perf 等。

      1. 使用探查器连接到您的流程;
      2. 运行你认为慢的任务等待;
      3. 保存分析器结果以进行分析;

      您应该注意总 CPU 时间。

      条件 2 无法连接 profiler

      是的,在这里您可以使用 jstack 来获取线程转储。 jps 获取java进程ID。

      1. 准备 cmd/bash;
      2. 运行 jps 并找到您的进程 pid,记住;
      3. 运行你认为很慢的任务;
      4. 多次运行jstack并保存输出(jstack pid > output.1、jstack pid > output.2等);
      5. 分析所有结果并查看最常用的方法。

      不要进行预优化,先测量性能。 :)

      UPDATE获取新信息后的答案。

      在Thread dump中你可以看到很多“sun.nio.ch.EPollArrayWrapper.epollWait”,试着看一些链接:

      也许是你的情况。 epoll 有一个错误。但现在也有类似的事情发生。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-10
        • 2018-01-29
        • 1970-01-01
        • 1970-01-01
        • 2021-12-06
        • 1970-01-01
        • 2017-08-19
        • 2019-11-14
        相关资源
        最近更新 更多