Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java inside Docker pitfalls

Java inside Docker pitfalls

Docker Ottawa Meetup. August 30, 2017.

Aleksey Vorobyov

August 30, 2017
Tweet

More Decks by Aleksey Vorobyov

Other Decks in Technology

Transcript

  1. Why Java in Docker is a special case JVM and

    libraries decide how much memory and how many threads to use. This decision is based on a host hardware configuration. JVM and many libraries are designed to take a full advantage of all available resources. • JVM ergonomics • Libraries ergonomics These ergonomics work well in VM but not in a container
  2. Docker is a leaking abstraction • Docker uses Linux namespaces

    and cgroups • In a docker instance, an application can access a host hardware configuration • Java doesn't know about Docker and cgroups (before April 2017) • Java reads host configuration from /proc not from /sys/fs/cgroup • Demo (htop shows java process)
  3. Naive Scenario • Docker instance doesn’t have limits • Java

    without heap limit (no -Xmx option) • I hope nobody does this in production. But it works well in some circumstances. • According to current server JVM ergonomic, JVM will take ¼ of RAM for a heap
  4. How much memory do I need for my Java application?

    1. Test an application with a production scenario 2. Capture memory usage a. Easy way. docker stats b. Another way. jcmd <pid> VM.native_memory
  5. Memory in Java JVM allocates memory for • Heap •

    Metaspace • Code • GC • Threads • Native objects Start Java with -XX:NativeMemoryTracking=summary jcmd <pid> VM.native_memory
  6. Normal scenario • Docker instance have memory limits (2 GB)

    • Java with -Xmx (1GB) • Regular scenario
  7. Swap scenario • Docker instance have memory limits (600 MB)

    • Java with -Xmx (512 MB) • The most difficult to address scenario. From time to time a request latency is not stable
  8. Swap and Crash scenario • Docker instance have memory and

    swap limit (700 MB) • Java with -Xmx (512 MB) • Crashes sometimes, hard to reproduce
  9. CPU --cpuset-cpus as for now is the only way to

    tell JVM (8u131+) how many real cores you allow to use But this approach is very bad for resource utilization. It’s better • Use --cpus or --cpu-shares and don’t deploy CPU heavy services on the same host. • Configure JVM and an application according to provisioned resources
  10. Useful JVM configuration options -XX:+UseSerialGC Uses only 1 GC thread.

    -XX:MaxRAM=n Sets the maximum amount of memory used by the JVM -XX:+UseCGroupMemoryLimitForHeap This flag present in the more recent builds of JDK8 tells the JVM to use the information in /sys/fs/cgroup/memory/memory.limit_in_bytes to calculate memory defaults. -XX:ParallelGCThreads=n Set the number of parallel GC threads to n. This is helpful if you are trying to limit the cpu usage of your container.