Какой наиболее эффективный способ чтения в массивном файле журнала и отправки в конечную точку API на Java?

#java #performance #file #memory #io

#java #Производительность #файл #память #io

Вопрос:

В настоящее время в моем приложении есть массивный файл журнала, который мне нужно отправить в конечную точку. Я периодически запускаю метод, который будет считывать весь файл в список, выполнять некоторое форматирование, чтобы конечная точка приняла его, а затем преобразовала строку с помощью StringBuilder, возвращает эту строку, а затем отправляет ее в мою конечную точку. О, я забыл упомянуть, я собираю данные порциями по X символов. Я вижу некоторые проблемы с памятью в своем приложении и пытаюсь справиться с этим.

Итак, вот как я разделяю данные на временный список

  if (logFile.exists()) {
            try (BufferedReader br = new BufferedReader(new FileReader(logFile.getPath()))) {
                String line;
                while ((line = br.readLine()) != null) {
                    if (isJSONValid(line)) {
                        temp.add(line);
                        tempCharCount  = line.length();
                    }
                    if (tempCharCount >= LOG_PARTITION_CHAR_COUNT) {
                        // Formatting for the backend
                        String tempString = postFormat(temp);

                        // Send
                        sendLogs(tempString);

                        // Refresh
                        temp = new ArrayList<>();
                        tempCharCount = 0;
                    }
                }

                // Send "dangling" data
                // Formatting for the backend
                String tempString = postFormat(temp);

                // Send
                sendLogs(tempString);
            } catch (FileNotFoundException e) {
                Timber.e(new Exception(e));
            } catch (IOException e) {
                Timber.e(new Exception(e));
            }
  

Итак, когда мы достигаем нашего предела раздела для количества символов, вы можете видеть, что мы запускаем

 String tempString = postFormat(temp);
  

Здесь мы удостоверяемся, что наши данные отформатированы в строку данных json, которую примет конечная точка.

 private String postFormat(ArrayList<String> list) {
            list.add(0, LOG_ARRAY_START);
            list.add(LOG_ARRAY_END);

            StringBuilder sb = new StringBuilder();
            for (int stringCount = 0; stringCount < list.size(); stringCount  ) {
                sb.append(list.get(stringCount));

                // Only add comma separators after initial element, but never add to final element and
                // its preceding element to match the expected backend input
                if (stringCount > 0 amp;amp; stringCount < list.size() - 2) {
                    sb.append(",");
                }
            }

            return sb.toString();
    }
  

Как вы можете себе представить, если у вас большой файл журнала, и эти запросы выполняются асинхронно, тогда мы будем использовать много памяти. После завершения работы нашего Stringbuilder мы возвращаем строку, которая в конечном итоге будет сжата в gzip и отправлена в конечную точку.

Я ищу способы уменьшить использование памяти этим. Я немного профилировал его сбоку и мог видеть, насколько он явно неэффективен, но не уверен, как я могу сделать это лучше. Приветствуются любые идеи.

Комментарии:

1. Я должен упомянуть, что я уменьшил лимит символов и начал чаще отправлять журналы, но я думаю, что это обходные пути в хороший день для плохого управления памятью. Я вижу, что мое приложение здесь неэффективно, но я ищу идеи по его улучшению.

2. Этот процесс звучит довольно неприятно — рассмотрите совершенно другой подход после прочтения этого .

Ответ №1:

У меня есть одно предложение для вас.

Форматированный вывод во временный файл — вы можете записать форматированный вывод во временный файл. После завершения преобразования вы можете читать временные файлы и отправлять в конечную точку. Если у вас нет проблем с последовательностью, вы можете использовать несколько потоков для добавления одного и того же файла. При таком подходе вы не штурмуете какие-либо данные в памяти во время преобразования, что сэкономит много памяти.

Комментарии:

1. Хороший совет, даст этому шанс 🙂