服务第一次访问卡顿

数据库连接池 数据库连接池的目的是为了减少频繁开关连接的时间,提高整个系统的响应能力。 基本设置: 初始大小 扩容的大小 最大连接个数 空闲死亡时间 目录DBCPC3P0DruidHikariCP DBCP 属于 apache 在org.apache.commons.dbcp2。比较简单几乎没人用 需要导入3个jar包 commons-dbcp2-2.7.0\commons-dbcp2-2.7.0.jar... 阅读详情

一、问题分析

前段时间有同事和我说我们自测环境新增了几个小服务第一此访问的时候总是卡卡的,后面就好了,想让我排查一下。心里想了几种可能

  1. Apache代理服务器与后台服务器首次握手慢,后续请求复用长链接无卡顿现象。我们自测环境前端服务器用的是apache,配置了反向代理到后端小服务。如果客户端请求超过了代理服务器设置的最大链接数,当前请求时不会被转发到后台服务器的。
  2. 一个服务第一次被调用时会触发很多类的加载和初始化,但这个往往是第一次访问卡,后续访问就不卡了。因为类的卸载是比较苛刻的所以大多数类加载到jvm后等进程结束时才会被卸载。所以这种情况不会出现间隔性卡顿(即:第一次请求卡紧接着请求不卡,等半小时或一小时再请求又卡),仅仅第一次访问卡顿。
  3. 由于后台服务用到了数据库连接池、线程池、redis连接池可能由于参数配置不合理导致,链接长时间没被使用导致过期销毁。

首先尝试跳过代理服务器用postman直接访问后台服务器接口看是否可以复现,结果是复现了,那就排除了情况1。虽然看现象更贴近3,直接去排查连接池、线程池、redis连接池参数可能可以直接定位问题。但万一是这个后台服务器网络IO层面的问题呢?是为了避免忽略细节走弯路,首先要判断下这个请求是否能及时被服务端接收到。我用Arthas对这个后台服务进行一个监控,监控一下web层Handler方法执行时间。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

如上图可以发现postman方法执行耗时6s,而在labelStatics中调用了staticsService.staticsLabel()方法耗时5.7s,所以可以彻底排查服务器网络IO问题了,完完全全是服务本身问题(我干~~)。使用Arthas继续对调用链路进行追踪最后发现卡顿之处在与数据库交互的方法上。
查询数据库的业务代码块

然后我理所当然去监控了一下数据池获取数据库链接的DruidDataSource.getConnection()方法,果然罪魁祸首就是它。
Druid数据池获取数据库链接方法

至此我们已经定位到了卡顿原因,由于线程池参数配置有误导致线程失效。这个小服务还在开发阶段线程池的配置就是随便网上copy的如下。

spring.datasource.primary.url=****
spring.datasource.primary.username=***
spring.datasource.primary.password=***
spring.datasource.primary.driver-class-name=org.postgresql.Driver
spring.datasource.primary.max-active=50
spring.datasource.primary.initial-size=15
spring.datasource.primary.min-idle=0 

对于Druid数据池我也没有深入了解过仅仅知道简单参数配置,以及它是一个生产消费者模式的连接池,里面包含了创建连接线程、销毁连接线程、消费连接线程(请求对getConnection方法的调用)。也趁此机会翻了一下Druid数据池的源码,Druid数据池的源码帖子网上很多,这里只探讨下导致卡顿问题出现的源码部分。

先说结论:因为当前服务在自测环境调用方不多,且没有操作数据库的定时任务,在min-idle=0的情况下初始化的15个连接在半小时内如果没有被使用到将会被销毁连接线程销毁掉。

二、Druid销毁连接线程源码分析

