Skip to content

Large memory usage by gcloud-logging API. #1449

Closed

Description

@gregw

The logging API has a large memory foot print, with approximately 4KB of memory consumed for each log generated.

This was measured with the following program:

package com.google.cloud.runtimes.jetty9;

import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class StackDriverLogging {

  static void init() throws Exception {
    Logger log = Logger.getLogger(StackDriverLogging.class.getName());
    log.info("test info");
    log.fine("test fine");

    long last = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

    // Run 50 times to ensure everything is hot and any queues are max allocated
    for (int r=50;r-->0;) {
      long total = Runtime.getRuntime().totalMemory();
      long free = Runtime.getRuntime().freeMemory();
      long used = total - free;
      long delta = used - last;
      last = used;
      System.err.printf("total(%d)-free(%d)=used(%d) delta=%d%n", total, free, used, delta);

      for (int i = 1000; i-- > 0;)
        log.info("test info");
      
      if (r==10) {
        System.err.println("DRAINING...");
        // Wait a minute so all queued logs can drain out
        TimeUnit.MINUTES.sleep(1);
        System.gc();
        System.err.println("LAST 10...");
      }
      
      Thread.sleep(10);
    }

    System.err.println("DUMP!");
    Thread.sleep(1000000);
    
  }

  public static void main(String... args) throws Exception {
    init();
  }
}

Eclipse MAT was used to analyse a head dump taken immediately after 10K log entries were generated, then again once the program had returned to idle and network monitor indicated that all data had been flushed.

After 10L log messages, the heap was 51MB, which reduced to 13.4MB once the logs had been flushed (but no forced GC, so the difference may be larger). Thus at least 38MB appears to be consumed by logging 10K messages, which is 3.9KB per message. The attached reports( 10K Top Consumers.pdf & Idle Top Consumers.pdf ) indicate that 22.9 MB is used by io.grpc.netty.NettyClientTransport$2 and 12.1MB alone is consumed by io.netty.handler.codec.http2.StreamBufferingEncoder.

Ideally, the memory usage per log line could be greatly reduced. Eitherway, it would also be highly desirable to be able to put some limits on the memory consumed by the logging subsystem so that excessively verbose logs are either discarded, summarized, blocked or excepted.

Activity

  1. meltsufin commented on Dec 6, 2016

    @meltsufin
    Contributor

    Thanks @gregw for a detailed analysis.
    @garrettjonesgoogle Can you please take a look at this? 4KB per log message seems excessive.

  2. garrettjonesgoogle commented on Dec 7, 2016

    @garrettjonesgoogle
    Contributor

    Unfortunately, google-cloud-java gets its version of Netty indirectly through grpc, so there isn't a super-clean way to update that. Regardless, I would be very interested in seeing what your analysis shows if you update the Netty dependency on your end to 4.1.5 using the exclusions feature of Maven described in #1433 .

  3. gregw commented on Dec 8, 2016

    @gregw
    Author

    @garrettjonesgoogle I ran the same test with 4.1.5.Final Netty. It improve the base memory usage, but not the dynamic usage per request. After the 10K log messages total memory usage is now only 45.5MB, but when idle it now reduces to 8.7MB. So there is an approx 5MB saving, but the per message cost is about the same, dominated by 22.8 MB is used by io.grpc.netty.NettyClientTransport$2 and 11.4MB by io.netty.handler.codec.http2.StreamBufferingEncoder.

  4. gregw commented on Jan 19, 2017

    @gregw
    Author

    As per the discussion in grpc/grpc-java#2554, the issue appears to be caused (or at least aggravated) by the flush size of 1, which results in only an individual log entry being sent per RPC and many log entry lists being created as garbage. The simple flush level will be replaced by a better mechanism called "bundling", to provide timely yet aggregated log entries.

  5. self-assigned this
    on Jan 20, 2017
  6. pongad commented on Jan 23, 2017

    @pongad
    Contributor

    @garrettjonesgoogle I see two ways to resolve this

    • Add bundling options to logging and regenerate it with toolkit
    • Hand-write code to work with ThresholdBundlingForwarder and friends directly in this class

    Do you have a preference?

    Since this class allows configuring various options on per-handler basis, I think the 2nd option is probably easier to do. Due to the work we're doing on pubsub, the bundling surface feels somewhat unstable. So either way we decide to do it, we might have to rewrite pieces of it. I'll be happy to do the work though.

  7. garrettjonesgoogle commented on Jan 23, 2017

    @garrettjonesgoogle
    Contributor

    Bundling was already added to Logging and the GAPIC client was regenerated in d4d494d .

  8. pongad commented on Jan 24, 2017

    @pongad
    Contributor
  9. garrettjonesgoogle commented on Jan 24, 2017

    @garrettjonesgoogle
    Contributor

    Ahh you're right, I haven't submitted it there yet.

  10. pongad commented on Jan 24, 2017

    @pongad
    Contributor

    @gregw After discussing this with Garrett, I think this issue should have been resolved by d4d494d . Could you try again?

  11. meltsufin commented on Jan 25, 2017

    @meltsufin
    Contributor

    @gregw Can you please take a look?

  12. gregw commented on Jan 27, 2017

    @gregw
    Author

    @meltsufin @garrettjonesgoogle

    I have rerun the test I did above. The good news is that the network usage appears to be a lot better!

    Bad news is that the memory usage appears to be a lot worse:

    • After initialization and logging two simple messages, then heap size is only 5.3MB
    • After warm up logging of 50K messages the heap size grew to 88MB of which 83MB is consumed by com.google.api.gax.bundling
    • After logging 10K more messages, the heap grew to 108MB of which 103MB is consumed by com.google.api.gax.bundling

    I'll see if I can attach some detailed reports.

    Bad news is that the total image size is a bit bigger at 62MB, of which 54MB is consumed by com.google.api.gax.bundling. But the good news is that the size remains pretty much constant over the generation of 10K logs. Also good is that the network activity is now hardly noticeable, so the RPC usage appears to be much more efficient.

  13. gregw commented on Jan 27, 2017

    @gregw
    Author

    Here is a report. Tell me if you need more info.
    Export.pdf

  14. 31 remaining items

  15. michaelbausor commented on Mar 17, 2017

    @michaelbausor
    Contributor
  16. added a commit that references this issue on Aug 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions