生产环境典型问题实录第二期

这篇具有很好参考价值的文章主要介绍了生产环境典型问题实录第二期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

生产环境典型问题实录第二期

  • 往期回顾
    • 第一期 : https://mp.weixin.qq.com/s/Vm7-k2pbpdkw2ZWFzl0-Hg

案例六:方法体内部创建线程池

"pool-2494-thread-1" prio=10 tid=0x00007f885014c800 nid=0xc06d waiting on condition [0x00007f86d20fe000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000608e437c8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)
   Locked ownable synchronizers:
	- None
  • 线程名称pool-2494-thread-1透露出来的信息是这已经是第2494个线程池,每个线程池里只有1个线程。
  • WAITING表示这个线程池的任务队列为空,所以阻塞在LinkedBlockingQueue.take方法上。
  • 线程池数量已经到2000多个,基本上可以说明这个线程池是在方法内部创建的;线程数量是1,大概率是调用的Executors.newSingleThreadExecutor; 阻塞在LinkedBlockingQueue.take上,说明这个线程池用完后没有关闭。
  • 总结:不建议在方法内部创建私有的线程池,这个等同于在方法内部创建线程,并发量高的时候,线程数会暴增,可能出现OOM:Unable to create new thread,而且大量的线程并不会带来性能的提高,相反由于上下文切换反而会带来性能损耗,就好比只有两个核酸检测人员(两核),你排成2000条队(2000个线程),并不能提高核酸检测效率,还会由于2000条队列的调度拖慢效率。

案例七:慎用反射

反射调用是一个较慢的操作,通过Class.forName进行反射调用时,会调用ClassLoader.loadClass,这是一个synchronized的方法,在并发量大时,会出现严重性能瓶颈。

    final Class<?> loadClass(Module module, String name) {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                c = findClass(module.getName(), name);
            }
            if (c != null && c.getModule() == module) {
                return c;
            } else {
                return null;
            }
        }
    }

我们常用的两个框架logbackhibernate也是反射的重度使用者。

  • logback在输出日志时如果要输出jar包名称,会调用PackageDataCalculation进行反射调用,建议关闭此特性。
    • 参考 https://jira.qos.ch/browse/LOGBACK-730
"qtp1747988071-86163" prio=10 tid=0x00007f8bd809d800 nid=0x193e7 waiting for monitor entry [0x00007f8b2bd7a000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:390)
	- waiting to lock <0x0000000731400000> (a org.eclipse.jetty.webapp.WebAppClassLoader)
	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:383)
	at ch.qos.logback.classic.spi.PackagingDataCalculator.loadClass(PackagingDataCalculator.java:207)
  • 通过hibernate写hql时,hibernate需要大量使用反射来将数据库表、字段与PO、属性进行反射调用,在hibernate3.X版本中有严重性能问题,hibernate5.X做了优化。
    • 参考 https://hibernate.atlassian.net/browse/HHH-4959
"qtp1884473012-36570" prio=10 tid=0x00007ff7d8323000 nid=0x134a waiting for monitor entry [0x00007ff7275b2000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:390)
	- waiting to lock <0x00000007315a3620> (a org.eclipse.jetty.webapp.WebAppClassLoader)
	at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:383)
	at org.hibernate.util.ReflectHelper.classForName(ReflectHelper.java:95)
	at org.hibernate.impl.SessionFactoryImpl.getImplementors(SessionFactoryImpl.java:683)
	at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1543)
	at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:283)
  • 总结 : 反射调用时在评估一下调用次数,超过一定量会引起系统锁竞争爆发,大量线程Block。

案例八:线程池需考虑任务队列大小和拒绝策略

