当前位置: 首页 > news >正文

建个企业网站多少钱网站搜索引擎优化方案

建个企业网站多少钱,网站搜索引擎优化方案,政府网站app建设,做网站那里好一、前言 最近遇到了个log4j2写日志导致线程阻塞的问题(多亏了开发小哥日志打的多,不然就没有下面这一系列骚操作)。 大致描述下当时的情况(内网限制,没法把现场东西拿出来,只能口述了): log4j2配置情况: 同时配置了3个…

一、前言

  最近遇到了个log4j2写日志导致线程阻塞的问题(多亏了开发小哥日志打的多,不然就没有下面这一系列骚操作)。2.jpg

大致描述下当时的情况(内网限制,没法把现场东西拿出来,只能口述了):

log4j2配置情况: 同时配置了3个RollingRandomAccessFile,分别针对SQL语句、INFO日志、ERROR日志,大致的配置如下:

<RollingRandomAccessFile name="RandomAccessFile" fileName="${FILE_PATH}/async-log4j2.log" append="false"filePattern="${FILE_PATH}/rollings/async-testLog4j2-%d{yyyy-MM-dd}_%i.log.gz"><PatternLayout><Pattern>${LOG_PATTERN}</Pattern></PatternLayout><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true" /><SizeBasedTriggeringPolicy size="450MB"/></Policies><DefaultRolloverStrategy max="15" compressionLevel="0"/>
</RollingRandomAccessFile>

问题描述: 1、32C的机器压缩日志占用30%+的资源;2、tomcat主线程全部50%+都是park状态,线程状态大致如下;

image.png

当时针对log4j2给的优化建议是: 1、配置immediateFlush=false 2、将filePattern对应的gz后缀去掉(因为对应的compressionLevel=0,根本不压缩),是否就不会调用JDK的Deflater进行压缩。【猜测,也是后面还原现场的原因之一,想亲自验证一下】

二、本地复现&部分源码学习

  问题复现的过程也是蛮艰辛的,遇到各种问题。下面记录的是我本地复现时遇到的问题以及解决办法,附带一些log4j2基于disruptor的部分源码学习,篇幅可能会稍长。10.jpg

环境:Macbook Pro x86(16C32G)、jdk1.8、log4j-core 2.12.1、log4j-api 2.12.1、disruptor 3.4.2

测试代码(启动50线程不间断地写日志【现场系统涉及200个Tomcat线程】):

public class TestLog4j {private static Logger logger = LogManager.getLogger(TestLog4j.class);private final ThreadPoolExecutor executor;public TestLog4j() {this.executor = new ThreadPoolExecutor(50, 50,60, TimeUnit.SECONDS,new ArrayBlockingQueue(1000),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());}public void testLog() {for (int i = 0; i < this.executor.getCorePoolSize(); i++) {this.executor.execute(() -> {while (true) {logger.info("测试日志--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞" +"--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞" +"--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞--麻利麻利哄快阻塞");}});}}public static void main(String[] args) {new TestLog4j().testLog();}
}

部分log4j2.xml配置(将备份的压缩日志大小改小至100M,备份文件数量增加至100):

<appenders><RollingRandomAccessFile name="RandomAccessFile" fileName="${FILE_PATH}/async-log4j2.log" append="false"filePattern="${FILE_PATH}/rollings/async-testLog4j2-%d{yyyy-MM-dd}_%i.log.gz"><PatternLayout><Pattern>${LOG_PATTERN}</Pattern></PatternLayout><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/><Policies><TimeBasedTriggeringPolicy interval="1" modulate="true" /><SizeBasedTriggeringPolicy size="100MB"/></Policies><DefaultRolloverStrategy max="100" compressionLevel="0"/></RollingRandomAccessFile>
</appenders>
<loggers><!--disruptor异步日志--><AsyncLogger name="DisruptorLogger" level="info" includeLocation="false"><AppenderRef ref="RandomAccessFile"/></AsyncLogger><Asyncroot level="info" includeLocation="false"><appender-ref ref="RandomAccessFile"/></Asyncroot>
</loggers>

(一)线程阻塞-Blocked

  一切准备就绪,点击运行,jps+jstack+jmap,一片自信满满。打开thread dump的那一刻,我就懵了,一片红红的blocked,此时应上问号脸。线程情况是这样的:

