#java #database #out-of-memory #orientdb #wal
#java #База данных #нехватка памяти #orientdb #wal
Вопрос:
После того, как один из моих сценариев импорта завершил импорт всех данных, я попытался перезапустить его, чтобы получить любые обновленные данные. Первое, что он делает, это захватывает самую последнюю обновленную запись:
db.select().from(newClass).order('updatedAt desc').limit(1).one()
Однако это вызвало следующую ошибку из моего скрипта узла:
Possibly unhandled OrientDB.RequestError: Java heap space
at Operation.parseError (/Users/gsquare567/node_modules/oriento/lib/transport/binary/protocol/operation.js:779:13)
at Operation.consume (/Users/gsquare567/node_modules/oriento/lib/transport/binary/protocol/operation.js:369:35)
at Connection.process (/Users/gsquare567/node_modules/oriento/lib/transport/binary/connection.js:324:17)
at Connection.handleSocketData (/Users/gsquare567/node_modules/oriento/lib/transport/binary/connection.js:250:17)
at Socket.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:748:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:410:10)
at emitReadable (_stream_readable.js:406:5)
at readableAddChunk (_stream_readable.js:168:9)
И я получил следующий вывод сервера:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid1694.hprof ...
Heap dump file created [2055557443 bytes in 37.799 secs]
Error on fetching record during browsing. The record has been skipped
Error on retrieving record #11:1023466 (cluster: user)
-> com.orientechnologies.orient.core.db.raw.ODatabaseRaw.read(ODatabaseRaw.java:252)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract.executeReadRecord(ODatabaseRecordAbstract.java:1017)
-> com.orientechnologies.orient.core.tx.OTransactionNoTx.loadRecord(OTransactionNoTx.java:65)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordTx.load(ODatabaseRecordTx.java:264)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordTx.load(ODatabaseRecordTx.java:40)
-> com.orientechnologies.orient.core.iterator.OIdentifiableIterator.readCurrentRecord(OIdentifiableIterator.java:285)
-> com.orientechnologies.orient.core.iterator.ORecordIteratorClusters.hasNext(ORecordIteratorClusters.java:139)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.fetchFromTarget(OCommandExecutorSQLSelect.java:913)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.executeSearch(OCommandExecutorSQLSelect.java:397)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.execute(OCommandExecutorSQLSelect.java:358)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate.execute(OCommandExecutorSQLDelegate.java:60)
-> com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:94)
-> com.orientechnologies.orient.core.storage.OStorageEmbedded.command(OStorageEmbedded.java:83)
-> com.orientechnologies.orient.core.command.OCommandRequestTextAbstract.execute(OCommandRequestTextAbstract.java:59)
-> com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.command(ONetworkProtocolBinary.java:1181)
-> com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.executeRequest(ONetworkProtocolBinary.java:340)
-> com.orientechnologies.orient.server.network.protocol.binary.OBinaryNetworkProtocolAbstract.execute(OBinaryNetworkProtocolAbstract.java:169)
-> com.orientechnologies.common.thread.OSoftThread.run(OSoftThread.java:45)
GC overhead limit exceeded
Мой другой скрипт импорта, запущенный одновременно, также был остановлен из-за следующего:
"error":{"name":"OrientDB.RequestError","message":"Java heap space","data":{},"previous":[],"id":1,"type":"java.lang.OutOfMemoryError","hasMore":0}
После повторной попытки запустить исходный скрипт на моем сервере я получил следующий вывод:
Exception in thread "OrientDB WAL Flush Task (pumpup)" Error on client connection
Java heap spacejava.lang.OutOfMemoryError: Java heap space
Вывод скрипта узла:
Possibly unhandled OrientDB.RequestError: Java heap space
at Operation.parseError (/Users/gsquare567/node_modules/oriento/lib/transport/binary/protocol/operation.js:779:13)
at Operation.consume (/Users/gsquare567/node_modules/oriento/lib/transport/binary/protocol/operation.js:369:35)
at Connection.process (/Users/gsquare567/node_modules/oriento/lib/transport/binary/connection.js:324:17)
at Connection.handleSocketData (/Users/gsquare567/node_modules/oriento/lib/transport/binary/connection.js:250:17)
at Socket.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:748:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:410:10)
at emitReadable (_stream_readable.js:406:5)
at readableAddChunk (_stream_readable.js:168:9)
Редактировать
После увеличения лимита памяти до 2 ГБ я смог вставить 5 миллионов записей (вместо предыдущих 2 миллионов записей), но все еще сталкиваюсь с этой ошибкой.
GC overhead limit exceeded
-> com.orientechnologies.orient.core.db.raw.ODatabaseRaw.read(ODatabaseRaw.java:252)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract.executeReadRecord(ODatabaseRecordAbstract.java:1017)
-> com.orientechnologies.orient.core.tx.OTransactionNoTx.loadRecord(OTransactionNoTx.java:65)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordTx.load(ODatabaseRecordTx.java:264)
-> com.orientechnologies.orient.core.db.record.ODatabaseRecordTx.load(ODatabaseRecordTx.java:40)
-> com.orientechnologies.orient.core.iterator.OIdentifiableIterator.readCurrentRecord(OIdentifiableIterator.java:285)
-> com.orientechnologies.orient.core.iterator.ORecordIteratorClusters.hasNext(ORecordIteratorClusters.java:139)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.fetchFromTarget(OCommandExecutorSQLSelect.java:913)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.executeSearch(OCommandExecutorSQLSelect.java:397)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLSelect.execute(OCommandExecutorSQLSelect.java:358)
-> com.orientechnologies.orient.core.sql.OCommandExecutorSQLDelegate.execute(OCommandExecutorSQLDelegate.java:60)
-> com.orientechnologies.orient.core.storage.OStorageEmbedded.executeCommand(OStorageEmbedded.java:94)
-> com.orientechnologies.orient.core.storage.OStorageEmbedded.command(OStorageEmbedded.java:83)
-> com.orientechnologies.orient.core.command.OCommandRequestTextAbstract.execute(OCommandRequestTextAbstract.java:59)
-> com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.command(ONetworkProtocolBinary.java:1181)
-> com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary.executeRequest(ONetworkProtocolBinary.java:340)
-> com.orientechnologies.orient.server.network.protocol.binary.OBinaryNetworkProtocolAbstract.execute(OBinaryNetworkProtocolAbstract.java:169)
-> com.orientechnologies.common.thread.OSoftThread.run(OSoftThread.java:45)
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Timer-0"
Комментарии:
1. Как правило, есть 2 варианта решения проблемы OOME: увеличить доступную память или уменьшить потребление
2. Сколько у вас памяти? Вы можете изменить это в bin/server.sh файл, добавив -Xmx2G в последнюю строку (где запускается Java), присваивает OrientDB 2G (максимум).
3. Я Лука, я сделал это, и на этот раз я добился 5 миллионов строк, но этого все еще недостаточно. Сейчас я не могу запускать какие-либо запросы к своим данным и, вероятно, мне придется воссоздавать свою базу данных, потому что это вызывает ошибку WAL. Как возможно иметь миллиарды записей?
Ответ №1:
Проблема здесь в том, что вы пытаетесь отсортировать все 5 миллионов записей.
Эта операция должна загрузить весь набор данных в память, чтобы отсортировать его (на самом деле у нас есть план по его оптимизации, чтобы избежать ООМ в этих случаях, но он еще не реализован).
Таким образом, даже если вы укажете ограничение 1, вы загрузите целую кучу записей, и запрос будет медленным и займет много памяти.
Чтобы оптимизировать этот запрос, создайте индекс над полем updatedAt.
Комментарии:
1. Вы бы порекомендовали,
NOTUNIQUE_HASH_INDEX
если ониDATETIME
не уникальны?2. Это сработало с
NOTUNIQUE
, а не сNOTUNIQUE_HASH_INDEX
нет. После просмотра документации выяснилось, что последняя не поддерживает запросы диапазона, так что это имеет смысл.