Neo4J огромное снижение производительности после добавления записей в пространственный слой
Итак, у меня есть около 70 миллионов пространственных записей, которые я хочу добавить к пространственному слою (я проверил с небольшим набором, и все идет гладко, запросы возвращают те же результаты, что и postgis, и операция слоя выглядит нормально) Но когда я пытаюсь Если добавить все пространственные записи в базу данных, производительность резко снижается до такой степени, что она становится очень медленной - около 5 миллионов записей (около 2 часов работы) и зависает на уровне ~7,7 миллиона (по прошествии 8 часов).
Так как пространственный индекс является Rtree, который использует структуру графа для построения себя, мне интересно, почему он ухудшается, когда число записей os увеличивается. Вставки Rtree - это O(n), если я не ошибаюсь, и поэтому я обеспокоен тем, что это может быть что-то среднее между перестановкой ограничивающих прямоугольников, узлами, которые не являются листьями деревьев, что приводит к замедлению процесса addToLayer с течением времени.
В настоящее время я добавляю узлы к слою вот так (много запрограммированных вещей, так как я пытаюсь выяснить проблему до шаблонов и стиля кода):
Transaction tx = database.beginTx();
try {
ResourceIterable<Node> layerNodes = GlobalGraphOperations.at(database).getAllNodesWithLabel(label);
long i = 0L;
for (Node node : layerNodes) {
Transaction tx2 = database.beginTx();
try {
layer.add(node);
i++;
if (i % commitInterval == 0) {
log("indexing (" + i + " nodes added) ... time in seconds: "
+ (1.0 * (System.currentTimeMillis() - startTime) / 1000));
}
tx2.success();
} finally {
tx2.close();
}
}
tx.success();
} finally {
tx.close();
}
Какие-нибудь мысли? Любые идеи о том, как производительность может быть увеличена?
PS: использование Java API Neo4j 2.1.2, Spatial 0.13 Core i5 3570k @4,5 ГГц, 32 ГБ оперативной памяти, выделенный жесткий диск 2 ТБ 7200 для базы данных (без ОС, файлов виртуальной памяти, только сами данные)
PS2.: Все геометрии являются LineStrings (если это важно:P), они представляют улицы, дороги и т.д..
PS3.: узлы уже находятся в базе данных, мне нужно только добавить их в слой, чтобы я мог выполнять пространственные запросы, атрибуты bbox и wkb в порядке, протестированы и работают для небольшого набора.
заранее спасибо
После повторного изменения и запуска кода (который занимает 5 часов для вставки точек в базу данных без использования слоя), произойдет попытка увеличить кучу jvm и параметры памяти внедренного графа.
indexing (4020000 nodes added) ... time in seconds: 8557.361
Exception in thread "main" org.neo4j.graphdb.TransactionFailureException: Unable to commit transaction
at org.neo4j.kernel.TopLevelTransaction.close(TopLevelTransaction.java:140)
at gis.CataImporter.addDataToLayer(CataImporter.java:263)
at Neo4JLoadData.addDataToLayer(Neo4JLoadData.java:138)
at Neo4JLoadData.main(Neo4JLoadData.java:86)
Caused by: javax.transaction.SystemException: Kernel has encountered some problem, please perform neccesary action (tx recovery/restart)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.neo4j.kernel.impl.transaction.KernelHealth.assertHealthy(KernelHealth.java:61)
at org.neo4j.kernel.impl.transaction.TxManager.assertTmOk(TxManager.java:339)
at org.neo4j.kernel.impl.transaction.TxManager.getTransaction(TxManager.java:725)
at org.neo4j.kernel.TopLevelTransaction.close(TopLevelTransaction.java:119)
... 3 more
Caused by: javax.transaction.xa.XAException
at org.neo4j.kernel.impl.transaction.TransactionImpl.doCommit(TransactionImpl.java:560)
at org.neo4j.kernel.impl.transaction.TxManager.commit(TxManager.java:448)
at org.neo4j.kernel.impl.transaction.TxManager.commit(TxManager.java:385)
at org.neo4j.kernel.impl.transaction.TransactionImpl.commit(TransactionImpl.java:123)
at org.neo4j.kernel.TopLevelTransaction.close(TopLevelTransaction.java:124)
at gis.CataImporter.addDataToLayer(CataImporter.java:256)
... 2 more
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.neo4j.kernel.impl.nioneo.store.DynamicRecord.clone(DynamicRecord.java:179)
at org.neo4j.kernel.impl.nioneo.store.PropertyBlock.clone(PropertyBlock.java:215)
at org.neo4j.kernel.impl.nioneo.store.PropertyRecord.clone(PropertyRecord.java:221)
at org.neo4j.kernel.impl.nioneo.xa.Loaders$2.clone(Loaders.java:118)
at org.neo4j.kernel.impl.nioneo.xa.Loaders$2.clone(Loaders.java:81)
at org.neo4j.kernel.impl.nioneo.xa.RecordChanges$RecordChange.ensureHasBeforeRecordImage(RecordChanges.java:217)
at org.neo4j.kernel.impl.nioneo.xa.RecordChanges$RecordChange.prepareForChange(RecordChanges.java:162)
at org.neo4j.kernel.impl.nioneo.xa.RecordChanges$RecordChange.forChangingData(RecordChanges.java:157)
at org.neo4j.kernel.impl.nioneo.xa.PropertyCreator.primitiveChangeProperty(PropertyCreator.java:64)
at org.neo4j.kernel.impl.nioneo.xa.NeoStoreTransactionContext.primitiveChangeProperty(NeoStoreTransactionContext.java:125)
at org.neo4j.kernel.impl.nioneo.xa.NeoStoreTransaction.nodeChangeProperty(NeoStoreTransaction.java:1244)
at org.neo4j.kernel.impl.persistence.PersistenceManager.nodeChangeProperty(PersistenceManager.java:119)
at org.neo4j.kernel.impl.api.KernelTransactionImplementation$1.visitNodePropertyChanges(KernelTransactionImplementation.java:344)
at org.neo4j.kernel.impl.api.state.TxStateImpl$6.visitPropertyChanges(TxStateImpl.java:238)
at org.neo4j.kernel.impl.api.state.PropertyContainerState.accept(PropertyContainerState.java:187)
at org.neo4j.kernel.impl.api.state.NodeState.accept(NodeState.java:148)
at org.neo4j.kernel.impl.api.state.TxStateImpl.accept(TxStateImpl.java:160)
at org.neo4j.kernel.impl.api.KernelTransactionImplementation.createTransactionCommands(KernelTransactionImplementation.java:332)
at org.neo4j.kernel.impl.api.KernelTransactionImplementation.prepare(KernelTransactionImplementation.java:123)
at org.neo4j.kernel.impl.transaction.xaframework.XaResourceManager.prepareKernelTx(XaResourceManager.java:900)
at org.neo4j.kernel.impl.transaction.xaframework.XaResourceManager.commit(XaResourceManager.java:510)
at org.neo4j.kernel.impl.transaction.xaframework.XaResourceHelpImpl.commit(XaResourceHelpImpl.java:64)
at org.neo4j.kernel.impl.transaction.TransactionImpl.doCommit(TransactionImpl.java:548)
... 7 more
28/07 -> Увеличение памяти не помогло, теперь я тестирую некоторые модификации в RTreeIndex и LayerRTreeIndex (что именно делает поле maxNodeReferences
делает?
// Constructor
public LayerRTreeIndex(GraphDatabaseService database, Layer layer) {
this(database, layer, 100);
}
public LayerRTreeIndex(GraphDatabaseService database, Layer layer, int maxNodeReferences) {
super(database, layer.getLayerNode(), layer.getGeometryEncoder(), maxNodeReferences);
this.layer = layer;
}
Он жестко запрограммирован на 100, и изменение его значения изменяется, когда (количество добавленных узлов) addToLayer
метод приводит к ошибке OutOfMemory. Если я не ошибаюсь, изменение значения этого поля увеличивает или уменьшает ширину и глубину дерева (на 100 шире, чем 50, а 50 - глубже, чем 100).
Подводя итоги прогресса на данный момент:
- Некорректное использование транзакций исправлено @Jim
- Объем памяти увеличился до 27 ГБ по совету @Peter
- Осталось 3 пространственных слоя, но теперь проблема становится реальной, потому что они большие.
- Сделал некоторое профилирование памяти при добавлении узлов в пространственный слой, и я нашел интересные точки.
Профилирование памяти и GC: http://postimg.org/gallery/biffn9zq/
Тип, который использует больше всего памяти в течение всего процесса, - это byte[], который, как я могу предположить, принадлежит только свойствам wkb геометрии (либо самой геометрии, либо bbox rtree). Имея это в виду, я также заметил (вы можете проверить новые изображения профилирования), что количество используемого пространства кучи никогда не опускается ниже отметки 18 ГБ.
В соответствии с этим вопросом , примитивы Java - это сборщик мусора. Примитивные типы в java являются необработанными данными, поэтому не подвергаются сборке мусора и освобождаются из стека метода только при возврате метода (так что, возможно, когда я создаю новый пространственный слой, все эти Массивы байтов wkb будут оставаться в памяти, пока я не закрою объект слоя вручную).
Имеет ли это смысл? Есть ли лучший способ управления ресурсами памяти, чтобы слой не сохранял старые данные загруженными?
3 ответа
Наконец, решили проблему с тремя исправлениями: установив cache_type= нет увеличивая размер кучи для движка низкоуровневых графов neostore и установив use_memory_mapped_buffers=true, чтобы управление памятью осуществлялось ОС, а не медленной JVM
таким образом, моя пользовательская пакетная вставка в пространственные слои прошла намного быстрее, без каких-либо ошибок / исключений
Спасибо за всю предоставленную помощь, я думаю, что мой ответ - это всего лишь комбинация всех советов, которые люди здесь предоставили, большое спасибо
Глядя на ошибку java.lang.OutOfMemoryError: превышен лимит накладных расходов GC, возможно, происходит чрезмерное создание объекта. Из ваших результатов профилирования это не похоже, не могли бы вы перепроверить?
Catacavaco,
Вы делаете каждое добавление как отдельную транзакцию. Чтобы использовать ваш commitInterval, вам нужно изменить код на что-то вроде этого.
Transaction tx = database.beginTx();
try {
ResourceIterable<Node> layerNodes = GlobalGraphOperations.at(database).getAllNodesWithLabel(label);
long i = 0L;
for (Node node : layerNodes) {
layer.add(node);
i++;
if (i % commitInterval == 0) {
tx.success();
tx.close();
log("indexing (" + i + " nodes added) ... time in seconds: "
+ (1.0 * (System.currentTimeMillis() - startTime) / 1000));
tx = database.beginTx();
}
}
tx.success();
} finally {
tx.close();
}
Посмотрите, поможет ли это.
Благодать и мир,
Джим