Druid销毁连接线程为DestroyConnectionThread

 public class DestroyConnectionThread extends Thread {

        public DestroyConnectionThread(String name){
            super(name);
            this.setDaemon(true);
        }

        public void run() {
            initedLatch.countDown();

            while (true) {
                try {
                    if (closed) {
                        break;
                    }
                    // timeBetweenEvictionRunsMillis默认值为60s。即60s调用一次destroyTask.run();方法
                    // timeBetweenEvictionRunsMillis可以通过配置修改
                    if (timeBetweenEvictionRunsMillis > 0) {
                        Thread.sleep(timeBetweenEvictionRunsMillis);
                    } else {
                        Thread.sleep(1000); //
                    }

                    if (Thread.interrupted()) {
                        break;
                    }

                    destroyTask.run();
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }

看下核心逻辑destroyTask.run();

 public class DestroyTask implements Runnable {

        @Override
        public void run() {
        // 回收未被使用的连接逻辑
            shrink(true, keepAlive);
		// 如果remove-abandoned=true则会调用回收正在被使用的连接逻辑,防止出现代码逻辑出现死锁占用连接不释放的情况
            if (isRemoveAbandoned()) {
                removeAbandoned();
            }
        }

    }

引发我们卡顿的逻辑在shrink(true, keepAlive)中,连接尚未被使用就过期了。在分析这块代码之前先说一下Druid中有三个存放连接的关键数组:

  • connections[] 存放可以使用的连接,当有请求调用getConnection获取连接时就是从这里面取的。
  • keepAliveConnections[] 在DestroyConnectionThread在扫描connections[]中的连接进行回收时,满足某些条件的连接会被放入keepAliveConnections[]中后续会对keepAliveConnections[]中的连接进行有效性验证如果有效还可以复活更新其最后活跃时间并重新放入connections[]中,如果无效则关闭销毁连接
  • evictConnections[] 在DestroyConnectionThread在扫描connections[]中的连接进行回收时,满足某些条件的连接会被放入evictConnections[]中,后续全部关闭销毁。
 public void shrink(boolean checkTime, boolean keepAlive) {
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            return;
        }

        int evictCount = 0;
        int keepAliveCount = 0;
        try {
            if (!inited) {
                return;
            }
			// poolingCount为connections[]数组的有效长度,minIdle对应配置项中的min-idle,我们当前项目配置的0.所以checkCount=poolingCount。
            final int checkCount = poolingCount - minIdle;
            final long currentTimeMillis = System.currentTimeMillis();
            // 遍历connections[]中的连接
            for (int i = 0; i < poolingCount; ++i) {
                DruidConnectionHolder connection = connections[i];
				// 是否开始时间筛选,如果不开启则直接将连接回收到数量=min-idle
                if (checkTime) {
                // phyTimeoutMillis为连接的允许存活时间,默认为-1,如果配置了,只要 '当前时间-连接创建时间>phyTimeoutMillis' 则直接将连接添加到evictConnections[]数组中后续关闭
                    if (phyTimeoutMillis > 0) {
                        long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
                        if (phyConnectTimeMillis > phyTimeoutMillis) {
                            evictConnections[evictCount++] = connection;
                            continue;
                        }
                    }
					// idleMillis为连接的空闲时间
                    long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
					// 如果连接空闲时间小于minEvictableIdleTimeMillis最小空闲时间则不做处理,minEvictableIdleTimeMillis默认为半小时
                    if (idleMillis < minEvictableIdleTimeMillis) {
                        break;
                    }
					// 到这里说明当前连接 '空闲时间>minEvictableIdleTimeMillis',在这个项目中checkCount==poolingCount,
					// 'checkTime && i < checkCount'恒成立,所以只要空闲时间超过minEvictableIdleTimeMillis的连接就会被回收
					// 我吐了。我理解这个配置存在的意义是将空闲线程回收到数量=minIdle
                    if (checkTime && i < checkCount) {
                        evictConnections[evictCount++] = connection;
                    } else if (idleMillis > maxEvictableIdleTimeMillis) {
                    // 当 '空闲时间>maxEvictableIdleTimeMillis最大空闲时间' 时添加到evictConnections数组直接关闭,maxEvictableIdleTimeMillis的默认值是7小时
                        evictConnections[evictCount++] = connection;
                    } else if (keepAlive) {
                    // 当 'minEvictableIdleTimeMillis<空闲时间<maxEvictableIdleTimeMillis'且keep-alive=true
					// 时将连接添加到keepAliveConnections数组中进行后续有效性验证
                        keepAliveConnections[keepAliveCount++] = connection;
                    }
                } else {
                    if (i < checkCount) {
                        evictConnections[evictCount++] = connection;
                    } else {
                        break;
                    }
                }
            }
			// 要移除的连接总数
            int removeCount = evictCount + keepAliveCount;
            if (removeCount > 0) {
                System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
                Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
                poolingCount -= removeCount;
            }
            keepAliveCheckCount += keepAliveCount;
        } finally {
            lock.unlock();
        }
		// 关闭evictConnections[]数组中的连接
        if (evictCount > 0) {
            for (int i = 0; i < evictCount; ++i) {
                DruidConnectionHolder item = evictConnections[i];
                Connection connection = item.getConnection();
                JdbcUtils.close(connection);
                destroyCount.incrementAndGet();
            }
            Arrays.fill(evictConnections, null);
        }
		// 判断keepAliveConnections[]数组中的连接是否有效,如果有效更新其最后活跃时间lastActiveTime并放入connections[]数组中,无效的关闭连接
        if (keepAliveCount > 0) {
            this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
            // keep order
            for (int i = keepAliveCount - 1; i >= 0; --i) {
                DruidConnectionHolder holer = keepAliveConnections[i];
                Connection connection = holer.getConnection();
                holer.incrementKeepAliveCheckCount();

                boolean validate = false;
                try {
                    this.validateConnection(connection);
                    validate = true;
                } catch (Throwable error) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("keepAliveErr", error);
                    }
                    // skip
                }

                if (validate) {
                    holer.setLastActiveTimeMillis(System.currentTimeMillis());
                    put(holer);
                } else {
                    JdbcUtils.close(connection);
                }
            }
            Arrays.fill(keepAliveConnections, null);
        }
    }