在使用线程池时,会使用阻塞队列BlockingQueue做为其任务队列。

  • ArrayBlockingQueue必须设置其固定大小,有使用者误以为其capacity类似于ArrayListinitialCapacity,其实不然。ArrayBlockingQueue是固定大小的,不是像ArrayList会动态扩容。
  • BlockingQueue及其子类应该都是固定大小的,不排除有些自定义的BlockingQueue可以动态扩容。
  • BlockingQueue的容量大小(capacity)要考虑内存占用和任务的消费速度,既要避免内存占用过多导致OOM,也要考虑队列容量过小导致系统阻塞。
"qtp1975260912-1059" - Thread t@1059
   java.lang.Thread.State: WAITING
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for <4a3136f1> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at java.util.concurrent.LinkedBlockingQueue.put(Unknown Source)
	at com.thunisoft.summer.component.ssoserver.asyn.LogRecordWriterImpl.writeLog(LogRecordWriterImpl.java:49)
  • 线程池的拒绝策略不要选择DiscardPolicyDiscardPolicy不会更新Future的任务状态,导致后续调用Future.get会无限阻塞。
    • 推荐使用AbortPolicy或者给Future.get设置超时时间。
    • 参考 https://mp.weixin.qq.com/s/2VEGYqIHhlG7l-9CZUP9qg

案例九:读写锁,需考虑写锁的耗时

java提供了读写锁ReentrantReadWriteLock,读锁与读锁之间互相不阻塞,读锁与写锁、写锁与写锁之间阻塞,因此在使用写锁时要考虑写锁的阻塞耗时,尽量不要超过1秒,避免写锁阻塞时间过长,导致系统无响应。

Thread 102250: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
 - java.lang.Object.wait() @bci=2, line=485 (Compiled frame)
 - EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock$ReaderLock.acquire() @bci=34 (Compiled frame)
 - com.thunisoft.summer.util.cache.AbstractCacheImpl.readLock() @bci=7, line=34 (Compiled frame)
 - com.thunisoft.summer.component.config.sysConfig.SysConfigCache$$EnhancerByCGLIB$$9bf9c44$$FastClassByCGLIB$$ec264ca4.invoke(int, java.lang.Object, java.lang.Object[]) @bci=723 (Compiled frame)

案例十:不要用System.out.println

System.out 用的是PrintStream,其println源码如下:

public void println(boolean x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

可以看到printlnsynchonzied方法,当并发较大或者往控制台输出信息过多时,其方法就阻塞住。文章来源地址https://www.toymoban.com/news/detail-422425.html

  • 总结
    • 不要显式调用System.out。注:sonar可以检查出来。
    • 使用logback时,生产环境不要使用ConsoleAppender,其内部就是System.out
    "qtp1349006843-290" - Thread t@290
       java.lang.Thread.State: BLOCKED
    	at java.io.PrintStream.write(PrintStream.java:429)
    	- waiting to lock <58526d71> (a XXX.server.module.log.TASPrintStream) owned by     "qtp1349006843-36" t@36
    	at XXX.server.module.log.TASPrintStream.write(TASPrintStream.java:55)
    	at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
    	at ch.qos.logback.core.joran.spi.ConsoleTarget$1.write(ConsoleTarget.java:36)
    	at ch.qos.logback.core.encoder.LayoutWrappingEncoder.doEncode(LayoutWrappingEncoder.java:135)
    	at ch.qos.logback.core.OutputStreamAppender.writeOut(OutputStreamAppender.java:194)
    	at ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:219)
    	at ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:103)
    	at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:88)
    	at ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:48)
    

