Вступление
Недавно я работал для клиента, пытаясь удалить некоторые паузы GC для большой хорошо созданной системы Java. После профилирования я понял, что большая часть мусора производилась при ведении журнала! Был ли простой ненавязчивый способ удалить все это распределение? Оказывается, там было 🙂
Какой фреймворк я должен использовать для свободной регистрации GC?
Давайте снова обратим наше внимание на давний вопрос о том, какую систему ведения журналов использовать.
Обычные кандидаты
- log4j2
- Logback
- java.util.logging
- slf4j (простой)
и если вы не делаете что-то сверхъестественное, вы можете не думать, что это имеет огромное значение для того, кого вы выберете
Было проведено много исследований по сравнению производительности, и, конечно, это может быть важно, если вы играете на арене со сверхнизкими задержками. ( см. Сравнительный анализ Java-каркасов )
Но что меня беспокоит, так это распределение !!
Смотрите мой предыдущий пост о пороках распределения . Первое правило оптимизации производительности.
В типичной системе 30% -50% всего распределения может быть в журнале! Таким образом, даже если большинство людей не возражают против того, что ведение журнала занимает в одной инфраструктуре на пару миллисекунд дольше, чем в другой, они почти наверняка будут беспокоиться о длительных паузах GC, вызванных мусором, создаваемым инфраструктурой журналирования.
И все это распределение журналов может быть удалено простой настройкой. Log4J2 начиная с версии 2.6 — это бесплатное выделение, так что на самом деле нет оправдания, чтобы не воспользоваться этим 🙂
Давайте посмотрим на это в действии
Одно дело сделать заявку на бесплатное распределение, но давайте посмотрим, верно ли это на практике.
Рассмотрим этот простой код регистрации ниже: обратите внимание, что я использовал slf4j в коде и, следовательно, нужно всего лишь изменить конфигурацию для работы с различными структурами ведения журнала. Это хорошая идея, потому что хотя log4j2 может быть лучшей средой на данный момент, кто знает, что принесет завтрашний день …
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; public class GCLogger { private final static Logger LOGGER = LoggerFactory.getLogger(GCLogger. class ); public static void main(String[] args) throws InterruptedException { List<String> list = IntStream.range( 0 ,( int )1e6) .mapToObj(i-> "" + i) .collect(Collectors.toList()); //Log 1 million lines in a loop sleeping 1 second between each iteration of the loop //to allow time to run Flight Recorder. for ( int i = 0 ; i < 1000 ; i++) { list.forEach(s->LOGGER.info( "Logging [{}]" , s)); Thread.sleep( 1000 ); } } } |
Запустить с log4j2 — без выделения
Если мы настроим программу для работы с log4j2, используя эту конфигурацию maven:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
< dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-api</ artifactId > < version >1.7.25</ version > </ dependency > < dependency > < groupId >org.apache.logging.log4j</ groupId > < artifactId >log4j-api</ artifactId > < version >2.9.1</ version > </ dependency > < dependency > < groupId >org.apache.logging.log4j</ groupId > < artifactId >log4j-core</ artifactId > < version >2.9.1</ version > </ dependency > < dependency > < groupId >org.apache.logging.log4j</ groupId > < artifactId >log4j-slf4j-impl</ artifactId > < version >2.9.1</ version > </ dependency > |
И мы используем эту конфигурацию log4j2
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
xml version="1.0" encoding="UTF-8" ?>< Configuration status = "INFO" > < Appenders > < Console name = "Console" target = "SYSTEM_OUT" > < PatternLayout pattern = "%d{HH:mm:ss:SSS} [%t] %-5level %logger[36] %msg%n" ></ PatternLayout > </ Console > < File name = "MyFile" fileName = "all.log" immeadiateFlush = "false" append = "false" > < PatternLayout pattern = "%d{dd MMM yyyy HH:mm:ss,SSS} [%t] %-5level %logger[36] %msg%n" ></ PatternLayout > </ File > </ Appenders > < Loggers > < Root level = "debug" > < AppenderRef ref = "MyFile" ></ AppenderRef > </ Root > </ Loggers > </ Configuration > |
Тогда мы получаем 0 распределения!
Мы можем доказать это, запустив Flight Recorder в программе (см. Ниже):
Единственная выделяемая память — из-за Регистратора Полетов (кстати, FR можно настроить так, чтобы этого не происходило).
Запустить используя logback
Попробуйте точно так же, используя Logback.
Используйте эту конфигурацию Maven
1
2
3
4
5
|
< dependency > < groupId >ch.qos.logback</ groupId > < artifactId >logback-classic</ artifactId > < version >1.2.3</ version > </ dependency > |
Используйте эту конфигурацию входа в систему:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
< configuration > < appender name = "FILE" class = "ch.qos.logback.core.FileAppender" > < file >myApp.log</ file > < encoder > < pattern >%date %level [%thread] %logger{10} [%file:%line] %msg%n</ pattern > </ encoder > </ appender > < appender name = "STDOUT" class = "ch.qos.logback.core.ConsoleAppender" > < encoder > < pattern >%msg%n</ pattern > </ encoder > </ appender > < root level = "debug" > < appender-ref ref = "FILE" /> </ root > </ configuration > |
И когда мы бежим с Flight Recorder, мы видим распределение суммы объятий!
Но слово предупреждения …
Вам необходимо использовать конфигурацию log4j2 точно так, как указано в документации, см. Поддерживаемые макеты . Если вы хотя бы немного измените формат даты, распределение снова будет безудержным.
Резюме
- Используйте slf4j, чтобы вы могли легко изменить свою реализацию регистрации
- Используйте log4j2, чтобы избежать выделения
- Убедитесь, что вы используете поддерживаемые форматы для поддержки распределения бесплатных журналов
См. Оригинальную статью здесь: размещение без регистрации с log4j2
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |