我有一个自定义DB Appender,它扩展了logback DBAppender。我的应用程序有100个并行线程。这些线程还在处理请求时通过自定义db appender将事件记录到数据库中。
日志记录的性能非常慢,如果禁用日志,则执行将在20分钟内完成。在启用日志的情况下,由于我的日志记录是同步的,因此大部分时间都需要花费大约5个小时来等待写入日志以继续下一步。
起初我认为性能缓慢可能是由于logback appender的同步doAppend
方法。但是,后来我注意到DB appender扩展了
UnsynchronizedAppenderBase(public abstract class DBAppenderBase<E>
/* */ extends UnsynchronizedAppenderBase<E>).
任何人都可以帮助我理解这种糟糕表现的原因是什么?
我的数据库附加器:
package com.test;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.omg.CORBA.TRANSACTION_UNAVAILABLE;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.db.DBAppender;
import ch.qos.logback.classic.spi.ILoggingEvent;
public class CustomDBAppender extends DBAppender {
final static Logger logger = LoggerFactory.getLogger("com.test");
protected String insertPropertiesSQL;
protected String insertExceptionSQL;
protected String insertSQL;
private CustomDBNameResolver dbNameResolver;
// default constructor
public CustomDBAppender() {
logger.debug("DB Appender instantiated");
}
// set dbNameResolver for getting table information
public void setCsiDbNameResolver(CustomDBNameResolver dbNameResolver) {
this.dbNameResolver = dbNameResolver;
}
@Override
public void start() {
super.start();
if (dbNameResolver == null)
dbNameResolver = new CustomDBNameResolver();
insertSQL = CustomSQLBuilder.buildInsertSQL(dbNameResolver);
}
@Override
protected void subAppend(ILoggingEvent event, Connection connection, PreparedStatement insertStatement)
throws Throwable {
logEvents(insertStatement, event);
// System.out.println("=== INSERT STATEMENT === " +
// insertStatement.toString());
int updateCount = -1;
try {
updateCount = insertStatement.executeUpdate();
} catch (Exception e) {
logger.error(" ERROR ");
e.printStackTrace();
}
logger.info(" updateCount = " + updateCount);
if (updateCount != 1) {
logger.error(" ERROR IT IS ");
addWarn("Failed to insert loggingEvent");
}
}
protected void secondarySubAppend(ILoggingEvent event, Connection connection, long eventId) throws Throwable {
}
// @override
private void logEvents(PreparedStatement stmt, ILoggingEvent event) throws SQLException {
logData(event, stmt);
}
private void logData(ILoggingEvent event, PreparedStatement stmt) throws SQLException {
try {
if (null != event && null != logMsgArgs && (event.getLoggerName().indexOf("com.test.beans.") != -1)) {
payload = null == logMsgArgs[0] ? "NA"
: (logMsgArgs[0].toString()).substring(0,
(logMsgArgs[0].toString().length() >= 4000 ? 3999 : logMsgArgs[0].toString().length()));
msgHeader = null == logMsgArgs[1] ? "NA"
: (logMsgArgs[1].toString()).substring(0,
(logMsgArgs[1].toString().length() >= 4000 ? 3999 : logMsgArgs[1].toString().length()));
currentStage = null == logMsgArgs[2] ? -1 : Integer.parseInt(logMsgArgs[2].toString());
currentEvent = null == logMsgArgs[3] ? null : logMsgArgs[3].toString();
trxId = null == logMsgArgs[4] ? null : logMsgArgs[4].toString();
batchId = null == logMsgArgs[5] ? null : logMsgArgs[5].toString();
headerId = null == logMsgArgs[6] ? null : logMsgArgs[6].toString();
}
stmt.setString(1, logLevel);
stmt.setObject(2, trxId);
stmt.setString(3, logMessage);
stmt.setDate(4, getSqlDate());
stmt.setString(5, event.getLoggerName());
stmt.setString(6, event.getThreadName());
stmt.setString(7, event.getLoggerContextVO().getName());
stmt.setString(8, logMessage.substring(0, logMessageLength));
stmt.setString(9, payload);
stmt.setString(10, msgHeader);
stmt.setInt(11, currentStage);
stmt.setString(12, currentEvent);
stmt.setString(13, batchId);
stmt.setString(14, headerId);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Exception while printing log:" + e.getMessage());
e.printStackTrace();
} finally {
}
}
private Object nvl(Object input) {
if (null == input) {
return null;
}
return input;
}
private java.sql.Date getSqlDate() {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSX");
String nowDateStr = sdf.format(now);
logger.info("nowDateStr = " + nowDateStr);
java.sql.Date toDB = null;
try {
toDB = new java.sql.Date(sdf.parse(nowDateStr).getTime());
logger.info("toDB = " + toDB);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return toDB;
}
@Override
protected String getInsertSQL() {
return insertSQL;
}
protected void insertProperties(Map<String, String> mergedMap, Connection connection, long eventId)
throws SQLException {
}
}
/ * appender结束* /