至此我们彻底警情定位了问题所在就是我们Druid参数配置不合理导致的。

三、Druid 参数修改

然后我重新修改了Druid 参数,问题也是顺利解决

  • spring.datasource.druid.initial-size=15
    初始化连接数
  • spring.datasource.druid.max-active=100
    最大活跃连接数,包括池内和池外 max-active>=activeCount(池外) + poolingCount(connections数组的有效长度)
  • spring.datasource.druid.min-idle=15
    连接池内最小可用连接数,回收空闲连接时,将保证至少有minIdle个连接.
  • spring.datasource.druid.max-wait=60000
    获取连接超时的时间,即getConnection方法的超时时间
  • spring.datasource.druid.time-between-eviction-runs-millis=60000
    Druid销毁连接线程为DestroyConnectionThread的调用间隔
  • spring.datasource.druid.min-evictable-idle-time-millis=300000
    连接最小空闲时间
  • spring.datasource.druid.test-on-borrow=false
    如果为true则获取连接时会验证一下连接的有效性,生产环境开启影响性能
  • spring.datasource.druid.test-on-return=false
    如果为true则返回链接时会验证一下连接的有效性,生产环境开启影响性能
  • spring.datasource.druid.test-while-idle=true
    如果为true则获取连接时且当前连接的空闲时间>time-between-eviction-runs-millis时会验证连接的有效性,生产环境开启防止DestroyConnectionThread由于系统资源紧张得不到cpu执行时连接未被回收失效
  • spring.datasource.druid.validation-query=SELECT 1
    验证连接有效性时执行的语句
  • spring.datasource.druid.validation-query-timeout=1000
    验证有效性语句SELECT 1的超时时间,超过这个时间则认为无效
  • spring.datasource.druid.keep-alive=true
    对于空闲时间超过min-evictable-idle-time-millis的连接如果keep-alive为true时,则会调用validation-query对其进行验证并更新最后活跃时间保证连接池内最小可用连接数不小于 min-idle
  • spring.datasource.druid.remove-abandoned=true
    如果remove-abandoned=true则会调用回收正在被使用的连接逻辑,防止出现代码逻辑出现死锁占用连接不释放的情况
  • spring.datasource.druid.remove-abandoned-timeout=180
    设置druid 强制回收连接的时限,当程序从池中get到连接开始算起,超过此 值后,druid将强制回收该连接,单位秒。应大于业务运行最长时间
  • spring.datasource.druid.log-abandoned=true
    当druid强制回收连接后,是否将stack trace 记录到日志中
Druid各配置项生效原理 之前项目中排查由于Druid配置问题导致的生产事故的时候,对相关配置实际原理研究了一下,下面文章,讲的很清晰,但是对个别参数讲的不清晰。【历代文学】Druid连接池实战:搞懂6个参数,就能用好它_timebetweenevictionrunsmillis-优快云博客# 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时# 连接池最小空闲的连接数minIdle: 8。 阅读详情

相关推荐

金蝶K3 ERP 跨网段访问服务器卡顿问题排查和解决方法