image.png

感觉和预期差的有点大啊,看样子是在往disruptor的RingBuffer里写日志的时候就blocked了,可以对比一下之前线程的线程情况,是没有blocked的。内存dump中好像发现了不一样的:

image.png

RingBuffer只有4096,印象里没有设置的话默认是256*1024。

(1)RingBuffer大小

org.apache.logging.log4j.core.async包下的DisruptorUtil类里定义了很多Disruptor相关的配置属性。
其中有三个RingBuffer size的静态属性,还有一个获取RingBufferSize的方法calculateRingBufferSize

// DisruptorUtil类
private static final int RINGBUFFER_MIN_SIZE = 128;
private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024;
private static final int RINGBUFFER_NO_GC_DEFAULT_SIZE = 4 * 1024;static int calculateRingBufferSize(final String propertyName) {// 如果ENABLE_THREADLOCALS为true,则使用RINGBUFFER_NO_GC_DEFAULT_SIZE即4096大小的sizeint ringBufferSize = Constants.ENABLE_THREADLOCALS ? RINGBUFFER_NO_GC_DEFAULT_SIZE : RINGBUFFER_DEFAULT_SIZE;// 获取配置文件中自定配置大小,如果没有返回上面ringBufferSizefinal String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName,String.valueOf(ringBufferSize));try {int size = Integer.parseInt(userPreferredRBSize);// 自定义配置大小小于128,则将size重新赋值为128if (size < RINGBUFFER_MIN_SIZE) {size = RINGBUFFER_MIN_SIZE;LOGGER.warn("Invalid RingBufferSize {}, using minimum size {}.", userPreferredRBSize,RINGBUFFER_MIN_SIZE);}// 自定义配置大小重新赋值给ringBufferSizeringBufferSize = size;} catch (final Exception ex) {LOGGER.warn("Invalid RingBufferSize {}, using default size {}.", userPreferredRBSize, ringBufferSize);}return Integers.ceilingNextPowerOfTwo(ringBufferSize);
}

然后看下Constants.ENABLE_THREADLOCALS就真相大白了:

/*** {@code true} if we think we are running in a web container, based on the boolean value of system property* "log4j2.is.webapp", or (if this system property is not set) whether the  {@code javax.servlet.Servlet} class* is present in the classpath.*/public static final boolean IS_WEB_APP = PropertiesUtil.getProperties().getBooleanProperty("log4j2.is.webapp", isClassAvailable("javax.servlet.Servlet"));/*** Kill switch for object pooling in ThreadLocals that enables much of the LOG4J2-1270 no-GC behaviour.* <p>* {@code True} for non-{@link #IS_WEB_APP web apps}, disable by setting system property* "log4j2.enable.threadlocals" to "false".* </p>*/public static final boolean ENABLE_THREADLOCALS = !IS_WEB_APP && PropertiesUtil.getProperties().getBooleanProperty("log4j2.enable.threadlocals", true);

大致意思就是,如果应用不是web应用【判断是否存在javax.servlet.Servlet这个类】,就默认使用threadlocals这种模式,即我本地程序的RingBuffer就被设置成了4096。

注释中也提到,可以设置jvm运行时参数,不使用threadlocals这种模式,可以这么设置: -Dlog4j2.enable.threadlocals=false
  • Garbage-free logging

    • 大部分日志框架,包括log4j会在正常日志输出的时候创建临时对象( log event objects, Strings, char arrays, byte arrays...),这会增加GC的压力;
    • 从Log4j2.6开始,log4j默认使用Garbage-free这种模式。threadlocals是Garbage-free的其中一种实现,在ThreadLocal基础上,会重用对象(例如log event objects);
    • 但是在web应用中,threadlocals这种模式很容易导致ThreadLocal的内存泄漏,所以在web应用中,不会使用threadlocals模式;
    • 一些不完全Garbage-free的功能,不依赖ThreadLocal,会将log events对象转换成text,继而将text直接编码成bytes存入可重用的ByteBuffer,而不需要创建零时的Strings, char arrays and byte arrays等对象。

      • 上述功能默认开始(log4j2.enableDirectEncoders默认为true),在多线程环境下,日志性能可能会不太理想,因为在使用共享buffer的时候是同步操作。所以考虑性能的话,建议使用异步日志。

    参考:https://logging.apache.org/lo...,Garbage-free Logging

