Upload
vitebsk-dsc
View
237
Download
7
Embed Size (px)
Citation preview
31 ОКТЯБРЯ, 2015
ЭКСТРЕМАЛЬНАЯ
ОПТИМИЗАЦИЯ
ПРОИЗВОДИТЕЛЬНОСТИ
на примере MongoDB Java Driver
Евгений Берлог
Java-разработчик
EPAM
План выступления
С чего все начиналось
Выбор стандартного решения
Что-то пошло не так…
Что мы могли сделать?
Что мы сделали?
Выводы
Исходные условия
OracleCoherence
WEB RESTInternal
Tool
х 15 х 15 х 10
Исходные условия
OracleCoherence
WEB RESTInternal
Tool
MongoDB
х 15 х 15 х 10
Особенности системы
Большие размеры объектов (~1MB)
Много уровней вложенности
Зависимости между объектами
Вложенные массивы
Множество сценариев использования
Ограниченный объем RAM
Выбор фреймворка
M
MORPHIA SPRING DATA
Многообещающий
красавчикУверенный в себе
крепыш
«Плоский» и
гибкий работяга
JAVA DRIVER
+ самописный ORM
Нагрузочное тестирование
100% запросов на чтения
50 параллельных потоков
1 млн запросов
Morphia, секJava-драйвер +
самописный ORM, сек
Документ 10KB 14,0 13,7 (-2,2%)
Документ 100KB 120,0 115,9 (-3,5%)
Документ 1MB 927,2 887,0 (-4,4%)
Суммарное время выполнения запросов
Результаты тестирования
Morphia, секJava-драйвер +
самописный ORM, сек
Документ 10KB 0,101 0,097 (-4,0%)
Документ 100KB 1,044 0,995 (-4,7%)
Документ 1MB 9,377 8,811 (-6,1%)
Суммарное время работы сборщика мусора (GC)
Результаты тестирования
Plain MongoDB driver
Большой объем потребляемой памяти
Сборщик мусора отрабатывает часто
Непредсказуемая производительность и
стабильность
Что же делать?
JUST OPTIMIZE IT.
Что не так с Plain driver?
MongoDB
MongoDB
DriverConverter Service
byte[ ] DBObject Domain
А что, если…
MongoDB
MongoDB
DriverConverter Service
byte[ ] DBObject
ByteArrayToDomainConverter
Domain
Что получилось
MongoDB
DomainMagic
ConverterImproved
MongoDB Driver
byte[ ]
Service
Другие улучшения
Создание строк
Кэширование строк
«Ленивая» загрузка документов
«Ленивая» десериализация
Создание строк?
Да, создание строк
Текущая реализация в драйвере
String createString() {byte[] bytes = new byte[size];readBytes(bytes); // copy bytes from input streamreturn new String(bytes, UTF8_CHARSET);
}
Создание строк
Попытка #1 – Чуть-чуть лучше
String createString() {char[] array = new char[bytes.length];for (int i = 0; i < bytes.length; i++) {
array[i] = (char) bytes[i];}return new String(array);
}
Создание строк
Попытка #2 – Оптимально
String createString() throws IllegalAccessException {char[] array = new char[bytes.length];for (int i = 0; i < bytes.length; i++) {
array[i] = (char) bytes[i];}
String s = new String();Field field = String.class.getDeclaredField("value"); field.set(s, array);return s;
}
Создание 1 млрд строк
Общее время, сек Время GC, сек
new String(byte[ ], UTF-8) 95,8 0,884
new String(char[ ]) 93,0 (-3,0%) 0,861 (-3,0%)
Reflection 92,1 (-3,9%) 0,568 (-36,0%)
Кэширование строк
0xffaa11 0xccff2e
String 1
String 2
... ... ... ...
ConcurrentHashMap
• Ключ – hash от строки
• Значение – CopyOnWriteArrayList<String>
«Ленивая» подгрузка
Domain1
Item*
«Ленивая» подгрузка
Domain Proxy LinkResolver Template
load()
readIds()
resolve()
findByIds(ids)
setItems(resolved)
getItems()
Что получилось
{"_id": "Java","type": "language","father": {
"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true
},"features": /* массив байт */
}
Business rules
Что получилось
{"_id": "Java","type": "language","father": {
"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true
},"features": /* массив байт */
}
Optional
No package
Reflections
Что получилось
{"_id": "Java","type": "language","father": {
"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true
},"features": /* массив байт */
}
Lazy de-serialization
Что получилось
{"_id": "Java","type": "language","father": {
"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true
},"features": [
"object-oriented","static type-checking"
]}
De-serialized array
Что получилось
Java-драйвер + самописный ORM,
сек
«Улучшенный»Java-драйвер,
сек
Документ 10KB 13,7 12,7 (-7,3%)
Документ 100KB 115,9 105,2 (-9,2%)
Документ 1MB 887,0 791,4 (-10,7%)
100% запросов на чтения
50 параллельных потоков
1 млн запросов
Суммарное время выполнения запросов
Что получилось
100% запросов на чтения
50 параллельных потоков
1 млн запросов
Суммарное время работы сборщика мусора (GC)
Java-драйвер + самописный ORM,
сек
«Улучшенный»Java-драйвер,
сек
Документ 10KB 0,097 0,087 (-10,0%)
Документ 100KB 0,995 0,791 (-20,5%)
Документ 1MB 8,811 5,861 (-33,5%)
Недостатки решения
Сложность поддержки
Сложность тестирования
• Соответствие BSON формату
• Коллизии кэширования
• Многопоточность
Java Driver 3.0+
Апрель 2015
API упрощающий интеграцию
Выводы
Вопросы ?