摘要:某公司网络出现卡顿,通过抓包发现存在MAC欺骗,更换三层交换机并划分VLAN后解决了网络风暴问题。但金蝶K3ERP跨网段访问变慢,抓包分析显示TCP窗口值异常(Win=0)。解决方案是调整Windows的TCP自动调优级别为restricted模式,优化高延迟网络下的传输性能。具体操作为管理员执行netsh命令修改全局TCP参数,该模式能有效改善跨网段应用的响应速度,特别适用于远程桌面、文件传输等场景。同时建议服务器端启用RSS和ECN功能以进一步提升网络性能。

大IT职男日志 1081

Redis客户端配置优化建议

Redis客户端配置优化建议 Redis客户端配置项 参考spring-boot docs:data-properties.本篇以lettuce为例.着重讲连接池的配置. 配置项 默认值 描述 中文描述 spring.redis.lettuce.cluster.refresh.adaptive false Whether adaptive topology refreshing using all available refresh triggers should be used. re

过了这个村没这个老王的博客 7724

【mysql调优】数据库连接池配置优化

数据库连接池通过预先创建和管理数据库连接,优化服务性能。其核心原理是维护连接的复用机制,动态调整连接数,避免频繁创建/销毁连接的开销。配置需考虑并发量、DB规模等因素,关键参数包括最小/最大连接数、超时时间、心跳检测间隔等。建议关闭不必要的检测以减少负载,合理设置空闲时间(如90秒),优先使用ping命令检测。连接池优化可显著减少获取连接耗时,提升整体响应速度。

sysu_lluozh 7901

Jedis 连接池 详解