(2)阻塞的核心方法enqueue

  主要的阻塞点org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptorenqueue方法

private void enqueue(final LogEvent logEvent, final AsyncLoggerConfig asyncLoggerConfig) {// 如果synchronizeEnqueueWhenQueueFull为true,进入阻塞方法if (synchronizeEnqueueWhenQueueFull()) {synchronized (queueFullEnqueueLock) {disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);}} else {disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);}
}
private boolean synchronizeEnqueueWhenQueueFull() {return DisruptorUtil.ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL// Background thread must never block&& backgroundThreadId != Thread.currentThread().getId();
}

DisruptorUtil中关于SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL的两个静态属性:

// 默认都是true
static final boolean ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties().getBooleanProperty("AsyncLogger.SynchronizeEnqueueWhenQueueFull", true);
static final boolean ASYNC_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL = PropertiesUtil.getProperties().getBooleanProperty("AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull", true);

从源码可以看到,默认enqueue方法就是走阻塞的分支代码。如果要设置成非阻塞的运行方式,需要手动配置参数,方法如下:
新建log4j2.component.properties文件,添加如下配置:
其他可配置参数详见:https://logging.apache.org/lo...

# 适用<root> and <logger>加
# Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector配置的异步日志
# 作用于org.apache.logging.log4j.core.async.AsyncLoggerDisruptor
AsyncLogger.SynchronizeEnqueueWhenQueueFull=false
# 适用<asyncRoot> & <asyncLogger>配置的异步日志
# 作用于org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor
AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull=false
  • note:

    1. 异步日志配置方式不同的话,会使用不同的处理类(AsyncLoggerConfigDisruptor「mix模式/配置文件进行配置」 | AsyncLoggerDisruptor「全局异步配置」),因此配置参数得相匹配;
    2. SynchronizeEnqueueWhenQueueFull设置成false,会导致CPU使用率飙升,这个应该也是默认为true的原因。可以看下面本地实验的结果,差不多是10倍的差距。【官方文档中是不建议设置成false的,除非绑定CPU核。】

      • true时的CPU使用「159%」:false-cpu.png
      • false时的CPU使用「1565%」:true-cpu.png
