应公司需求我们对一个项目进行了线上压力测试,结果发现,三台服务器一共只有59TPS,结果惨不忍睹。
那么针对这样的场景,我们利用一周时间进行专注性的优化,寻找性能的瓶颈点。
第一步:我们针对线上的环境进行模拟,尽量真实的在测试环境中再现,采用数据库连接池为咱们默认的C3P0。
那么当压测到二万批,100个用户同时访问的时候,并发量突然降为零!报错如下:
Could not get JDBC Connection; nested exception is java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
针对以上错误跟踪C3P0源码,以及在网上搜索资料(http://blog.sina.com.cn/s/blog_53923f940100g6as.html)发现,C3P0在大并发下表现的性能不佳。
第二步:针对这个问题进行数据库连接池优化,更换了BoneCPDataSource,以及Apache BasicDataSource后,发现报错如下:
java.lang.OutOfMemoryError: unable to create new native thread, dubbo version: 2.5.4, current host: 192.168.122.1 java.lang.OutOfMemoryError: unable to create new native thread
第三步:由此可以判断,问题不在于连接池的问题,于是在压测的时候,将DUMP日志导出进行分析发现,项目中启动了一万多个线程,而且每个线程都极为忙碌,彻底将资源耗尽。
于是迅速定位到代码,发现如下代码:
private static final ExecutorService executorService = Executors.newCachedThreadPool(); /** * 异步执行短频快的任务 * @param task */ public static void asynShortTask(Runnable task){ executorService.submit(task); //task.run(); } CommonUtils.asynShortTask(new Runnable() { @Override public void run() { String sms = sr.getSmsContent(); sms = sms.replaceAll(finalCode, AES.encryptToBase64(finalCode, ConstantUtils.getDB_AES_KEY())); sr.setSmsContent(sms); smsManageService.addSmsRecord(sr); } });
那么问题到底在哪里呢???就在这一行!
private static final ExecutorService executorService = Executors.newCachedThreadPool();
在并发的情况下,无限制的申请线程资源造成性能严重下降,在图表中显抛物线形状的元凶就是它!!!那么采用这种方式最大可以产生多少个线程呢??答案是:Integer的最大值!看如下源码:
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }
那么尝试修改成如下代码:
private static final ExecutorService executorService = Executors.newFixedThreadPool(50);
修改完成以后,并发量重新上升到100以上TPS,但是当并发量非常大的时候,项目GC(垃圾回收能力下降),分析原因还是因为 Executors.newFixedThreadPool(50)这一行,虽然解决了产生无限线程的问题,但是
当并发量非常大的时候,采用newFixedThreadPool这种方式,会造成大量对象堆积到队列中无法及时消费,看源码如下:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
可以看到采用的是无界队列,也就是说队列是可以无限的存放可执行的线程,造成大量对象无法释放和回收。
结论:
目前我们的项目还在持续优化中,还没有最终优化完成,目标是要把项目优化完善,但此次事件,再次提醒我们,在使用线程池的时候,一定要把握其细节,深入了解其原理再使用,不要随意使用,任何线程池的使用方式都有不同的使用场景,并不是只要使用了线程池就万事大吉,还有很多工作需要我们去注意。
相关推荐
一个Sqrt函数引发的血案-博文代码 博文地址:
### 由掩码地址设置不当,引发的血案(网络访问故障) 在现代网络环境中,子网掩码的正确配置对于确保数据包能够准确无误地传输至目标位置至关重要。本文将详细介绍一个由子网掩码设置不当所引发的网络访问故障案例,...
而"一个输入框引发的血案"这个标题似乎暗示了一个关于用户输入的安全性问题,这在Web开发中是一个极其重要的主题。在Python中,对用户输入的不当处理可能导致各种安全风险,如SQL注入、跨站脚本(XSS)攻击等。 ...
本文以一个实际案例"一条慢SQL引发的血案"为背景,探讨了如何诊断和解决慢查询问题。 首先,描述中提到的慢查询耗时达到了70秒,这对任何在线服务来说都是无法接受的,因为它可能导致整个网站瘫痪。这个查询的执行...
今天,我们就来谈谈这台电脑,以及它如何在一对父子之间引发了一场“血案”,当然,这里的血案仅仅是一个比喻,指的是一场因为电脑使用权而引发的“战争”。 小明是一名初中二年级的学生,和大多数同龄人一样,对...
理发师手中的剃刀如同一场悲剧的开始,它宣告着一段岁月的结束。父亲只能静静地看着,那些曾经在指尖缠绵的发丝,如今一一落入命运的裁决。每个理发的过程,都是父亲与孩子之间无声的告别。 文章将理发的过程比喻成...
一条看似简单的SQL语句,若未经充分优化,就有可能成为系统性能的瓶颈,甚至引发所谓的“血案”——即一系列由于性能问题导致的严重后果。本文将通过四个真实的案例,深入探讨与SQL优化相关的各个方面,以期揭示其...
一条SQL引发的“血案”:与SQL优化相关的个案例(文末送书).docx
sql学习 全局临时表案例1_统计信息引发性能血案.sql
在本文中,主要探讨了Nginx服务器配置中关于404错误页面的正确设置方法,以及一个关于等号引发的配置错误案例。这个案例表明了配置细节对于网站SEO(搜索引擎优化)的重要性,并解释了为什么自定义404错误页面是提高...
本讲主要涉及《左传》中的一则故事——郑伯克段于鄢,同时介绍了《春秋》及“三传”的基本概念,以及先秦时期的宗法制度和继承制度。 《春秋》是由鲁国史官编撰的一部编年史,以年、季、月、日记录当时各国的重大...
在IT领域,数据库管理是至关重要的任务,而细小的疏忽可能会引发严重的后果。本文主要探讨了在Oracle数据库中,一个看似微不足道的空格如何可能导致一系列问题,特别是当它出现在SQL语句的注释中时。这个问题在11.2....
题目中提到的"血案"实际上是一个关于`Integer`对象相等性比较的陷阱。在Java中,`Integer i01 = 59`这样的语句会触发装箱操作,将`int`值59转换为`Integer`对象。当进行`i01 == i02`的比较时,如果`i02`是一个`int`...
企业必须对可能引发品牌形象损害的行为保持警惕,及时发现并处理潜在问题,以避免短期或长期的品牌损害。 2. 品牌形象修复:品牌形象一旦受损,需要时间和恰当的策略来修复。欧典品牌损害被认为是短期的,主要依赖...
1. 硬件故障诊断:文档中提到产品返回的主要问题之一是液晶屏漏液,这通常是因为液晶屏表面受到外力影响导致的。这种问题的诊断相对直观,需要检查屏幕是否有明显的物理损伤,并考虑产品在运输和使用过程中可能遭受...
这个程序段没有同步问题,但存在一个特定情况下的问题:当`work`设置为100时,`num`会首先达到100,而`sum`还在99,导致在高电平结束后立即进入低电平,而不是等待完整周期。这同样会影响实际占空比,使其不等于...