一. JedisPool的几个重要参数介绍 1. maxTotal 控制连接池里面最多构建多少个Jedis实例。请看下面代码 public static void main(String[] args) { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(2); JedisPool pool = new JedisPool(config,"172.29.2.10",7000); while(true) {

吉他程序员的博客 6227

华为EC6108V9E刷机实战:从U盘准备到开机优化的完整避坑指南

本文提供华为悦盒EC6108V9E刷机与优化的完整实战指南。针对搭载RK3228芯片和安卓4.4.4系统的设备,从型号确认、固件选择、U盘准备,到详细刷机步骤、常见故障排除,以及刷机后的深度性能优化,手把手帮助用户规避风险,让旧盒子焕发新生,成为流畅的全能媒体中心。

weixin_29324401的博客 1187

基于PaddleX的垃圾分类识别

基于PaddleX的智能垃圾分类识别项目,使用百度开源的PaddlePaddle深度学习框架,结合PaddleX开发套件,实现对垃圾分类的识别检测

Mefishes的博客 8116

网站系统卡顿(mysql 占用内存超过100%)解决办法

一.今天,运营突然反应网站特别卡,于是上服务器使用top查看如下: 可以看到服务器负载很高,,mysql CPU使用已达到接近400%(因为是四核,所以会有超过100%的情况)。 登录mysql后使用show processlist;命令查看如下: 发现Sending data(数据库查询)过多,但是sql的字段索引优化已经优化了,,,所以怀疑是请求过多,,,经询问,是一小伙伴在页面...

守护大白菜的博客 3390

西门子S7-200 SMART 实战解析:滑动平均值滤波算法在模拟量信号处理中的应用

本文详细解析了在西门子S7-200 SMART PLC中实现滑动平均值滤波算法的实战应用。通过处理模拟量信号如温度、压力等,该算法有效抑制信号干扰,提升系统稳定性。文章涵盖算法原理、程序框架、信号采集及调试优化,为工业自动化工程师提供实用指南。

gitlab7runner的博客 1151

客户端访问服务器网络卡顿问题处理

前几天室友的客户反馈云桌面客户机访问服务器网络卡顿,刚好那段时间比较空,就向室友了解了下情况并帮忙分析. 网络拓扑如下 客户端-核心交换机-服务器接入交换机-服务器 云桌面客户端和服务器为不同网段,网关均在核心交换机上。 室友已经做了初步的排查:在客户端上ping客户端网关没问题,延迟为1ms,没有丢包现象,访问服务器网段不规律丢包,在相关设备上查看过CRC和接口流量均正常,丢包现象和环路不符,但还是排查过环路问题,没有mac漂移的现象.并在核心上镜像抓包,和我说怀疑是arp和445端口的问题,可能

qq_33301336的博客 1847

微信小程序后台定位与实时位置更新的实战指南

本文提供了微信小程序实现后台定位与实时位置更新的完整实战指南。针对小程序退到后台后位置更新中断的痛点,详细解析了基于`startLocationUpdateBackground`API的后台定位解决方案。内容涵盖从隐私协议配置、项目权限声明,到授权、启动、监听、停止的核心代码流程,并分享了真机调试、性能优化及权限引导等关键避坑经验,帮助开发者构建稳定可靠的后台位置服务。

weixin_29008055的博客 466

SpringBoot多线程查询实战-查询库中所有数据多线程实现

但是,在数据量较大且服务器资源足够的情况下,多线程方法通常能够显著提高查询效率。此外,由于它是同步执行的,没有利用并行处理的能力,所以在处理大量数据时可能会比较慢。这个方法采用了分页查询的方式,每次只获取一部分数据,从而避免了内存溢出的问题。然而,它也是同步执行的,没有利用多线程或并行处理的能力。如果每次分页查询的数据量仍然很大,或者需要查询的轮数很多,那么这种方法的效率可能仍然会受到限制。​ ​ ​在比较这三种方式的效率时,我们需要考虑几个关键因素:数据量的大小、查询操作的复杂性、以及并行处理的能力。

勇敢牛牛,不怕困难! 4809

【已解决】linux ssh 远程连接服务器,出现登陆慢、打字卡顿输入卡顿解决方案

问题描述: 提示:这里可以添加学习目标 例如:一周掌握 Java 入门知识 解决方案: 提示:这里可以添加要学的内容 例如: 1、 搭建 Java 开发环境 2、 掌握 Java 基本语法 3、 掌握条件语句 4、 掌握循环语句 ...

idiot5lie的博客 4万+

DeepSeek+Cline:开启自动化编程新纪元

随着 AI 技术不断进步,编程领域迎来效率变革。DeepSeek 与 Cline 的结合,成为自动化编程的强大工具。DeepSeek 凭借先进的自然语言处理能力,能精准理解编程需求;Cline 作为 VSCode 插件,可实现代码生成、调试、注释等功能的无缝衔接。本文详细阐述二者安装配置、实战操作流程,涵盖从基础代码生成到复杂项目开发的应用技巧,同时解答常见问题,帮助开发者快速掌握这对 “智能搭档”,提升编程效率,解锁自动化编程的无限可能。

邓邓子的博客 6254

Deepseek 卡顿救星!五大免费访问方法超丝滑

最近,Deepseek 可谓是火爆全网,大家都被它强大的 AI 能力吸引,纷纷想要一探究竟。然而,官网却常常被挤得水泄不通,卡顿、掉线等问题层出不穷,让人头疼不已。别担心,今天就给大家分享几个无卡顿免费访问 Deepseek 的宝藏方法,让你轻松畅玩,不再被卡顿困扰!

hxsyyds49的博客 2183

基于STM32L4XX、HAL库的ICM-42670-P姿态传感器驱动程序设计

sprintf(buffer, "温度: %.1f °C\r\n\r\n", sensor_data.temperature);sprintf(buffer, "陀螺仪: X=%.2f Y=%.2f Z=%.2f rad/s\r\n",sprintf(buffer, "加速度: X=%.2f Y=%.2f Z=%.2f m/s²\r\n",sprintf(buffer, "开始校准IMU,请保持传感器静止...\r\n");sprintf(buffer, "读取传感器数据失败\r\n");

zhusl6688的博客 637

基于STM32的智能血氧、心率、体温、血压监测系统

摘要:本文设计了一款基于STM32F103C8T6的多功能健康监测系统,可实时检测血氧、心率、体温和血压四项生理参数。系统集成MAX30102、DS18B20等传感器模块,采用OLED显示和蓝牙无线传输技术,实现一键血压测量、阈值报警及手机APP数据管理功能。硬件设计包含传感器采集、电源管理、显示报警等模块;软件采用模块化架构,实现数据采集处理、蓝牙通讯等功能。测试表明系统测量准确可靠,为家庭健康监测提供了便携解决方案。未来可扩展更多监测参数和智能分析功能。

3254968421的博客 766

服务器为什么会卡顿,出现卡顿情况怎么办

服务器为什么会卡顿,出现卡顿情况怎么办

XRY_XIAO的博客 2921

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

服务器卡顿怎么办?如何处理

服务器如有出现卡顿的情况,就会影响游戏与网站的加载速度。一般情况下,用户访问网站或进游戏,业面如果长时间跳转不出,是不会继续等待,而是直接关闭。服务器稳定流畅的运行是至关重要的。造成服务器卡顿会的原因有很多,一般来说主要的是以下几个: 1.服务器中毒,服务器中毒服务器如果中毒的话,会导致服务器对外发包,耗尽带宽,造成卡顿。建议可以对服务器进行杀毒,清楚可疑文件 2.服务器访问量大,服务器如果访问量大,会造成带宽资源不足,带宽跑满占用过高造成线路拥堵,数据传输就会变得缓慢,建议可以升级带宽 3.服务器被

qq3007312960的博客 8313

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

服务器卡顿怎么办?怎么处理?

现在市场上,不管是网站或是游戏,运行流畅是最重要的。如果遇到服务器卡顿的情况,会造成用户访问网站或进游戏,网站页面长时间无法打开,游戏页面运行卡顿,这样就很容易会造成用户的流失,从而导致业务亏损极大,所以服务器稳定流畅的运行是至关重要的。...

dexun2881281453的博客 2261

应用部署在TongWeb出现访问的或者卡顿的现象!

应用部署在TongWeb出现访问的或者卡顿的现象! 1、分析原因: 这有可能是系统的DNS解析、hostname映射影响到了响应问题 2、查看hostname #hostname localhost.localdomain(这是系统默认主机名) 3、再去看/etc/hosts映射情况 #cat /etc/hosts 这里边默认是没有配置配内网ip和主机名的映射的! 4、那我们接下来配置下主机名和ip的映射关系! #vi /etc/hosts 5、修改文件/etc/sysconfig/netwo

Hand_Power的博客 2204

饥荒云服务器卡顿情况如何解决

基于德迅云构建的一个隔离的网络环境,专有网络之间逻辑上彻底隔离,只能通过对外映射的IP(弹性公网IP和NAT IP)互联。由于使用隧道封装技术对云服务器的IP报文进行封装,所以云服务器的数据链路层(二层MAC地址)信息不会进入物理网络,实现了不同云服务器间二层网络隔离,因此也实现了不同专有网络间二层网络隔离。并且可以按需选配,资源弹性扩容;此时,服务器的处理能力无法满足所有玩家的需求,造成游戏卡顿的现象。限制同时连接的玩家数量:通过设置服务器的最大连接数量,避免服务器过载,保证每个玩家都有流畅的游戏体验。

dexunjiaqiang的博客 2625

Samba映射本地windows服务器延迟卡顿解决方案

测试完毕后samba性能提高、无卡顿,亲测可用。

qq67709200的博客 3331

Java服务使用同步阻塞数据库访问导致系统卡顿的重构策略

Java服务使用同步阻塞数据库访问导致系统卡顿是一个常见的问题,但通过合理的重构策略,我们可以有效地解决这个问题,提高系统的性能和可用性。重要的是要理解问题的本质,并根据应用的具体情况选择最合适的重构策略。很多时候,我们的系统一开始运行良好,但随着用户量增长,数据库交互成为性能瓶颈,导致服务响应缓慢甚至卡顿。确认问题后,我们需要选择合适的重构策略。以下是一些常用的策略,它们可以单独使用,也可以组合使用,具体选择取决于应用的具体情况。选择合适的重构策略后,我们需要逐步实施重构,并验证重构的效果。

weixin_41455464的博客 1028

禅道刷新可以正常访问,等待1分钟后访问卡顿问题解决|edge/chrome访问卡顿,firefox访问正常

禅道部署到服务器后,VPN直接访问内网地址正常访问,nginx发布后,edge/chrome登录/刷新后可正常访问,约1分钟后访问必定卡顿,F12查看请求为pending状态。而firefox访问正常。

weixin_55525951的博客 1306

vscode用ssh连接服务器后,明明内存还很富足,为什么却很卡顿

vscode连接服务器运行程序时突然卡顿的问题解决过程

weixin_46129187的博客 4404

WHAT - 为什么 NAS 可以解决在访问资源卡顿问题

NAS 通过本地存储、局域网播放、流媒体优化和离线下载等方式,大幅降低了对互联网的依赖,从而解决了户外观影时因网络不稳定而导致的卡顿问题。

weixin_58540586的博客 1162
上一篇: SpringDataJPA+Hibernate框架源码剖析(五)框架整合 之 SpringBoot整合JPA剖析
下一篇: @Async错误使用导致Spring循环依赖报错
躺平程序猿
博客等级 码龄8年 4870粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值