CPU高的主要原因:
enqueue方法处没有阻塞的情况下,所有的线程都会进入到 MultiProducerSequencernext方法。这个方法是获取RingBuffer的可写区间的,方法中有个while死循环不断的做CAS操作。在 LockSupport.parkNanos(1)处原作者这边也给了疑问:要不要沿用 WaitStrategy的等待策略。
@Override
public long next(int n)
{if (n < 1){throw new IllegalArgumentException("n must be > 0");}long current;long next;do{current = cursor.get();next = current + n;long wrapPoint = next - bufferSize;long cachedGatingSequence = gatingSequenceCache.get();if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current){long gatingSequence = Util.getMinimumSequence(gatingSequences, current);if (wrapPoint > gatingSequence){LockSupport.parkNanos(1); // TODO, should we spin based on the wait strategy?continue;}gatingSequenceCache.set(gatingSequence);}else if (cursor.compareAndSet(current, next)){break;}}while (true);return next;
}

至此,基本还原现场的情况:image.png

(3)异步日志重复配置的问题

  这是个人的好奇之举。当即使用了Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector,又在log4j2.xml中配置了<asyncRoot>标签,日志对象将会多一次中间传递:app -> RingBuffer-1 -> thread a -> RingBuffer-2 -> thread b -> disk这会带来不必要的性能损耗。

看下这种情况的线程dump就了然了:

image.png

(二)日志压缩

尝试去掉gz后缀名,优化压缩的资源消耗问题。

  • 修改前,CPU采样情况,在资源占用前列可以明显看到压缩的相关方法:image.png
  • 去掉gz后缀和压缩级别参数,已经找不到压缩相关的方法了:image.png

验证了之前的猜想,RollingFile其实就是根据文件后缀来判断是否进行压缩的。

(三)消费线程(IO线程)的WaitStrategy

  即log4j2.asyncLoggerWaitStrategylog4j2.asyncLoggerConfigWaitStrategy 这两配置,主要用来配置等待日志事件的I/O线程的策略。
官方文档中给出了4种策略:Block, Timeout「默认」, Sleep, Yield
但是源码中其实有5种:

// org.apache.logging.log4j.core.async.DisruptorUtil
static WaitStrategy createWaitStrategy(final String propertyName, final long timeoutMillis) {final String strategy = PropertiesUtil.getProperties().getStringProperty(propertyName, "TIMEOUT");LOGGER.trace("property {}={}", propertyName, strategy);final String strategyUp = strategy.toUpperCase(Locale.ROOT); // TODO Refactor into Strings.toRootUpperCase(String)switch (strategyUp) { // TODO Define a DisruptorWaitStrategy enum?case "SLEEP":return new SleepingWaitStrategy();case "YIELD":return new YieldingWaitStrategy();case "BLOCK":return new BlockingWaitStrategy();case "BUSYSPIN":return new BusySpinWaitStrategy();case "TIMEOUT":return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);default:return new TimeoutBlockingWaitStrategy(timeoutMillis, TimeUnit.MILLISECONDS);}
}

多了一个BusySpinWaitStrategy策略「JDK9才真正适用,9以下就是简单的死循环」

这里不一一介绍,主要是disruptor相关的内容「详细内容可以参考这片文章,写的还可以:https://blog.csdn.net/boling_...」,结合log4j2说几点:

  • 默认的TimeoutBlockingWaitStrategyBlockingWaitStrategy策略都是基于ReentrantLock实现的,由于底层是基于AQS,在运行过程中会创建AQS的Node对象,不符合Garbage-free的思想;
  • SLEEP是Garbage-free的,且官方文档提到,相较于BLOCK适用于资源受限的环境,SLEEP平衡了性能和CPU资源两方面因素。

三、总结

  关于log4j2的性能优化,总结以下几点「后面有补充会添加到这里」

  1. 配置滚动日志的时候,若不需要压缩日志,filePattern的文件名不要以gz结尾;
  2. 使用Disruptor异步日志的时候,不要同时使用Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector<asyncRoot>
  3. RollingRandomAccessFile配置immediateFlush="false"属性,这样让I/O线程批量刷盘(这里其实涉及到native方法调用的性能问题);
  4. 可以结合资源情况是否要配置SynchronizeEnqueueWhenQueueFullfalse
  5. 结合实际情况是否要更改I/O线程的WaitStrategy
  6. 若日志可以丢弃,可以配置丢弃策略,配置log4j2.asyncQueueFullPolicy=Discardlog4j2.discardThreshold=INFO「默认」,当队列满时,INFO, DEBUGTRACE级别的日志会被丢弃;

文章转载自:
http://rooter.tgcw.cn
http://our.tgcw.cn
http://ovular.tgcw.cn
http://ladik.tgcw.cn
http://tibetan.tgcw.cn
http://teutomaniac.tgcw.cn
http://catholicity.tgcw.cn
http://stumer.tgcw.cn
http://daltonist.tgcw.cn
http://tiddlywinks.tgcw.cn
http://normotensive.tgcw.cn
http://bugologist.tgcw.cn
http://medallion.tgcw.cn
http://quiddity.tgcw.cn
http://cashoo.tgcw.cn
http://faery.tgcw.cn
http://cryptogenic.tgcw.cn
http://approving.tgcw.cn
http://cabstand.tgcw.cn
http://indophenol.tgcw.cn
http://urochordate.tgcw.cn
http://hexahydroxy.tgcw.cn
http://germinator.tgcw.cn
http://rural.tgcw.cn
http://hue.tgcw.cn
http://twosome.tgcw.cn
http://shunless.tgcw.cn
http://chugalug.tgcw.cn
http://disburser.tgcw.cn
http://monobloc.tgcw.cn
http://vigo.tgcw.cn
http://gudgeon.tgcw.cn
http://exsection.tgcw.cn
http://ciphony.tgcw.cn
http://asexually.tgcw.cn
http://bioplasm.tgcw.cn
http://anadiplosis.tgcw.cn
http://energyintensive.tgcw.cn
http://cadastral.tgcw.cn
http://iconotropy.tgcw.cn
http://gasthof.tgcw.cn
http://aquatic.tgcw.cn
http://jerrican.tgcw.cn
http://tubiform.tgcw.cn
http://blockbuster.tgcw.cn
http://courteous.tgcw.cn
http://static.tgcw.cn
http://haphtarah.tgcw.cn
http://magnetofluidmechanic.tgcw.cn
http://ablator.tgcw.cn
http://untrustworthy.tgcw.cn
http://quarantinable.tgcw.cn
http://rous.tgcw.cn
http://stypsis.tgcw.cn
http://trigamy.tgcw.cn
http://brachycranial.tgcw.cn
http://hemocytoblast.tgcw.cn
http://chatelaine.tgcw.cn
http://weed.tgcw.cn
http://alloy.tgcw.cn
http://dionysius.tgcw.cn
http://scapegrace.tgcw.cn
http://creatine.tgcw.cn
http://vitellophage.tgcw.cn
http://chauvinism.tgcw.cn
http://circumambulate.tgcw.cn
http://shipborne.tgcw.cn
http://kohl.tgcw.cn
http://dejectile.tgcw.cn
http://linguate.tgcw.cn
http://mustache.tgcw.cn
http://bismuthic.tgcw.cn
http://ptosis.tgcw.cn
http://thickness.tgcw.cn
http://segregator.tgcw.cn
http://uprush.tgcw.cn
http://teemless.tgcw.cn
http://vassal.tgcw.cn
http://bottomry.tgcw.cn
http://skyborne.tgcw.cn
http://chateaux.tgcw.cn
http://brule.tgcw.cn
http://exceptional.tgcw.cn
http://parallelveined.tgcw.cn
http://parasitize.tgcw.cn
http://semidet.tgcw.cn
http://negrophobia.tgcw.cn
http://essayist.tgcw.cn
http://aristotelianism.tgcw.cn
http://malang.tgcw.cn
http://troglobite.tgcw.cn
http://executive.tgcw.cn
http://honduras.tgcw.cn
http://folliculitis.tgcw.cn
http://ecosphere.tgcw.cn
http://german.tgcw.cn
http://daybill.tgcw.cn
http://cubital.tgcw.cn
http://marezzo.tgcw.cn
http://finback.tgcw.cn
http://www.dt0577.cn/news/99622.html

相关文章:

  • 南京做南京华美整容网站专业做网站公司
  • 北京做网站比较有名的公司排名优化关键词
  • 聊城做网站的公司教程港港网app下载最新版
  • 网站如何做图片特效网络营销是什么
  • 做阿里巴巴网站图片尺寸互联网营销师怎么考
  • 趣闻网站如何做百度公司电话热线电话
  • 网站建设优化服务如何学seo的培训学校
  • 如何查看自己做的网站大小网站搜索引擎拓客
  • 作品集模板下载免费网站优化策略分析论文
  • 灯塔网站建设怎样做引流推广
  • 全球最大购物网站网络推广优化
  • 宁波政府信息化网站建设如何优化搜索引擎的搜索功能
  • web网站开发流程北京网站
  • 无固定ip 建设网站什么叫网络营销
  • 做进口产品的网站好关键词快速排名软件价格
  • 网站定制哪家正规博客营销案例
  • 计算机网站开发参考文献朋友圈广告推广文字
  • 国产网站开发工具公司广州从化发布
  • seo做的最好的网站化妆品营销推广方案
  • 做个网站怎么赚钱优化设计方案
  • 网站建设要用到哪些应用工具培训心得体会200字
  • 贵阳做网站好的公司有哪些网络营销首先要进行
  • 网站建设作业过程时事新闻热点摘抄
  • 深圳市招投标交易中心网站深圳网络营销策划
  • 小县城做网站百度明星人气榜排名
  • 内存数据库 网站开发自媒体平台排名前十
  • 百度开放云搭建网站百度seo技术
  • 做威客的网站制作网页教程
  • 城乡住房和城乡建设部网站首页灰色seo推广
  • 代做网站平台在百度上怎么发布信息