2015-08-03 3 views
0

Я столкнулся с проблемой оптимизации. Я нахожусь в середине написания службы на основе Scala, которая использует Play Framework и ElasticSearch для анализа около 200 тыс. Документов в индексе.Scala: Проблемы с памятью

Теперь анализ может быть выполнен только на всех документах, и у меня есть класс модели поверх ES, который при передаче в виде списка другому методу рисует анализ класса модели.

Теперь, чтобы получить документы 200k сразу и проанализировать их, не может быть и речи, поскольку это выходит за рамки наших ограничений. Так что я сделал это - Изнутри рекурсивной функции:

def getOverallAnalytics(accumulatedAnalytics: Map[...], limit: Int, startFrom: Int) = { 
    ElasticModel.getAnalytics(limit, startFrom).flatMap({ 
     case (hasMore, newAnalytics) => { 
      val combinedAnalytics = combine(accumulatedAnalytics, newAnalytics) 
      if (hasMore) getOverallAnalytics(combinedAnalytics, limit, startFrom + limit) 
      else Future(newAccumulator) 
     } 
    })   
} 

И у вас есть;

object ElasticModel { 
    getAnalytics(limit, startFrom) = { 
     val recordObjects = queryElastic.flatMap(result => new ElasticModel(result)) 
     Future((haveMore(), getAnalysis(recordObjects))) // 
    } 
} 

Что-то на этот счет. Теперь на карте, содержащей аналитику, имеется очень маленький набор ключей. Учитывая это, нельзя ожидать, что a

java.lang.OutOfMemoryError: 
Unable to create new native thread 

Это работает на 16 ГБ оперативной памяти.

Мои предположения: recordObjects не продолжает потреблять память после вызова getAnalytics отделки.

Это похоже на единственную возможность, когда это происходит не так.

Что именно я делаю неправильно здесь?

+1

Я думаю, что у вас меньше традиционной ошибки OOM и больше проблем с ресурсами на вашем компьютере. Является ли ваш threadpool ограниченным, и если да, то какой максимальный размер? Кроме того, у вас есть настройка вашего компьютера, чтобы иметь большое количество доступных дескрипторов файлов, так как эта ошибка может возникнуть из-за этого. Правильно ли вы закрываете свои http-соединения с ES, чтобы они не просочились? – cmbaxter

ответ

1

Вы могли бы попытаться избежать этого захваченной ссылки на recordObjects:

object ElasticModel { 
    def getAnalytics(limit, startFrom): Future[(Boolean, 'Analytics')] = { 
     Future((
      haveMore(), 
      getAnalysis(queryElastic.flatMap(result => new ElasticModel(result))) 
     )) 
    } 
} 

Однако, вы не могли бы вытащить дамп памяти и проверьте, если recordObjects копить?

+0

'recordObjects' ограничен за звонок getAnalytics примерно до 500, что не является особенно большим числом. – Ashesh

+0

Один из «recordObjects» может не быть проблемой, но если (каким-то образом) захватить его в «val», который ссылается на «замыкание в будущем» * в рекурсивной функции, результат vm не мусор, собирающий «recordObjects», они могут куча до более чем vm кучи может справиться. Я не уверен, что это преступник. Моим другим подозреваемым будет рекурсия. Поэтому я бы предложил посмотреть дамп памяти и проверить, не набирается ли причина для * OOME * 'recordObjects'. Предлагаемый код в моем ответе - скорее диагностический тест;) –

Смежные вопросы