From bcf103e9936975948f66886b5ffa30af377240fd Mon Sep 17 00:00:00 2001 From: caiconghui <55968745+caiconghui@users.noreply.github.com> Date: Wed, 14 Jun 2023 15:16:04 +0800 Subject: [PATCH] [enhancement](log4j) support high performance mode for log4j to escape potential bottleneck for doris read and write (#20759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we know, log4j2 some times may be bottleneck in doris fe when there are many logs to be output in sync mode while asynchronous logging has a better performance, and we find that capturing caller location has a similar impact across all logging libraries, and slows down asynchronous logging by about 30-100x. so, here we provide three log mode for log4j2 to meet the needs of different users. refer to https://logging.apache.org/log4j/2.x/performance.html --- conf/fe.conf | 3 ++ .../java/org/apache/doris/common/Config.java | 15 +++++-- .../main/java/org/apache/doris/DorisFE.java | 1 + .../org/apache/doris/common/Log4jConfig.java | 44 +++++++++++++++---- .../httpv2/controller/LogController.java | 17 +++---- fe/pom.xml | 6 +++ 6 files changed, 66 insertions(+), 20 deletions(-) diff --git a/conf/fe.conf b/conf/fe.conf index e5a097d974..b654b1613d 100644 --- a/conf/fe.conf +++ b/conf/fe.conf @@ -38,6 +38,9 @@ JAVA_OPTS_FOR_JDK_9="-Xss4m -Xmx8192m -XX:SurvivorRatio=8 -XX:MaxTenuringThresho # INFO, WARN, ERROR, FATAL sys_log_level = INFO +# NORMAL, BRIEF, ASYNC +sys_log_mode = NORMAL + # store metadata, must be created before start FE. # Default value is ${DORIS_HOME}/doris-meta # meta_dir = ${DORIS_HOME}/doris-meta diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index 4c2d309b9f..dc0839d300 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -34,10 +34,10 @@ public class Config extends ConfigBase { * sys_log_dir: * This specifies FE log dir. FE will produces 2 log files: * fe.log: all logs of FE process. - * fe.warn.log all WARNING and ERROR log of FE process. + * fe.warn.log all WARN and ERROR log of FE process. * * sys_log_level: - * INFO, WARNING, ERROR, FATAL + * INFO, WARN, ERROR, FATAL * * sys_log_roll_num: * Maximal FE log files to be kept within an sys_log_roll_interval. @@ -65,9 +65,18 @@ public class Config extends ConfigBase { "The path of the FE log file, used to store fe.log"}) public static String sys_log_dir = System.getenv("DORIS_HOME") + "/log"; - @ConfField(description = {"FE 日志的级别", "The level of FE log"}, options = {"INFO", "WARNING", "ERROR", "FATAL"}) + @ConfField(description = {"FE 日志的级别", "The level of FE log"}, options = {"INFO", "WARN", "ERROR", "FATAL"}) public static String sys_log_level = "INFO"; + @ConfField(description = {"FE 日志的输出模式,其中 NORMAL 为默认的输出模式,日志同步输出且包含位置信息," + + "BRIEF 模式是日志同步输出但不包含位置信息,ASYNC 模式是日志异步输出且不包含位置信息,三种日志输出模式的性能依次递增", + "The output mode of FE log, and NORMAL mode is the default output mode, which means the logs are " + + "synchronized and contain location information. BRIEF mode is synchronized and does not contain" + + " location information. ASYNC mode is asynchronous and does not contain location information." + + " The performance of the three log output modes increases in sequence"}, + options = {"NORMAL", "BRIEF", "ASYNC"}) + public static String sys_log_mode = "NORMAL"; + @ConfField(description = {"FE 日志文件的最大数量。超过这个数量后,最老的日志文件会被删除", "The maximum number of FE log files. After exceeding this number, the oldest log file will be deleted"}) public static int sys_log_roll_num = 10; diff --git a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java index 3a83a25e39..7d87091120 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java @@ -114,6 +114,7 @@ public class DorisFE { } Log4jConfig.initLogging(dorisHomeDir + "/conf/"); + Runtime.getRuntime().addShutdownHook(new Thread(LogManager::shutdown)); // set dns cache ttl java.security.Security.setProperty("networkaddress.cache.ttl", "60"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/Log4jConfig.java b/fe/fe-core/src/main/java/org/apache/doris/common/Log4jConfig.java index 7bf38fd786..7163a58418 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/Log4jConfig.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/Log4jConfig.java @@ -44,12 +44,12 @@ public class Log4jConfig extends XmlConfiguration { + " \n" + " " + " \n" - + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid) [%C{1}.%M():%L] %m%n\n" + + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid)%m%n\n" + " \n" + " " + " \n" + " \n" - + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid) [%C{1}.%M():%L] %m%n\n" + + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid)%m%n\n" + " \n" + " \n" + " \n" @@ -64,7 +64,7 @@ public class Log4jConfig extends XmlConfiguration { + " \n" + " \n" + " \n" - + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid) [%C{1}.%M():%L] %m%n\n" + + " %d{yyyy-MM-dd HH:mm:ss,SSS} %p (%t|%tid)%m%n\n" + " \n" + " \n" + " \n" @@ -94,7 +94,7 @@ public class Log4jConfig extends XmlConfiguration { + " \n" + " \n" + " \n" - + " \n" + + " \n" + " \n" + " \n" + " \n" @@ -109,6 +109,7 @@ public class Log4jConfig extends XmlConfiguration { private static StrSubstitutor strSub; private static String sysLogLevel; + private static String sysLogMode; private static String[] verboseModules; private static String[] auditModules; // save the generated xml conf template @@ -139,6 +140,12 @@ public class Log4jConfig extends XmlConfiguration { throw new IOException("sys_log_level config error"); } + if (!(sysLogMode.equalsIgnoreCase("NORMAL") + || sysLogMode.equalsIgnoreCase("BRIEF") + || sysLogMode.equalsIgnoreCase("ASYNC"))) { + throw new IOException("sys_log_mode config error"); + } + String sysLogRollPattern = "%d{yyyyMMdd}"; String sysRollMaxSize = String.valueOf(Config.log_roll_size_mb); if (Config.sys_log_roll_interval.equals("HOUR")) { @@ -174,6 +181,16 @@ public class Log4jConfig extends XmlConfiguration { newXmlConfTemplate = newXmlConfTemplate.replaceAll("", sb.toString()); + if (sysLogMode.equalsIgnoreCase("NORMAL")) { + newXmlConfTemplate = newXmlConfTemplate.replaceAll("", + " [%C{1}.%M():%L] "); + } else { + newXmlConfTemplate = newXmlConfTemplate.replaceAll("", " "); + if (sysLogMode.equalsIgnoreCase("ASYNC")) { + newXmlConfTemplate = newXmlConfTemplate.replaceAll("Root", "AsyncRoot"); + } + } + if (foreground) { StringBuilder consoleLogger = new StringBuilder(); consoleLogger.append("\n"); @@ -193,6 +210,8 @@ public class Log4jConfig extends XmlConfiguration { properties.put("audit_roll_maxsize", auditRollMaxSize); properties.put("audit_roll_num", auditRollNum); properties.put("audit_log_delete_age", auditDeleteAge); + properties.put("include_location_flag", sysLogMode.equalsIgnoreCase("NORMAL") ? "true" : "false"); + properties.put("immediate_flush_flag", sysLogMode.equalsIgnoreCase("ASYNC") ? "false" : "true"); strSub = new StrSubstitutor(new Interpolator(properties)); newXmlConfTemplate = strSub.replace(newXmlConfTemplate); @@ -216,15 +235,17 @@ public class Log4jConfig extends XmlConfiguration { return logXmlConfTemplate; } - public static class Tuple { + public static class Tuple { public final X x; public final Y y; public final Z z; + public final U u; - public Tuple(X x, Y y, Z z) { + public Tuple(X x, Y y, Z z, U u) { this.x = x; this.y = y; this.z = z; + this.u = u; } } @@ -239,6 +260,7 @@ public class Log4jConfig extends XmlConfiguration { public static synchronized void initLogging(String dorisConfDir) throws IOException { sysLogLevel = Config.sys_log_level; + sysLogMode = Config.sys_log_mode; verboseModules = Config.sys_log_verbose_modules; auditModules = Config.audit_log_modules; confDir = dorisConfDir; @@ -246,13 +268,17 @@ public class Log4jConfig extends XmlConfiguration { reconfig(); } - public static synchronized Tuple updateLogging( - String level, String[] verboseNames, String[] auditNames) throws IOException { + public static synchronized Tuple updateLogging( + String level, String mode, String[] verboseNames, String[] auditNames) throws IOException { boolean toReconfig = false; if (level != null) { sysLogLevel = level; toReconfig = true; } + if (mode != null) { + sysLogMode = mode; + toReconfig = true; + } if (verboseNames != null) { verboseModules = verboseNames; toReconfig = true; @@ -264,6 +290,6 @@ public class Log4jConfig extends XmlConfiguration { if (toReconfig) { reconfig(); } - return new Tuple<>(sysLogLevel, verboseModules, auditModules); + return new Tuple<>(sysLogLevel, sysLogMode, verboseModules, auditModules); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/LogController.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/LogController.java index 9c3f114fb8..dc7878b757 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/LogController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/LogController.java @@ -45,7 +45,7 @@ import javax.servlet.http.HttpServletRequest; public class LogController { private static final Logger LOG = LogManager.getLogger(LogController.class); - private static long WEB_LOG_BYTES = 1024 * 1024; // 1MB + private static final long WEB_LOG_BYTES = 1024 * 1024; // 1MB private String addVerboseName; private String delVerboseName; @@ -76,14 +76,15 @@ public class LogController { Map map = new HashMap<>(); try { - Log4jConfig.Tuple configs = Log4jConfig.updateLogging(null, null, null); + Log4jConfig.Tuple configs = + Log4jConfig.updateLogging(null, null, null, null); if (!Strings.isNullOrEmpty(addVerboseName)) { addVerboseName = addVerboseName.trim(); - List verboseNames = Lists.newArrayList(configs.y); + List verboseNames = Lists.newArrayList(configs.z); if (!verboseNames.contains(addVerboseName)) { verboseNames.add(addVerboseName); - configs = Log4jConfig.updateLogging(null, verboseNames.toArray(new String[verboseNames.size()]), - null); + configs = Log4jConfig.updateLogging(null, null, + verboseNames.toArray(new String[verboseNames.size()]), null); readEnvironment.reinitializeLoggingSystem(); } } @@ -92,8 +93,8 @@ public class LogController { List verboseNames = Lists.newArrayList(configs.y); if (verboseNames.contains(delVerboseName)) { verboseNames.remove(delVerboseName); - configs = Log4jConfig.updateLogging(null, verboseNames.toArray(new String[verboseNames.size()]), - null); + configs = Log4jConfig.updateLogging(null, null, + verboseNames.toArray(new String[verboseNames.size()]), null); readEnvironment.reinitializeLoggingSystem(); } } @@ -118,7 +119,7 @@ public class LogController { raf = new RandomAccessFile(logPath, "r"); long fileSize = raf.length(); long startPos = fileSize < WEB_LOG_BYTES ? 0L : fileSize - WEB_LOG_BYTES; - long webContentLength = fileSize < WEB_LOG_BYTES ? fileSize : WEB_LOG_BYTES; + long webContentLength = Math.min(fileSize, WEB_LOG_BYTES); raf.seek(startPos); map.put("showingLast", webContentLength + " bytes of log"); StringBuilder sb = new StringBuilder(); diff --git a/fe/pom.xml b/fe/pom.xml index 4d7b077ab8..b479dc3d57 100644 --- a/fe/pom.xml +++ b/fe/pom.xml @@ -308,6 +308,7 @@ under the License. 3.0.0 0.4.0-incubating + 3.3.4 @@ -711,6 +712,11 @@ under the License. log4j-api ${log4j2.version} + + com.lmax + disruptor + ${disruptor.version} + io.dropwizard.metrics