读取大量日志文件并 post 到 Java 中的 API 端点的最有效方法是什么?

What's the most efficient way to read in a massive log file, and post to an API endpoint in Java?

目前我的应用程序中有大量日志文件,我需要 post 到端点。我定期 运行 一个将整个文件读入列表的方法,执行一些格式化以便端点接受它,然后使用 StringBuilder 转换字符串,return 这个字符串,然后 post 它到我的端点。哦,我忘了说,我将数据分成 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));
            }

所以当我们达到字符数的分区限制时,您可以看到我们正在 运行ning

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 && stringCount < list.size() - 2) {
                    sb.append(",");
                }
            }

            return sb.toString();
    }

正如您想象的那样,如果您有一个很大的日志文件,并且这些请求是异步发出的,那么我们将使用大量内存。一旦我们的 Stringbuilder 完成,我们 return 作为一个字符串,最终将被 gzip 压缩并 posted 到一个端点。

我正在寻找减少内存使用的方法。我对它进行了一些侧面的分析,可以看出它的效率有多低,但我不确定如何才能做得更好。任何想法表示赞赏。

我有一个建议给你。

临时文件中的格式化输出 - 您可以在临时文件中写入格式化输出。一旦转换完成,您就可以读取临时文件并发送到端点。如果你不关心顺序,那么你可以使用多线程来追加同一个文件。 使用这种方法,您不会在转换时在内存中存储任何数据,这将节省大量内存。