35
31 ОКТЯБРЯ, 2015 ЭКСТРЕМАЛЬНАЯ ОПТИМИЗАЦИЯ ПРОИЗВОДИТЕЛЬНОСТИ на примере MongoDB Java Driver

Экстремальная оптимизация производительности на примере MongoDB Java Driver

Embed Size (px)

Citation preview

Page 1: Экстремальная оптимизация производительности на примере MongoDB Java Driver

31 ОКТЯБРЯ, 2015

ЭКСТРЕМАЛЬНАЯ

ОПТИМИЗАЦИЯ

ПРОИЗВОДИТЕЛЬНОСТИ

на примере MongoDB Java Driver

Page 2: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Евгений Берлог

Java-разработчик

EPAM

Page 3: Экстремальная оптимизация производительности на примере MongoDB Java Driver

План выступления

С чего все начиналось

Выбор стандартного решения

Что-то пошло не так…

Что мы могли сделать?

Что мы сделали?

Выводы

Page 4: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Исходные условия

OracleCoherence

WEB RESTInternal

Tool

х 15 х 15 х 10

Page 5: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Исходные условия

OracleCoherence

WEB RESTInternal

Tool

MongoDB

х 15 х 15 х 10

Page 6: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Особенности системы

Большие размеры объектов (~1MB)

Много уровней вложенности

Зависимости между объектами

Вложенные массивы

Множество сценариев использования

Ограниченный объем RAM

Page 7: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Выбор фреймворка

M

MORPHIA SPRING DATA

Многообещающий

красавчикУверенный в себе

крепыш

«Плоский» и

гибкий работяга

JAVA DRIVER

+ самописный ORM

Page 8: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Нагрузочное тестирование

100% запросов на чтения

50 параллельных потоков

1 млн запросов

Page 9: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Morphia, секJava-драйвер +

самописный ORM, сек

Документ 10KB 14,0 13,7 (-2,2%)

Документ 100KB 120,0 115,9 (-3,5%)

Документ 1MB 927,2 887,0 (-4,4%)

Суммарное время выполнения запросов

Результаты тестирования

Page 10: Экстремальная оптимизация производительности на примере MongoDB Java Driver

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)

Результаты тестирования

Page 11: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Plain MongoDB driver

Большой объем потребляемой памяти

Сборщик мусора отрабатывает часто

Непредсказуемая производительность и

стабильность

Page 12: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что же делать?

Page 13: Экстремальная оптимизация производительности на примере MongoDB Java Driver

JUST OPTIMIZE IT.

Page 14: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что не так с Plain driver?

MongoDB

MongoDB

DriverConverter Service

byte[ ] DBObject Domain

Page 15: Экстремальная оптимизация производительности на примере MongoDB Java Driver

А что, если…

MongoDB

MongoDB

DriverConverter Service

byte[ ] DBObject

ByteArrayToDomainConverter

Domain

Page 16: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

MongoDB

DomainMagic

ConverterImproved

MongoDB Driver

byte[ ]

Service

Page 17: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Другие улучшения

Создание строк

Кэширование строк

«Ленивая» загрузка документов

«Ленивая» десериализация

Page 18: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Создание строк?

Page 19: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Да, создание строк

Текущая реализация в драйвере

String createString() {byte[] bytes = new byte[size];readBytes(bytes); // copy bytes from input streamreturn new String(bytes, UTF8_CHARSET);

}

Page 20: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Создание строк

Попытка #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);

}

Page 21: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Создание строк

Попытка #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;

}

Page 22: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Создание 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%)

Page 23: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Кэширование строк

0xffaa11 0xccff2e

String 1

String 2

... ... ... ...

ConcurrentHashMap

• Ключ – hash от строки

• Значение – CopyOnWriteArrayList<String>

Page 24: Экстремальная оптимизация производительности на примере MongoDB Java Driver

«Ленивая» подгрузка

Domain1

Item*

Page 25: Экстремальная оптимизация производительности на примере MongoDB Java Driver

«Ленивая» подгрузка

Domain Proxy LinkResolver Template

load()

readIds()

resolve()

findByIds(ids)

setItems(resolved)

getItems()

Page 26: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

{"_id": "Java","type": "language","father": {

"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true

},"features": /* массив байт */

}

Business rules

Page 27: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

{"_id": "Java","type": "language","father": {

"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true

},"features": /* массив байт */

}

Optional

No package

Reflections

Page 28: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

{"_id": "Java","type": "language","father": {

"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true

},"features": /* массив байт */

}

Lazy de-serialization

Page 29: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

{"_id": "Java","type": "language","father": {

"class": "JavaContributor","name": "James","surname": "Gosling","hasBeard": true

},"features": [

"object-oriented","static type-checking"

]}

De-serialized array

Page 30: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

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 млн запросов

Суммарное время выполнения запросов

Page 31: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Что получилось

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%)

Page 32: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Недостатки решения

Сложность поддержки

Сложность тестирования

• Соответствие BSON формату

• Коллизии кэширования

• Многопоточность

Page 33: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Java Driver 3.0+

Апрель 2015

API упрощающий интеграцию

Page 34: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Выводы

Page 35: Экстремальная оптимизация производительности на примере MongoDB Java Driver

Вопросы ?