SlideShare a Scribd company logo
© Netcracker 2016 1
Производительность
open source решений
Владимир Ситников
JPoint 2016
© Netcracker 2016 2
•Владимир Ситников
•Инженер по производительности в Netcracker,
10 лет
•sitnikov@netcracker.com
•@VladimirSitnikv
Кто я
© Netcracker 2016 3
•Spring
•Cglib
•Pgjdbc
•HornetQ
•Wildfly
•Jenkins
План
© Netcracker 2016 4
План
Наш любимый
enterprise
продукт
© Netcracker 2016 5
Внедряем Spring в сжатые сроки
Монолит
spring
© Netcracker 2016 6
Внедряем Spring в сжатые сроки
Монолит
spring
© Netcracker 2016 7
Внедряем Spring в сжатые сроки
Core
Security
UI
© Netcracker 2016 8
Внедряем Spring в сжатые сроки
Core
Security
UI
© Netcracker 2016 9
Внедряем Spring в сжатые сроки
Core
Security
UI
© Netcracker 2016 10
•Когда нужен бин, то выполняем
beanFactory.getBean(Security.class)
В UI spring пока не наступил
© Netcracker 2016 11
•Когда нужен бин, то выполняем
beanFactory.getBean(Security.class)
•Но где взять beanFactory?
В UI spring пока не наступил
© Netcracker 2016 12
•Когда нужен бин, то выполняем
beanFactory.getBean(Security.class)
•Но где взять beanFactory?
•Правильно, Паблик Морозов поможет нам
В UI spring пока не наступил
© Netcracker 2016 13
public class AppContext implements BeanFactoryAware
{
static public BeanFactory beanFactory;
...
Получаем бин
© Netcracker 2016 14
public class AppContext implements BeanFactoryAware
{
static public BeanFactory beanFactory;
...
AppContext.beanFactory.getBean(Security.class)
Получаем бин
© Netcracker 2016 15
•Работает
Spring.getBean
© Netcracker 2016 16
•Работает
•Но медленно-медленно
Spring.getBean
© Netcracker 2016 17
•Работает
•Но медленно-медленно
•На getBean и 50% времени может уходить
Spring.getBean
© Netcracker 2016 18
•Java Flight Recorder
Подходящие для анализа инструменты
© Netcracker 2016 19
•Java Flight Recorder
•kill -3 profiler (poormansprofiler.org)
Подходящие для анализа инструменты
© Netcracker 2016 20
•Java Flight Recorder
•kill -3 profiler (poormansprofiler.org)
•Инструментирующий профилировщик.
Например самописный, настроенный на
getBean
Подходящие для анализа инструменты
© Netcracker 2016 21
160 секунд на getBean. Здорово?
© Netcracker 2016 22
160 секунд на getBean. Здорово?
•Java 8 / Spring 4.1.7
© Netcracker 2016 23
•SPR-6870 Cache by-type lookups in
DefaultListableBeanFactory
Проверяем известные проблемы
© Netcracker 2016 24
•SPR-6870 Cache by-type lookups in
DefaultListableBeanFactory
Проверяем известные проблемы
ЯЗЬ!!!
© Netcracker 2016 25
•SPR-6870 Cache by-type lookups in
DefaultListableBeanFactory
•Fix version: 3.2 M1, а у нас 4.1+ 
Проверяем известные проблемы
© Netcracker 2016 26
Flight Recorder, allocations in new TLAB
© Netcracker 2016 27
protected Object getCacheKey(
Class<?> beanClass, String beanName) {
return beanClass.getName() + "_" + beanName;
}
AbstractAutoProxyCreator
© Netcracker 2016 28
protected Object getCacheKey(
Class<?> beanClass, String beanName) {
return beanClass.getName() + "_" + beanName;
}
AbstractAutoProxyCreator
© Netcracker 2016 29
protected Object getCacheKey(
Class<?> beanClass, String beanName) {
return beanName == null ? beanClass : ...;
}
github.com/spring-projects/spring-
framework/pull/913
AbstractAutoProxyCreator
© Netcracker 2016 30
public class SharedSecrets {
@Inject
public Security security;
@PostConstruct
public void init() { INSTANCE = this; }
public static volatile SharedSecrets INSTANCE;
Как выжить без обновления Spring?
© Netcracker 2016 31
•Не стоит злоупотреблять prototype
bean’ами. Если singleton, то singleton
Prototype vs singleton
© Netcracker 2016 32
•Не стоит злоупотреблять prototype
bean’ами. Если singleton, то singleton
•Замена getBean на
javax.inject.Provider<...> лишь
ухудшает время работы
•
Prototype vs singleton
© Netcracker 2016 33
@Pointcut(
"execution(
public* my.service.*ServiceImpl.*(..))”
)
Spring AOP
© Netcracker 2016 34
•OutOfMemory: perm gen
Spring AOP
© Netcracker 2016 35
•OutOfMemory: perm gen
•В хипдампе куча java.lang.reflect.Method
Spring AOP
© Netcracker 2016 36
•OutOfMemory: perm gen
•В хипдампе куча java.lang.reflect.Method
•Method’ы занимают 100-500MiB
Spring AOP
© Netcracker 2016 37
•OutOfMemory: perm gen
•В хипдампе куча java.lang.reflect.Method
•Method’ы занимают 100-500MiB
•Все они лежат в AspectJExpressionPointcut
Spring AOP
© Netcracker 2016 38
@Pointcut(
"execution(
public* my.service.*ServiceImpl.*(..))”
)
Spring AOP
© Netcracker 2016 39
•Решение: добавлять
within(my.package.service.business..*)
Spring AOP vs AspectJ
© Netcracker 2016 40
•Решение: добавлять
within(my.package.service.business..*)
•Разумеется, AspectJ рекомендуют
использовать within всегда:
http://dev.eclipse.org/mhonarc/lists/aspectj-
users/msg10969.html
•
Spring AOP vs AspectJ
© Netcracker 2016 41
•Cglib используется много где: рукотворный
код, тот же Spring
Cglib
© Netcracker 2016 42
•Cglib используется много где: рукотворный
код, тот же Spring
•Наверняка уже всё исправлено давным-
давно
Cglib
© Netcracker 2016 43
•Cglib используется много где: рукотворный
код, тот же Spring
•Наверняка уже всё исправлено давным-
давно
•Наверняка туда давно никто не заглядывал
Cglib
© Netcracker 2016 44
@Benchmark
public Object newProxy() {
return Beans.newProxy(Beans.class);
}
Cglib: замеряем
© Netcracker 2016 45
0
2
4
6
8
10
12
14
16
18
Cglib 3.1
1 поток 2 потока 4 потока 8 потоков
Замеры Cglib, μs/opБыстрее
© Netcracker 2016 46
0
2
4
6
8
10
12
14
16
18
Cglib 3.1 Cglib 3.2.2
1 поток 2 потока 4 потока 8 потоков
Замеры Cglib, μs/opБыстрее
© Netcracker 2016 47
Benchmark Score
newProxy 2.1 ± 0.3 μs/op
newProxy.alloc.rate 1240 B/op
Стало
newProxy 0.14 ± 0.02 μs/op
newProxy.alloc.rate 256 B/op
Cglib 3.2.2: ждём в очередном Spring
© Netcracker 2016 48
•Skip finalize while building proxy
https://github.com/cglib/cglib/pull/51
•Concurrent cache of generated classes
https://github.com/cglib/cglib/pull/53
План захвата Cglib
© Netcracker 2016 49
•А, может, ну его этот cglib, есть же быстрый
ByteBuddy?
Но есть же ByteBuddy
© Netcracker 2016 50
•А, может, ну его этот cglib, есть же быстрый
ByteBuddy?
@Benchmark
public ExampleClass benchmarkCglib() {
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(false);
ByteBuddy, jmh тест
© Netcracker 2016 51
•А, может, ну его этот cglib, есть же быстрый
ByteBuddy?
@Benchmark
public ExampleClass benchmarkCglib() {
Enhancer enhancer = new Enhancer();
enhancer.setUseCache(false);
ByteBuddy, jmh тест
© Netcracker 2016 52
•JMH тесты в ByteBuddy показывают
скорость создания классов
•Постоянно создавать классы нехорошо
•Значит, нужно измерять скорость
кэшированного обращения
ByteBuddy, jmh тест
© Netcracker 2016 53
•КО: «Бери pgjdbc»
Подключаемся к PostgreSQL
© Netcracker 2016 54
•КО: «Бери pgjdbc»
•КО: «Используй batch statements»
Подключаемся к PostgreSQL
© Netcracker 2016 55
•КО: «Бери pgjdbc»
•КО: «Используй batch statements»
•Что может пойти не так?
Подключаемся к PostgreSQL
© Netcracker 2016 56
Connection con = ...;
PreparedStatement ps =
con.prepareStatement("SELECT...");
...
ps.close();
PreparedStatement
© Netcracker 2016 57
Connection con = ...;
PreparedStatement ps =
con.prepareStatement("SELECT...");
...
ps.close();
PreparedStatement
© Netcracker 2016 58
PARSE S_1 as ...; // con.prepareStmt
BIND/EXEC
DEALLOCATE // ps.close()
PARSE S_2 as ...;
BIND/EXEC
DEALLOCATE // ps.close()
Работа с PostgreSQL курильщика
© Netcracker 2016 59
PARSE S_1 as ...; 
BIND/EXEC
BIND/EXEC
BIND/EXEC 
BIND/EXEC
BIND/EXEC
...
DEALLOCATE
Работа с PostgreSQL здорового человека
© Netcracker 2016 60
PARSE S_1 as ...;  1 раз в жизни
BIND/EXEC  обработка REST
BIND/EXEC
BIND/EXEC  ещё REST
BIND/EXEC
BIND/EXEC
...
DEALLOCATE  желательно «никогда»
DEALLOCATE
Работа с PostgreSQL здорового человека
© Netcracker 2016 61
Вывод: чтобы работало быстрее,
закрывать statement’ы не нужно
ps = con.prepareStatement(...)
ps.execueQuery();
ps = con.prepareStatement(...)
ps.execueQuery();
...
Счастливые statement’ов не закрывают
© Netcracker 2016 62
Вывод: чтобы работало быстрее,
закрывать statement’ы не нужно
ps = con.prepare...
ps.execueQuery();
ps = con.prepare...
ps.execueQuery();
...
Счастливые statement’ов не закрывают
© Netcracker 2016 63
@Benchmark
public Statement leakStatement() {
return con.createStatement();
}
pgjdbc < 9.4.1202, -Xmx128m, OracleJDK 1.8u40
# Warmup Iteration 1: 1147,070 ns/op
# Warmup Iteration 2: 12101,537 ns/op
# Warmup Iteration 3: 90825,971 ns/op
# Warmup Iteration 4: <failure>
java.lang.OutOfMemoryError: GC overhead limit exceeded
OpenJDK: не все JRE одинаково полезны
© Netcracker 2016 64
@Benchmark
public Statement leakStatement() {
return con.createStatement();
}
pgjdbc >= 9.4.1202, -Xmx128m, OracleJDK 1.8u40
# Warmup Iteration 1: 30 ns/op
# Warmup Iteration 2: 27 ns/op
...
github.com/pgjdbc/pgjdbc/pull/299
Убираем finalize из класса PgConnection
© Netcracker 2016 65
Вывод: чтобы работало быстро, нужно
как-то кэшировать statement’ы
ps = con.prepareStatement("select id,
name ...");
ps.execueQuery();
ps.close();
ps2 = con.prepareStatement("select id,
name ...");
Счастливые statement’ов не закрывают
© Netcracker 2016 66
•Кэш запросов появился в версии 9.4.1202
(2015-08-27)
см. https://github.com/pgjdbc/pgjdbc/pull/319
Кэш запросов в PgJDBC
© Netcracker 2016 67
•Кэш запросов появился в версии 9.4.1202
(2015-08-27)
см. https://github.com/pgjdbc/pgjdbc/pull/319
•Работает прозрачно для приложения
Кэш запросов в PgJDBC
© Netcracker 2016 68
•Кэш запросов появился в версии 9.4.1202
(2015-08-27)
см. https://github.com/pgjdbc/pgjdbc/pull/319
•Работает прозрачно для приложения
•Скорость такая, что PL/PgSQL не нужен
Кэш запросов в PgJDBC
© Netcracker 2016 69
•Кэш запросов появился в версии 9.4.1202
(2015-08-27)
см. https://github.com/pgjdbc/pgjdbc/pull/319
•Работает прозрачно для приложения
•Скорость такая, что PL/PgSQL не нужен
•Server-prepare активируется после 5-го
выполнения (prepareThreshold)
Кэш запросов в PgJDBC
© Netcracker 2016 70
•Конечно, затраты planning time напрямую
зависят от сложности запросов
Цифры где?
© Netcracker 2016 71
•Конечно, затраты planning time напрямую
зависят от сложности запросов
•У нас доходило до 20мс+ planning time на
OLTP запросах: 10КиБ запрос, 170 строк
explain
•
Цифры где?
© Netcracker 2016 72
•Конечно, затраты planning time напрямую
зависят от сложности запросов
•У нас доходило до 20мс+ planning time на
OLTP запросах: 10КиБ запрос, 170 строк
explain
•Стало ~0мс
Цифры где?
© Netcracker 2016 73
Если типы параметров меняются, то server-
prepared statement приходится менять
ps.setInt(1, 42);
...
ps.setNull(1, Types.VARCHAR);
JDBC: Типы параметров
© Netcracker 2016 74
Если типы параметров меняются, то server-
prepared statement приходится менять
ps.setInt(1, 42);
...
ps.setNull(1, Types.VARCHAR);
JDBC: Типы параметров
© Netcracker 2016 75
•Вывод: даже у NULL’ов должен быть
верный тип
JDBC: Тип параметров изменять нельзя
© Netcracker 2016 76
•Вывод: даже у NULL’ов должен быть
верный тип
•Ещё раз: setObject(1, null)
использовать нельзя
JDBC: Тип параметров изменять нельзя
© Netcracker 2016 77
•Перешли на prepared, и запрос замедлился
в 5'000 раз. Как так?
Нежданчик
© Netcracker 2016 78
•Перешли на prepared, и запрос замедлился
в 5'000 раз. Как так?
Нежданчик
A. Бага C. Фича
B. Фича D. Бага
© Netcracker 2016 79
https://gist.github.com/vlsi -> 01_plan_flipper.sql
select *
from plan_flipper -- <- таблица
where skewed = 0 -- 1 млн строк
and non_skewed = 42 -- 20 строк
Нежданчик
© Netcracker 2016 80
https://gist.github.com/vlsi -> 01_plan_flipper.sql
0.1мс  1-е выполнение
0.05мс  2-е выполнение
0.05мс  3-е выполнение
0.05мс  4-е выполнение
0.05мс  5-е выполнение
250 мс  6-е выполнение
Нежданчик
© Netcracker 2016 81
https://gist.github.com/vlsi -> 01_plan_flipper.sql
0.1мс  1-е выполнение
0.05мс  2-е выполнение
0.05мс  3-е выполнение
0.05мс  4-е выполнение
0.05мс  5-е выполнение
250 мс  6-е выполнение
Нежданчик
© Netcracker 2016 82
Запрещаем использование индекса через +0:
select *
from plan_flipper
where skewed+0 = 0  ~ /*+no_index*/
and non_skewed = 42
Чиним
© Netcracker 2016 83
Как сделать опциональные фичи?
•NO_RESULTS
•BOTH_ROWS_AND_STATUS
•DESCRIBE_ONLY
Фичи
© Netcracker 2016 84
Конечно, enum!
enum ... {
NO_RESULTS,
BOTH_ROWS_AND_STATUS,
DESCRIBE_ONLY;
}
Фичи
© Netcracker 2016 85
Конечно, enum!
enum ... {
NO_RESULTS,
BOTH_ROWS_AND_STATUS,
DESCRIBE_ONLY;
}
А на java 1.4?
Фичи
© Netcracker 2016 86
В java 1.4, конечно, interface!
interface ... {
int NO_RESULTS = 1;
int BOTH_ROWS_AND_STATUS = 2;
int DESCRIBE_ONLY = 4;
}
Фичи: java 1.4 наносит ответный удар
© Netcracker 2016 87
Меняем 1 строку, и скорость работы batch insert
возрастает в 10 раз:
https://github.com/pgjdbc/pgjdbc/pull/380
- static int QUERY_FORCE_DESCRIBE_PORTAL = 128;
+ static int QUERY_FORCE_DESCRIBE_PORTAL = 512;
Ужасы нашего городка
© Netcracker 2016 88
Меняем 1 строку, и скорость работы batch insert
возрастает в 10 раз:
https://github.com/pgjdbc/pgjdbc/pull/380
- static int QUERY_FORCE_DESCRIBE_PORTAL = 128;
+ static int QUERY_FORCE_DESCRIBE_PORTAL = 512;
// оказалось, значение 128 уже было занято
static int QUERY_DISALLOW_BATCHING = 128;
Ужасы нашего городка
© Netcracker 2016 89
•WildFly 8.2, JMS
HornetQ
© Netcracker 2016 90
•WildFly 8.2, JMS
•Всего ~100 JMS/сек
HornetQ
© Netcracker 2016 91
•WildFly 8.2, JMS
•Всего ~100 JMS/сек
•1 вызов sendMessage – 5-30 секунд
HornetQ
© Netcracker 2016 92
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 93
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 94
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 95
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at org.hornetq ... ClientProducerImpl.sendRegularMessage
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 96
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at org.hornetq ... ClientProducerImpl.sendRegularMessage
at org.hornetq ... ClientProducerImpl.doSend
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 97
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at org.hornetq ... ClientProducerImpl.sendRegularMessage
at org.hornetq ... ClientProducerImpl.doSend
at org.hornetq ... ClientProducerImpl.send
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 98
at java.util.concurrent.Semaphore.tryAcquire
at org.hornetq ... ClientProducerCreditsImpl.acquireCredits
at org.hornetq ... ClientProducerImpl.sendRegularMessage
at org.hornetq ... ClientProducerImpl.doSend
at org.hornetq ... ClientProducerImpl.send
at org.hornetq ... HornetQMessageProducer.doSendx
at com ... JMSSender.sendMessage
kill -3 профайлер
© Netcracker 2016 99
• 'Producer Window Size’ на connection factory
Backpressure
© Netcracker 2016 100
• 'Producer Window Size’ на connection factory
• address-settings -> address-setting -> max-size-bytes
Backpressure
© Netcracker 2016 101
• 'Producer Window Size’ на connection factory
• address-settings -> address-setting -> max-size-bytes
• Если в JMS очереди накапливается 10МиБ, то отправка
JMS начинает притормаживать
Backpressure
© Netcracker 2016 102
• 'Producer Window Size’ на connection factory
• address-settings -> address-setting -> max-size-bytes
• Если в JMS очереди накапливается 10МиБ, то отправка
JMS начинает притормаживать
<address-settings>
<address-setting match="#">
<max-size-bytes>10 485 760</max-size-bytes>
…
Backpressure
© Netcracker 2016 103
•Настраиваем max-size-bytes для каждой
очереди
Backpressure: чиним
© Netcracker 2016 104
•Настраиваем max-size-bytes для каждой
очереди
•Либо смотрим в сторону RxJava
Backpressure: чиним
© Netcracker 2016 105
•Старт приложения на WF 8.2 занимает 2-5
минут
WildFly: пытаемся взлететь
© Netcracker 2016 106
•Старт приложения на WF 8.2 занимает 2-5
минут
•Concurrent deploy работает плохо
WildFly: пытаемся взлететь
© Netcracker 2016 107
•Старт приложения на WF 8.2 занимает 2-5
минут
•Concurrent deploy работает плохо
•Spring xml app config анализирует все
jar’ники
WildFly: пытаемся взлететь
© Netcracker 2016 108
•Уменьшать размер jar (исключать лишние)
• WildFly копирует jar в /tmp при запуске
WildFly: как чинить
© Netcracker 2016 109
•Уменьшать размер jar (исключать лишние)
• WildFly копирует jar в /tmp при запуске
•Делать патчи на WF, чтобы он не
складывал строки
• https://github.com/jbossas/jboss-vfs/pull/25
• https://github.com/wildfly/wildfly-core/pull/1219
WildFly: как чинить
© Netcracker 2016 110
•Уменьшать размер jar (исключать лишние)
• WildFly копирует jar в /tmp при запуске
•Делать патчи на WF, чтобы он не
складывал строки
• https://github.com/jbossas/jboss-vfs/pull/25
• https://github.com/wildfly/wildfly-core/pull/1219
•Профилировать запуск вашего WF (kill -3
profiler)
WildFly: как чинить
© Netcracker 2016 111
Самое главное в CI –
переменные окружения
Jenkins
© Netcracker 2016 112
https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin
Jenkins: EnvInjectPlugin
© Netcracker 2016 113
Пишем по образу и подобию:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORAC
LE_HOME/…
PATH=$PATH:$ORACLE/bin:…
Jenkins: EnvInjectPlugin
© Netcracker 2016 114
EnvInjectEnvVars.resolveVars()
Jenkins: EnvInjectPlugin
© Netcracker 2016 115
EnvInjectEnvVars.resolveVars()
-> hudson.Util.replaceMacro()
Jenkins: EnvInjectPlugin
© Netcracker 2016 116
EnvInjectEnvVars.resolveVars()
-> hudson.Util.replaceMacro()
-> OutOfMemoryError.<init>()
Jenkins: EnvInjectPlugin
© Netcracker 2016 117
$LD_LIBRARY_PATH:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:$ORACLE_HOME/lib
:$ORACLE_HOME/lib:...
Jenkins: EnvInjectPlugin
© Netcracker 2016 118
https://issues.jenkins-ci.org/browse/JENKINS-
19856
^^^ с вами с 2013 года
Jenkins: EnvInjectPlugin
© Netcracker 2016 119
•Общение Jenkins master и slave тщательно
логируется
Jenkins: master vs slave
© Netcracker 2016 120
•Общение Jenkins master и slave тщательно
логируется
•«Разумеется», в памяти хранятся
последние 1000 записей
Jenkins: master vs slave
© Netcracker 2016 121
•Общение Jenkins master и slave тщательно
логируется
•«Разумеется», в памяти хранятся
последние 1000 записей
•Н
а эти логи может уходить 100-200МиБ
Jenkins: master vs slave
© Netcracker 2016 122
•Общение Jenkins master и slave тщательно
логируется
•«Разумеется», в памяти хранятся
последние 1000 записей
•Н
•Да, да. Логи хранятся в памяти и никогда не
попадают в файл
Jenkins: master vs slave
© Netcracker 2016 123
•Хорошо, что есть опция
• -Dhudson.remoting.ExportTable.unexportLog=0
Jenkins: master vs slave
© Netcracker 2016 124
•Хорошо, что есть опция
• -Dhudson.remoting.ExportTable.unexportLog=0
•Разумеется, в Google ровно один результат
Jenkins: master vs slave
© Netcracker 2016 125
•Хорошо, что есть опция
• -Dhudson.remoting.ExportTable.unexportLog=0
•Разумеется, в Google ровно один результат
•На исходный код, где она определена :)
Jenkins: master vs slave
© Netcracker 2016 126
•Оказалось, что запуск master занимает 50
минут
• 3000 jobs, 10-500 runs per job
• 24 CPU, 64 GiB RAM
• -Xmx40g
Jenkins: запускаемся
© Netcracker 2016 127
•При старте, Jenkins инициализирует job’ы
Jenkins: файлы разные нужны, файлы разные важны
© Netcracker 2016 128
•При старте, Jenkins инициализирует job’ы
•Maven job загружает данные по всем
запускам
Jenkins: файлы разные нужны, файлы разные важны
© Netcracker 2016 129
•При старте, Jenkins инициализирует job’ы
•Maven job загружает данные по всем
запускам
•В
каждом запуске есть fingerprint’ы, они тоже
грузятся
Jenkins: файлы разные нужны, файлы разные важны
© Netcracker 2016 130
•При старте, Jenkins инициализирует job’ы
•Maven job загружает данные по всем
запускам
•В
•В итоге много-много операций с диском
•и тоже грузятся
Jenkins: файлы разные нужны, файлы разные важны
© Netcracker 2016 131
•Решение в лоб: удалить fingerprint’ы перед
запуском
Jenkins: чиним
© Netcracker 2016 132
•Решение в лоб: удалить fingerprint’ы перед
запуском
•Более сложное: не плодить fingerprint’ы
Jenkins: чиним
© Netcracker 2016 133
•Решение в лоб: удалить fingerprint’ы перед
запуском
•Более сложное: не плодить fingerprint’ы
•Поможет и сокращение хранимой истории
Jenkins: чиним
© Netcracker 2016 134
•Решение в лоб: удалить fingerprint’ы перед
запуском
•Более сложное: не плодить fingerprint’ы
•Поможет и сокращение хранимой истории
•В идеальном мире нужно разбираться с
maven-jenkins-plugin
Jenkins: чиним
© Netcracker 2016 135
Кто виноват и что делать?
© Netcracker 2016 136
•Владимир Ситников
•Инженер по производительности в Netcracker
•sitnikov@netcracker.com
•@VladimirSitnikv
С вами был
© Netcracker 2016 137
Вопросы?

More Related Content

PPTX
Implement your own profiler with blackjack and fun
PPTX
Трудовые будни инженера производительности
PPTX
PostgreSQL и JDBC: выжимаем все соки
PPTX
A step-by-step approach toward high quality OutOfMemoryError analysis
PDF
Подводные камни в нагрузочном тестировании
PPTX
Regular expressions
PPTX
Do it yourself profiler
PPTX
Разбор сложных случаев OutOfMemoryError
Implement your own profiler with blackjack and fun
Трудовые будни инженера производительности
PostgreSQL и JDBC: выжимаем все соки
A step-by-step approach toward high quality OutOfMemoryError analysis
Подводные камни в нагрузочном тестировании
Regular expressions
Do it yourself profiler
Разбор сложных случаев OutOfMemoryError

What's hot (20)

PPTX
Производительность open source решений
PDF
Быстрое построение backendов c помощью реактивных потоков
PDF
Организация процесса регулярной обработки больших объемов данных
PPTX
Zabbix 3.4 - простая непростая дружба с сообществом / Алексей Владышев (Zabbix)
PPTX
Kubernetes
PDF
Реактивный двигатель вашего Android приложения
PDF
Алексей Романчук «Реактивное программирование»
PDF
Илья Кудинов
PDF
Selenium grid on-demand
PPTX
Всевидящее око. Мониторинг нагрузочного тестирования с InfluxDB и Grafana
PDF
Deployment to production with an unexpected load
PDF
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
PPTX
Service Discovery. More that it seems
PPTX
Переезжаем с Zabbix на Prometheus / Василий Озеров (fevlake)
PPT
Ядро автоматизации под микро-сервисную архитектуру
PDF
10M tests per day
PDF
Эволюционный дизайн. Joker Students Day 2016
PDF
Continuous Delivery with Jenkins: Lessons Learned
PDF
Олег Миколайченко "Как перестать хранить секреты в git и начать использовать ...
PDF
Joker 2015. WILD microSERVICES
Производительность open source решений
Быстрое построение backendов c помощью реактивных потоков
Организация процесса регулярной обработки больших объемов данных
Zabbix 3.4 - простая непростая дружба с сообществом / Алексей Владышев (Zabbix)
Kubernetes
Реактивный двигатель вашего Android приложения
Алексей Романчук «Реактивное программирование»
Илья Кудинов
Selenium grid on-demand
Всевидящее око. Мониторинг нагрузочного тестирования с InfluxDB и Grafana
Deployment to production with an unexpected load
Что нам стоит DAL построить? Акуляков Артём D2D Just.NET
Service Discovery. More that it seems
Переезжаем с Zabbix на Prometheus / Василий Озеров (fevlake)
Ядро автоматизации под микро-сервисную архитектуру
10M tests per day
Эволюционный дизайн. Joker Students Day 2016
Continuous Delivery with Jenkins: Lessons Learned
Олег Миколайченко "Как перестать хранить секреты в git и начать использовать ...
Joker 2015. WILD microSERVICES
Ad

Viewers also liked (20)

PPTX
PostgreSQL and JDBC: striving for high performance
PDF
Семантика final полей в java
PPT
High Performance Jdbc
PDF
67 - Spring. Начальные знания
PDF
Final field semantics
PDF
Контроль за стилем кода — Кирилл Борисов
PDF
Григорий Липин: Автоматизация нагрузочного тестирования
PDF
«CI. Jenkins. 2GIS» — Игорь Павлов, 2ГИС
PDF
Дмитрий Пронин – Python для веба
PPTX
Openstack Third-Party CI and the review of a few Openstack Infrastructure pro...
PDF
Developing PostgreSQL Performance, Simon Riggs
PDF
jobDSL plugin: настройка jenkins ci скриптом
PDF
Разработка Enterprise-приложения на основе Spring Framework
PDF
Непрерывный анализ качества кода с помощью SonarQube
PPTX
Konstantin slisenko - Spring Framework
PPTX
Highload в ВУЗе идеализм, расчётливый менеджмент или пустые надежды / Артем К...
PDF
Ceph BlueStore - новый тип хранилища в Ceph / Максим Воронцов, (Redsys)
PDF
66 - Spring. Spring и JSF
PDF
Apache Camel + Apache ActiveMQ persistence
PPT
Движение по хрупкому дну / Сергей Караткевич (servers.ru)
PostgreSQL and JDBC: striving for high performance
Семантика final полей в java
High Performance Jdbc
67 - Spring. Начальные знания
Final field semantics
Контроль за стилем кода — Кирилл Борисов
Григорий Липин: Автоматизация нагрузочного тестирования
«CI. Jenkins. 2GIS» — Игорь Павлов, 2ГИС
Дмитрий Пронин – Python для веба
Openstack Third-Party CI and the review of a few Openstack Infrastructure pro...
Developing PostgreSQL Performance, Simon Riggs
jobDSL plugin: настройка jenkins ci скриптом
Разработка Enterprise-приложения на основе Spring Framework
Непрерывный анализ качества кода с помощью SonarQube
Konstantin slisenko - Spring Framework
Highload в ВУЗе идеализм, расчётливый менеджмент или пустые надежды / Артем К...
Ceph BlueStore - новый тип хранилища в Ceph / Максим Воронцов, (Redsys)
66 - Spring. Spring и JSF
Apache Camel + Apache ActiveMQ persistence
Движение по хрупкому дну / Сергей Караткевич (servers.ru)
Ad

Similar to Проблемы производительности open source библиотек (20)

PPTX
Jenkins 2.0: Организуем тестирование в составе Continuous Delivery
PDF
Moscow Jenkins Meetup #1. Pipeline для инженеров. Обзор экосистемы
PDF
Леонид Васильев "Python в инфраструктуре поиска"
PPTX
Асинхронность и сопрограммы
PDF
Drupal code sprint для новичков
PPT
Где кончается react native? / Павел Кондратенко (Rambler&Co)
PDF
Unsafe: to be or to be removed?
PDF
Борис Павлович - Производительность и масштабируемость OpenStack
PDF
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
PPT
Easy authcache 2 кеширование для pro родионов игорь
PDF
Тестируй это / Виктор Русакович (GP Solutions)
PDF
GitLab, Prometheus и Grafana с Kubernetes
PDF
Инфраструктура распределенных приложений на Node.js
PDF
"Непрерывная интеграция или "Кто всё сломал?", Виктор Русакович, MoscowJS 23
PDF
Zero Downtime PHP Deployment with Envoyer And Forge
PDF
Алексей Ильенко "In real-time with Apache Kafka"
PPTX
javaaaaddawdawdawdasdsadsaddadadm11n.pptx
PPT
Easy authcache 2 кэширование для pro. Родионов Игорь
PPTX
Multithreading in java past and actual
PPTX
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
Jenkins 2.0: Организуем тестирование в составе Continuous Delivery
Moscow Jenkins Meetup #1. Pipeline для инженеров. Обзор экосистемы
Леонид Васильев "Python в инфраструктуре поиска"
Асинхронность и сопрограммы
Drupal code sprint для новичков
Где кончается react native? / Павел Кондратенко (Rambler&Co)
Unsafe: to be or to be removed?
Борис Павлович - Производительность и масштабируемость OpenStack
Регрессионное тестирование на lenta.ru, Кондратенко Павел, Rambler&Co, Moscow...
Easy authcache 2 кеширование для pro родионов игорь
Тестируй это / Виктор Русакович (GP Solutions)
GitLab, Prometheus и Grafana с Kubernetes
Инфраструктура распределенных приложений на Node.js
"Непрерывная интеграция или "Кто всё сломал?", Виктор Русакович, MoscowJS 23
Zero Downtime PHP Deployment with Envoyer And Forge
Алексей Ильенко "In real-time with Apache Kafka"
javaaaaddawdawdawdasdsadsaddadadm11n.pptx
Easy authcache 2 кэширование для pro. Родионов Игорь
Multithreading in java past and actual
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#

Проблемы производительности open source библиотек

  • 1. © Netcracker 2016 1 Производительность open source решений Владимир Ситников JPoint 2016
  • 2. © Netcracker 2016 2 •Владимир Ситников •Инженер по производительности в Netcracker, 10 лет •sitnikov@netcracker.com •@VladimirSitnikv Кто я
  • 3. © Netcracker 2016 3 •Spring •Cglib •Pgjdbc •HornetQ •Wildfly •Jenkins План
  • 4. © Netcracker 2016 4 План Наш любимый enterprise продукт
  • 5. © Netcracker 2016 5 Внедряем Spring в сжатые сроки Монолит spring
  • 6. © Netcracker 2016 6 Внедряем Spring в сжатые сроки Монолит spring
  • 7. © Netcracker 2016 7 Внедряем Spring в сжатые сроки Core Security UI
  • 8. © Netcracker 2016 8 Внедряем Spring в сжатые сроки Core Security UI
  • 9. © Netcracker 2016 9 Внедряем Spring в сжатые сроки Core Security UI
  • 10. © Netcracker 2016 10 •Когда нужен бин, то выполняем beanFactory.getBean(Security.class) В UI spring пока не наступил
  • 11. © Netcracker 2016 11 •Когда нужен бин, то выполняем beanFactory.getBean(Security.class) •Но где взять beanFactory? В UI spring пока не наступил
  • 12. © Netcracker 2016 12 •Когда нужен бин, то выполняем beanFactory.getBean(Security.class) •Но где взять beanFactory? •Правильно, Паблик Морозов поможет нам В UI spring пока не наступил
  • 13. © Netcracker 2016 13 public class AppContext implements BeanFactoryAware { static public BeanFactory beanFactory; ... Получаем бин
  • 14. © Netcracker 2016 14 public class AppContext implements BeanFactoryAware { static public BeanFactory beanFactory; ... AppContext.beanFactory.getBean(Security.class) Получаем бин
  • 15. © Netcracker 2016 15 •Работает Spring.getBean
  • 16. © Netcracker 2016 16 •Работает •Но медленно-медленно Spring.getBean
  • 17. © Netcracker 2016 17 •Работает •Но медленно-медленно •На getBean и 50% времени может уходить Spring.getBean
  • 18. © Netcracker 2016 18 •Java Flight Recorder Подходящие для анализа инструменты
  • 19. © Netcracker 2016 19 •Java Flight Recorder •kill -3 profiler (poormansprofiler.org) Подходящие для анализа инструменты
  • 20. © Netcracker 2016 20 •Java Flight Recorder •kill -3 profiler (poormansprofiler.org) •Инструментирующий профилировщик. Например самописный, настроенный на getBean Подходящие для анализа инструменты
  • 21. © Netcracker 2016 21 160 секунд на getBean. Здорово?
  • 22. © Netcracker 2016 22 160 секунд на getBean. Здорово? •Java 8 / Spring 4.1.7
  • 23. © Netcracker 2016 23 •SPR-6870 Cache by-type lookups in DefaultListableBeanFactory Проверяем известные проблемы
  • 24. © Netcracker 2016 24 •SPR-6870 Cache by-type lookups in DefaultListableBeanFactory Проверяем известные проблемы ЯЗЬ!!!
  • 25. © Netcracker 2016 25 •SPR-6870 Cache by-type lookups in DefaultListableBeanFactory •Fix version: 3.2 M1, а у нас 4.1+  Проверяем известные проблемы
  • 26. © Netcracker 2016 26 Flight Recorder, allocations in new TLAB
  • 27. © Netcracker 2016 27 protected Object getCacheKey( Class<?> beanClass, String beanName) { return beanClass.getName() + "_" + beanName; } AbstractAutoProxyCreator
  • 28. © Netcracker 2016 28 protected Object getCacheKey( Class<?> beanClass, String beanName) { return beanClass.getName() + "_" + beanName; } AbstractAutoProxyCreator
  • 29. © Netcracker 2016 29 protected Object getCacheKey( Class<?> beanClass, String beanName) { return beanName == null ? beanClass : ...; } github.com/spring-projects/spring- framework/pull/913 AbstractAutoProxyCreator
  • 30. © Netcracker 2016 30 public class SharedSecrets { @Inject public Security security; @PostConstruct public void init() { INSTANCE = this; } public static volatile SharedSecrets INSTANCE; Как выжить без обновления Spring?
  • 31. © Netcracker 2016 31 •Не стоит злоупотреблять prototype bean’ами. Если singleton, то singleton Prototype vs singleton
  • 32. © Netcracker 2016 32 •Не стоит злоупотреблять prototype bean’ами. Если singleton, то singleton •Замена getBean на javax.inject.Provider<...> лишь ухудшает время работы • Prototype vs singleton
  • 33. © Netcracker 2016 33 @Pointcut( "execution( public* my.service.*ServiceImpl.*(..))” ) Spring AOP
  • 34. © Netcracker 2016 34 •OutOfMemory: perm gen Spring AOP
  • 35. © Netcracker 2016 35 •OutOfMemory: perm gen •В хипдампе куча java.lang.reflect.Method Spring AOP
  • 36. © Netcracker 2016 36 •OutOfMemory: perm gen •В хипдампе куча java.lang.reflect.Method •Method’ы занимают 100-500MiB Spring AOP
  • 37. © Netcracker 2016 37 •OutOfMemory: perm gen •В хипдампе куча java.lang.reflect.Method •Method’ы занимают 100-500MiB •Все они лежат в AspectJExpressionPointcut Spring AOP
  • 38. © Netcracker 2016 38 @Pointcut( "execution( public* my.service.*ServiceImpl.*(..))” ) Spring AOP
  • 39. © Netcracker 2016 39 •Решение: добавлять within(my.package.service.business..*) Spring AOP vs AspectJ
  • 40. © Netcracker 2016 40 •Решение: добавлять within(my.package.service.business..*) •Разумеется, AspectJ рекомендуют использовать within всегда: http://dev.eclipse.org/mhonarc/lists/aspectj- users/msg10969.html • Spring AOP vs AspectJ
  • 41. © Netcracker 2016 41 •Cglib используется много где: рукотворный код, тот же Spring Cglib
  • 42. © Netcracker 2016 42 •Cglib используется много где: рукотворный код, тот же Spring •Наверняка уже всё исправлено давным- давно Cglib
  • 43. © Netcracker 2016 43 •Cglib используется много где: рукотворный код, тот же Spring •Наверняка уже всё исправлено давным- давно •Наверняка туда давно никто не заглядывал Cglib
  • 44. © Netcracker 2016 44 @Benchmark public Object newProxy() { return Beans.newProxy(Beans.class); } Cglib: замеряем
  • 45. © Netcracker 2016 45 0 2 4 6 8 10 12 14 16 18 Cglib 3.1 1 поток 2 потока 4 потока 8 потоков Замеры Cglib, μs/opБыстрее
  • 46. © Netcracker 2016 46 0 2 4 6 8 10 12 14 16 18 Cglib 3.1 Cglib 3.2.2 1 поток 2 потока 4 потока 8 потоков Замеры Cglib, μs/opБыстрее
  • 47. © Netcracker 2016 47 Benchmark Score newProxy 2.1 ± 0.3 μs/op newProxy.alloc.rate 1240 B/op Стало newProxy 0.14 ± 0.02 μs/op newProxy.alloc.rate 256 B/op Cglib 3.2.2: ждём в очередном Spring
  • 48. © Netcracker 2016 48 •Skip finalize while building proxy https://github.com/cglib/cglib/pull/51 •Concurrent cache of generated classes https://github.com/cglib/cglib/pull/53 План захвата Cglib
  • 49. © Netcracker 2016 49 •А, может, ну его этот cglib, есть же быстрый ByteBuddy? Но есть же ByteBuddy
  • 50. © Netcracker 2016 50 •А, может, ну его этот cglib, есть же быстрый ByteBuddy? @Benchmark public ExampleClass benchmarkCglib() { Enhancer enhancer = new Enhancer(); enhancer.setUseCache(false); ByteBuddy, jmh тест
  • 51. © Netcracker 2016 51 •А, может, ну его этот cglib, есть же быстрый ByteBuddy? @Benchmark public ExampleClass benchmarkCglib() { Enhancer enhancer = new Enhancer(); enhancer.setUseCache(false); ByteBuddy, jmh тест
  • 52. © Netcracker 2016 52 •JMH тесты в ByteBuddy показывают скорость создания классов •Постоянно создавать классы нехорошо •Значит, нужно измерять скорость кэшированного обращения ByteBuddy, jmh тест
  • 53. © Netcracker 2016 53 •КО: «Бери pgjdbc» Подключаемся к PostgreSQL
  • 54. © Netcracker 2016 54 •КО: «Бери pgjdbc» •КО: «Используй batch statements» Подключаемся к PostgreSQL
  • 55. © Netcracker 2016 55 •КО: «Бери pgjdbc» •КО: «Используй batch statements» •Что может пойти не так? Подключаемся к PostgreSQL
  • 56. © Netcracker 2016 56 Connection con = ...; PreparedStatement ps = con.prepareStatement("SELECT..."); ... ps.close(); PreparedStatement
  • 57. © Netcracker 2016 57 Connection con = ...; PreparedStatement ps = con.prepareStatement("SELECT..."); ... ps.close(); PreparedStatement
  • 58. © Netcracker 2016 58 PARSE S_1 as ...; // con.prepareStmt BIND/EXEC DEALLOCATE // ps.close() PARSE S_2 as ...; BIND/EXEC DEALLOCATE // ps.close() Работа с PostgreSQL курильщика
  • 59. © Netcracker 2016 59 PARSE S_1 as ...;  BIND/EXEC BIND/EXEC BIND/EXEC  BIND/EXEC BIND/EXEC ... DEALLOCATE Работа с PostgreSQL здорового человека
  • 60. © Netcracker 2016 60 PARSE S_1 as ...;  1 раз в жизни BIND/EXEC  обработка REST BIND/EXEC BIND/EXEC  ещё REST BIND/EXEC BIND/EXEC ... DEALLOCATE  желательно «никогда» DEALLOCATE Работа с PostgreSQL здорового человека
  • 61. © Netcracker 2016 61 Вывод: чтобы работало быстрее, закрывать statement’ы не нужно ps = con.prepareStatement(...) ps.execueQuery(); ps = con.prepareStatement(...) ps.execueQuery(); ... Счастливые statement’ов не закрывают
  • 62. © Netcracker 2016 62 Вывод: чтобы работало быстрее, закрывать statement’ы не нужно ps = con.prepare... ps.execueQuery(); ps = con.prepare... ps.execueQuery(); ... Счастливые statement’ов не закрывают
  • 63. © Netcracker 2016 63 @Benchmark public Statement leakStatement() { return con.createStatement(); } pgjdbc < 9.4.1202, -Xmx128m, OracleJDK 1.8u40 # Warmup Iteration 1: 1147,070 ns/op # Warmup Iteration 2: 12101,537 ns/op # Warmup Iteration 3: 90825,971 ns/op # Warmup Iteration 4: <failure> java.lang.OutOfMemoryError: GC overhead limit exceeded OpenJDK: не все JRE одинаково полезны
  • 64. © Netcracker 2016 64 @Benchmark public Statement leakStatement() { return con.createStatement(); } pgjdbc >= 9.4.1202, -Xmx128m, OracleJDK 1.8u40 # Warmup Iteration 1: 30 ns/op # Warmup Iteration 2: 27 ns/op ... github.com/pgjdbc/pgjdbc/pull/299 Убираем finalize из класса PgConnection
  • 65. © Netcracker 2016 65 Вывод: чтобы работало быстро, нужно как-то кэшировать statement’ы ps = con.prepareStatement("select id, name ..."); ps.execueQuery(); ps.close(); ps2 = con.prepareStatement("select id, name ..."); Счастливые statement’ов не закрывают
  • 66. © Netcracker 2016 66 •Кэш запросов появился в версии 9.4.1202 (2015-08-27) см. https://github.com/pgjdbc/pgjdbc/pull/319 Кэш запросов в PgJDBC
  • 67. © Netcracker 2016 67 •Кэш запросов появился в версии 9.4.1202 (2015-08-27) см. https://github.com/pgjdbc/pgjdbc/pull/319 •Работает прозрачно для приложения Кэш запросов в PgJDBC
  • 68. © Netcracker 2016 68 •Кэш запросов появился в версии 9.4.1202 (2015-08-27) см. https://github.com/pgjdbc/pgjdbc/pull/319 •Работает прозрачно для приложения •Скорость такая, что PL/PgSQL не нужен Кэш запросов в PgJDBC
  • 69. © Netcracker 2016 69 •Кэш запросов появился в версии 9.4.1202 (2015-08-27) см. https://github.com/pgjdbc/pgjdbc/pull/319 •Работает прозрачно для приложения •Скорость такая, что PL/PgSQL не нужен •Server-prepare активируется после 5-го выполнения (prepareThreshold) Кэш запросов в PgJDBC
  • 70. © Netcracker 2016 70 •Конечно, затраты planning time напрямую зависят от сложности запросов Цифры где?
  • 71. © Netcracker 2016 71 •Конечно, затраты planning time напрямую зависят от сложности запросов •У нас доходило до 20мс+ planning time на OLTP запросах: 10КиБ запрос, 170 строк explain • Цифры где?
  • 72. © Netcracker 2016 72 •Конечно, затраты planning time напрямую зависят от сложности запросов •У нас доходило до 20мс+ planning time на OLTP запросах: 10КиБ запрос, 170 строк explain •Стало ~0мс Цифры где?
  • 73. © Netcracker 2016 73 Если типы параметров меняются, то server- prepared statement приходится менять ps.setInt(1, 42); ... ps.setNull(1, Types.VARCHAR); JDBC: Типы параметров
  • 74. © Netcracker 2016 74 Если типы параметров меняются, то server- prepared statement приходится менять ps.setInt(1, 42); ... ps.setNull(1, Types.VARCHAR); JDBC: Типы параметров
  • 75. © Netcracker 2016 75 •Вывод: даже у NULL’ов должен быть верный тип JDBC: Тип параметров изменять нельзя
  • 76. © Netcracker 2016 76 •Вывод: даже у NULL’ов должен быть верный тип •Ещё раз: setObject(1, null) использовать нельзя JDBC: Тип параметров изменять нельзя
  • 77. © Netcracker 2016 77 •Перешли на prepared, и запрос замедлился в 5'000 раз. Как так? Нежданчик
  • 78. © Netcracker 2016 78 •Перешли на prepared, и запрос замедлился в 5'000 раз. Как так? Нежданчик A. Бага C. Фича B. Фича D. Бага
  • 79. © Netcracker 2016 79 https://gist.github.com/vlsi -> 01_plan_flipper.sql select * from plan_flipper -- <- таблица where skewed = 0 -- 1 млн строк and non_skewed = 42 -- 20 строк Нежданчик
  • 80. © Netcracker 2016 80 https://gist.github.com/vlsi -> 01_plan_flipper.sql 0.1мс  1-е выполнение 0.05мс  2-е выполнение 0.05мс  3-е выполнение 0.05мс  4-е выполнение 0.05мс  5-е выполнение 250 мс  6-е выполнение Нежданчик
  • 81. © Netcracker 2016 81 https://gist.github.com/vlsi -> 01_plan_flipper.sql 0.1мс  1-е выполнение 0.05мс  2-е выполнение 0.05мс  3-е выполнение 0.05мс  4-е выполнение 0.05мс  5-е выполнение 250 мс  6-е выполнение Нежданчик
  • 82. © Netcracker 2016 82 Запрещаем использование индекса через +0: select * from plan_flipper where skewed+0 = 0  ~ /*+no_index*/ and non_skewed = 42 Чиним
  • 83. © Netcracker 2016 83 Как сделать опциональные фичи? •NO_RESULTS •BOTH_ROWS_AND_STATUS •DESCRIBE_ONLY Фичи
  • 84. © Netcracker 2016 84 Конечно, enum! enum ... { NO_RESULTS, BOTH_ROWS_AND_STATUS, DESCRIBE_ONLY; } Фичи
  • 85. © Netcracker 2016 85 Конечно, enum! enum ... { NO_RESULTS, BOTH_ROWS_AND_STATUS, DESCRIBE_ONLY; } А на java 1.4? Фичи
  • 86. © Netcracker 2016 86 В java 1.4, конечно, interface! interface ... { int NO_RESULTS = 1; int BOTH_ROWS_AND_STATUS = 2; int DESCRIBE_ONLY = 4; } Фичи: java 1.4 наносит ответный удар
  • 87. © Netcracker 2016 87 Меняем 1 строку, и скорость работы batch insert возрастает в 10 раз: https://github.com/pgjdbc/pgjdbc/pull/380 - static int QUERY_FORCE_DESCRIBE_PORTAL = 128; + static int QUERY_FORCE_DESCRIBE_PORTAL = 512; Ужасы нашего городка
  • 88. © Netcracker 2016 88 Меняем 1 строку, и скорость работы batch insert возрастает в 10 раз: https://github.com/pgjdbc/pgjdbc/pull/380 - static int QUERY_FORCE_DESCRIBE_PORTAL = 128; + static int QUERY_FORCE_DESCRIBE_PORTAL = 512; // оказалось, значение 128 уже было занято static int QUERY_DISALLOW_BATCHING = 128; Ужасы нашего городка
  • 89. © Netcracker 2016 89 •WildFly 8.2, JMS HornetQ
  • 90. © Netcracker 2016 90 •WildFly 8.2, JMS •Всего ~100 JMS/сек HornetQ
  • 91. © Netcracker 2016 91 •WildFly 8.2, JMS •Всего ~100 JMS/сек •1 вызов sendMessage – 5-30 секунд HornetQ
  • 92. © Netcracker 2016 92 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at com ... JMSSender.sendMessage kill -3 профайлер
  • 93. © Netcracker 2016 93 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at com ... JMSSender.sendMessage kill -3 профайлер
  • 94. © Netcracker 2016 94 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at com ... JMSSender.sendMessage kill -3 профайлер
  • 95. © Netcracker 2016 95 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at org.hornetq ... ClientProducerImpl.sendRegularMessage at com ... JMSSender.sendMessage kill -3 профайлер
  • 96. © Netcracker 2016 96 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at org.hornetq ... ClientProducerImpl.sendRegularMessage at org.hornetq ... ClientProducerImpl.doSend at com ... JMSSender.sendMessage kill -3 профайлер
  • 97. © Netcracker 2016 97 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at org.hornetq ... ClientProducerImpl.sendRegularMessage at org.hornetq ... ClientProducerImpl.doSend at org.hornetq ... ClientProducerImpl.send at com ... JMSSender.sendMessage kill -3 профайлер
  • 98. © Netcracker 2016 98 at java.util.concurrent.Semaphore.tryAcquire at org.hornetq ... ClientProducerCreditsImpl.acquireCredits at org.hornetq ... ClientProducerImpl.sendRegularMessage at org.hornetq ... ClientProducerImpl.doSend at org.hornetq ... ClientProducerImpl.send at org.hornetq ... HornetQMessageProducer.doSendx at com ... JMSSender.sendMessage kill -3 профайлер
  • 99. © Netcracker 2016 99 • 'Producer Window Size’ на connection factory Backpressure
  • 100. © Netcracker 2016 100 • 'Producer Window Size’ на connection factory • address-settings -> address-setting -> max-size-bytes Backpressure
  • 101. © Netcracker 2016 101 • 'Producer Window Size’ на connection factory • address-settings -> address-setting -> max-size-bytes • Если в JMS очереди накапливается 10МиБ, то отправка JMS начинает притормаживать Backpressure
  • 102. © Netcracker 2016 102 • 'Producer Window Size’ на connection factory • address-settings -> address-setting -> max-size-bytes • Если в JMS очереди накапливается 10МиБ, то отправка JMS начинает притормаживать <address-settings> <address-setting match="#"> <max-size-bytes>10 485 760</max-size-bytes> … Backpressure
  • 103. © Netcracker 2016 103 •Настраиваем max-size-bytes для каждой очереди Backpressure: чиним
  • 104. © Netcracker 2016 104 •Настраиваем max-size-bytes для каждой очереди •Либо смотрим в сторону RxJava Backpressure: чиним
  • 105. © Netcracker 2016 105 •Старт приложения на WF 8.2 занимает 2-5 минут WildFly: пытаемся взлететь
  • 106. © Netcracker 2016 106 •Старт приложения на WF 8.2 занимает 2-5 минут •Concurrent deploy работает плохо WildFly: пытаемся взлететь
  • 107. © Netcracker 2016 107 •Старт приложения на WF 8.2 занимает 2-5 минут •Concurrent deploy работает плохо •Spring xml app config анализирует все jar’ники WildFly: пытаемся взлететь
  • 108. © Netcracker 2016 108 •Уменьшать размер jar (исключать лишние) • WildFly копирует jar в /tmp при запуске WildFly: как чинить
  • 109. © Netcracker 2016 109 •Уменьшать размер jar (исключать лишние) • WildFly копирует jar в /tmp при запуске •Делать патчи на WF, чтобы он не складывал строки • https://github.com/jbossas/jboss-vfs/pull/25 • https://github.com/wildfly/wildfly-core/pull/1219 WildFly: как чинить
  • 110. © Netcracker 2016 110 •Уменьшать размер jar (исключать лишние) • WildFly копирует jar в /tmp при запуске •Делать патчи на WF, чтобы он не складывал строки • https://github.com/jbossas/jboss-vfs/pull/25 • https://github.com/wildfly/wildfly-core/pull/1219 •Профилировать запуск вашего WF (kill -3 profiler) WildFly: как чинить
  • 111. © Netcracker 2016 111 Самое главное в CI – переменные окружения Jenkins
  • 112. © Netcracker 2016 112 https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin Jenkins: EnvInjectPlugin
  • 113. © Netcracker 2016 113 Пишем по образу и подобию: LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORAC LE_HOME/… PATH=$PATH:$ORACLE/bin:… Jenkins: EnvInjectPlugin
  • 114. © Netcracker 2016 114 EnvInjectEnvVars.resolveVars() Jenkins: EnvInjectPlugin
  • 115. © Netcracker 2016 115 EnvInjectEnvVars.resolveVars() -> hudson.Util.replaceMacro() Jenkins: EnvInjectPlugin
  • 116. © Netcracker 2016 116 EnvInjectEnvVars.resolveVars() -> hudson.Util.replaceMacro() -> OutOfMemoryError.<init>() Jenkins: EnvInjectPlugin
  • 117. © Netcracker 2016 117 $LD_LIBRARY_PATH:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:$ORACLE_HOME/lib :$ORACLE_HOME/lib:... Jenkins: EnvInjectPlugin
  • 118. © Netcracker 2016 118 https://issues.jenkins-ci.org/browse/JENKINS- 19856 ^^^ с вами с 2013 года Jenkins: EnvInjectPlugin
  • 119. © Netcracker 2016 119 •Общение Jenkins master и slave тщательно логируется Jenkins: master vs slave
  • 120. © Netcracker 2016 120 •Общение Jenkins master и slave тщательно логируется •«Разумеется», в памяти хранятся последние 1000 записей Jenkins: master vs slave
  • 121. © Netcracker 2016 121 •Общение Jenkins master и slave тщательно логируется •«Разумеется», в памяти хранятся последние 1000 записей •Н а эти логи может уходить 100-200МиБ Jenkins: master vs slave
  • 122. © Netcracker 2016 122 •Общение Jenkins master и slave тщательно логируется •«Разумеется», в памяти хранятся последние 1000 записей •Н •Да, да. Логи хранятся в памяти и никогда не попадают в файл Jenkins: master vs slave
  • 123. © Netcracker 2016 123 •Хорошо, что есть опция • -Dhudson.remoting.ExportTable.unexportLog=0 Jenkins: master vs slave
  • 124. © Netcracker 2016 124 •Хорошо, что есть опция • -Dhudson.remoting.ExportTable.unexportLog=0 •Разумеется, в Google ровно один результат Jenkins: master vs slave
  • 125. © Netcracker 2016 125 •Хорошо, что есть опция • -Dhudson.remoting.ExportTable.unexportLog=0 •Разумеется, в Google ровно один результат •На исходный код, где она определена :) Jenkins: master vs slave
  • 126. © Netcracker 2016 126 •Оказалось, что запуск master занимает 50 минут • 3000 jobs, 10-500 runs per job • 24 CPU, 64 GiB RAM • -Xmx40g Jenkins: запускаемся
  • 127. © Netcracker 2016 127 •При старте, Jenkins инициализирует job’ы Jenkins: файлы разные нужны, файлы разные важны
  • 128. © Netcracker 2016 128 •При старте, Jenkins инициализирует job’ы •Maven job загружает данные по всем запускам Jenkins: файлы разные нужны, файлы разные важны
  • 129. © Netcracker 2016 129 •При старте, Jenkins инициализирует job’ы •Maven job загружает данные по всем запускам •В каждом запуске есть fingerprint’ы, они тоже грузятся Jenkins: файлы разные нужны, файлы разные важны
  • 130. © Netcracker 2016 130 •При старте, Jenkins инициализирует job’ы •Maven job загружает данные по всем запускам •В •В итоге много-много операций с диском •и тоже грузятся Jenkins: файлы разные нужны, файлы разные важны
  • 131. © Netcracker 2016 131 •Решение в лоб: удалить fingerprint’ы перед запуском Jenkins: чиним
  • 132. © Netcracker 2016 132 •Решение в лоб: удалить fingerprint’ы перед запуском •Более сложное: не плодить fingerprint’ы Jenkins: чиним
  • 133. © Netcracker 2016 133 •Решение в лоб: удалить fingerprint’ы перед запуском •Более сложное: не плодить fingerprint’ы •Поможет и сокращение хранимой истории Jenkins: чиним
  • 134. © Netcracker 2016 134 •Решение в лоб: удалить fingerprint’ы перед запуском •Более сложное: не плодить fingerprint’ы •Поможет и сокращение хранимой истории •В идеальном мире нужно разбираться с maven-jenkins-plugin Jenkins: чиним
  • 135. © Netcracker 2016 135 Кто виноват и что делать?
  • 136. © Netcracker 2016 136 •Владимир Ситников •Инженер по производительности в Netcracker •sitnikov@netcracker.com •@VladimirSitnikv С вами был
  • 137. © Netcracker 2016 137 Вопросы?