0%

log4j2自动删除日志文件

线上的项目每天产生大量的日志文件,而磁盘大小又是有限的,不可能一直把日志文件保留下来,但是每次磁盘报警上去删日志文件也挺麻烦的,log4j2中可以配置日志文件的删除策略。

在DefaultRolloverStrategy中配置Delete,当触发了滚动时,就会执行DefaultRolloverStrategy中配置的各个Action操作,而Delete标签就表示的DeleteAction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<DefaultRolloverStrategy max="30">
<!-- basePath表示扫描开始的路径
maxDepth 表示目录的扫描深度,2表示扫描basePath文件夹及其子文件夹
-->
<Delete basePath="${LOG_HOME}" maxDepth="2">
<!-- IfFileName 指定文件名满足的条件 -->
<IfFileName glob="*/*.bz2"/>
<!--!Note: 这里的age必须和filePattern协调, 后者是精确到天,age的单位就是天
另外, 数字最好>2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->

<!-- IfLastModified 指定文件修改时间满足的条件 -->
<IfLastModified age="30d"/>
</Delete>
<Delete basePath="${LOG_HOME}" maxDepth="1">
<!--!Note: 这里的age必须和filePattern协调, 后者是精确到天,age的单位就是天
另外, 数字最好>2, 否则可能造成删除的时候, 最近的文件还处于被占用状态,导致删除不成功!-->

<IfLastModified age="30d"/>
</Delete>
</DefaultRolloverStrategy>

log4j2日志文件滚动

Appender在log4j2中有很多实现类,如ConsoleAppender(插件名称为Console)、FileAppender(插件名称为File)、RollingFileAppender(插件名称为RollingFile)等,在实际的项目中通常使用的都是RollingFileAppender,也就是日志文件滚动更新的Appender

1
2
3
4
5
6
7
8
9
<RollingFile name="file" fileName="/data/log/app.log"
filePattern="/data/log/app.log.%d{yyyyMMdd}.%i.bz2">
<PatternLayout charset="UTF-8" pattern="[%-5p %d{yyyy-MM-dd HH:mm:ss.SSS}] %l [%m]%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="1024 MB"/>
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>

其滚动依赖于TriggeringPolicy(触发策略)和RolloverStrategy(滚动更新策略)

TriggeringPolicy

TriggeringPolicy为触发策略,决定了何时触发日志文件的滚动。常见策略有CronTriggeringPolicy、OnStartupTriggeringPolicy、SizeBasedTriggeringPolicy、TimeBasedTriggeringPolicy、CompositeTriggeringPolicy

CronTriggeringPolicy

CronTriggeringPolicy是基于Cron表达式来进行触发的

1
2
<!-- 根据cron来进行触发 -->
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>

代码

阅读全文 »

nf_conntrack: table full, dropping packet报错

最近项目时不时地连接mysql数据库报错

1
2
3
4
5
{pool-21-thread-1} SQL Error: 0, SQLState: 08S01
{pool-21-thread-1} Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server
java.net.UnknownHostException

同样的阿里云数据库,其他的服务器连接都不会报错,而且看云数据库的监控,负载是没有问题的。说明大概率不是云数据库的问题。

而该项目比其他服务器里的项目不同的是,访问量比较高,猜测会不会是外网带宽问题,尝试将mysql连接改成内网,这样走内网,观察两天发现,虽然减少了,但还是存在。

猜想是不是tcp连接太多导致的,后发现/var/log/messages日志中报错nf_conntrack: table full, dropping packet

阅读全文 »

视频生成缩略图

最近有个需求,视频上传之后在列表和详情页需要展示缩略图

使用ffmpeg

首先引入jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.0.2-1.4.3</version>
</dependency>

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public String getThumbnails(String videoFilePath){
String path = "/Users/zhanghe/Desktop/pic/";
String fileName = videoFilePath.substring(videoFilePath.lastIndexOf("/") + 1, videoFilePath.lastIndexOf("."))+"_thumb.jpg";

String filePath = StringUtils.join(path, fileName);
File targetFile = new File(filePath);
try {
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFilePath);
ff.start();
// 视频总帧数
int videoLength = ff.getLengthInFrames();

org.bytedeco.javacv.Frame f = null;
int i = 0;
while (i < videoLength) {
// 过滤前20帧,因为前20帧可能是全黑的
// 这里看需求,也可以直接根据帧数取图片
f = ff.grabFrame();
if (i > 20 && f.image != null) {
break;
}
i++;
}
int owidth = f.imageWidth;
int oheight = f.imageHeight;
// 对截取的帧进行等比例缩放
int width = 800;
int height = (int) (((double) width / owidth) * oheight);
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage fecthedImage = converter.getBufferedImage(f);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
bi.getGraphics().drawImage(fecthedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH),
0, 0, null);
ImageIO.write(bi, "jpg", targetFile);
ff.stop();

System.out.println(targetFile.getPath());
return targetFile.getPath();

} catch (IOException e) {
e.printStackTrace();
}
return "";
}

线上问题排查

  • 先确定是不是CPU占比太高 使用top命令查看cpu的 %idle还有多少,如果idle过少,表示CPU使用率较高,按P用CPU排序,查看CPU占用多的进程。之后可以通过该文章【 CPU飙升 】来查找问题
  • 查看内存情况,使用 free -h 查看内存使用情况,如果剩余内存偏少,使用vmstat -n 1查看 si、so列的情况,确认是否内存不够用了。如果内存不够用了,使用top命令,按M用内存排序,查看内存占用多的进程
  • 查看网络连接,使用netstat -tnop | wc -l 查看tcp连接数,如果连接数过高,按照PID统计tcp连接数量 netstat -tnp | awk '{print $7}' | sort | uniq -c | sort -m,查看各个状态下的连接有多少个netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c
  • 查看磁盘情况,使用iostat -d 1,查看kB_read/s kB_wrtn/s,如果磁盘读写频繁,找到大量写磁盘的进程,使用iotop或者ls -l /proc/*/fd或者pstack或者strace命令来查看