到了这里,关于生产环境典型问题实录第二期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ForkJoinPool在生产环境中使用遇到的一个问题

    在我们的项目中有这么一个场景,需要消费 kafka 中的消息,并生成对应的工单数据。早些时候程序运行的好好的,但是有一天, 我们升级了容器的配置 ,结果导致部分消息无法消费。而消费者的代码是使用 CompletableFuture.runAsync(() - {while (true){ ..... }}) 来实现的。 即: 需要消

    2024年03月24日
    浏览(26)
  • k8s集群生产环境的问题处理

    2 k8s上的服务均无法访问 执行命令 kubectl get pods -ALL ,k8s集群中的服务均是running状态 1 kuboard 网页无法访问 kuboard无法通过浏览器访问,但是查看端口是被占用的

    2024年02月12日
    浏览(32)
  • 宿主机无法连接docker里的redis问题解决(生产环境慎用)

    1.连接超时 2.连接能连上但马上断开并报错 3.提示保护模式什么的 链接redis 时只能通过本地localhost (127.0.0.1)这个来链接,而不能用网络ip(192.168…)这个链接 1.打开配置文件把下面对应的注释掉 2.Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进

    2024年04月13日
    浏览(49)
  • 记1次生产环境java进程内存泄漏问题定位(使用Arthas)

    简介 | arthas, Alibaba 开源的 Java 诊断工具,参照文档安装使用很简单,在线下载或者离线下载后解压运行,启动arthas-boot.jar,会自动扫描jps进程,根据序号选择后进入arthas界面: 常用的是dashboard,thread命令,dashboard命令能扫面当前java进程的全局信息,包括堆栈和线程信息,

    2024年02月22日
    浏览(42)
  • K8s 生产环境问题汇总及解决方案(持续更新 ing)

    目录 一、前端页面显示 503 Service Temporarily Unavailable 问题背景 解决方案 原理 二、Dockfile 构建镜像失败:When using COPY with more than one source file, the destination must be a directory and end with a /  问题背景 解决方案 原理 三、前端页面显示 502 Bad Gateway 问题背景  解决方案 原理 时间:2

    2024年02月02日
    浏览(31)
  • uni-app的h5/小程序/app 网络请求,解决本地环境和生产环境网络请求问题

    本篇的重点在于解决h5/小程序/app这三端在本地和生产环境的网络请求问题 全部代码贴在了全文最后 首先要理解这三个端的特性,h5会有跨域问题需要反向代理,小程序和app不需要反向代理,同时小程序还得用https域名。 一般会跨域需要反向代理。所以要在mainifest.json设置反向

    2024年02月10日
    浏览(43)
  • Win10 python环境测试selenium加IE浏览器自动化-踩坑实录

    【背景】 需要访问某个旧网址,仅支持IE浏览器访问。为了实现自动化,被迫采用python加selenium、加IE浏览器来做。 【实录】 selenium采用IE浏览器方式的资料不多,网上可供参考范例不多。以下实时记录整个过程,实现调通一个基本访问实例。 【第一步】安装正确版本的sele

    2024年01月21日
    浏览(59)
  • 阿里云图片上传返回地址有blob格式问题处理实录

    2.1根据上传返回响应状态 2.2调用GetObject接口获取下文件的大小     阿里云OSS上传图片功能很多人可能对实现过,正常情况下会返回https开头的图片地址.但是今天业务系统中运营人员反应上传的合同详情页面打开异常,看过服务端的日志之后发现用户上传的图片地址带有blob,线

    2023年04月21日
    浏览(33)
  • 若依(ruoyi)开源系统-多数据源问题踩坑实录

    上一节内容   介绍了用开源系统若依(ruoyi)搭建页面的过程。在实际项目中,经常遇到多数据源后者主从库的情况。本节记录若依多数据源配置过程中遇到的问题排查过程。 1.上一节在ry-vue库中新建了表t_user,这次新建数据库jingyes,新加同样的表t_user。其他功能不变,我们将

    2024年02月08日
    浏览(29)
  • 数学建模软件及算法模型典型问题汇总

    一、 软件篇 编程 、MATLAB(物理建模)、python(数据分析)、R、其他(SPSS、Stata、Origin) 这里其实还有一个 Lingo 软件,不过我不推荐,有更好的替代方案,就是 Yalmip 工具箱+OPTI 工具箱+gurobi 求解器,Yalmip 是基于 matlab 的求解规划问题的高级建模语言,OPTI 提供众多 开源的规

    2024年04月17日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包