📜 ⬆️ ⬇️

In Search of Performance, Part 2: Java Profiling for Linux

Argued that you can endlessly look at the fire, water and how others work, but there is something else! We are sure that you can talk endlessly with Sasha goldshtn Goldstein about performance. We already interviewed Sasha before JPoint 2017, but then the conversation was specifically about BPF, to which Sasha’s report was devoted.

This time we decided to dig deeper and find out the fundamental problems of monitoring performance and their solutions.



Where to start


- Last time we talked in some detail about BPF and briefly discussed the problems of monitoring Java performance under Linux. This time I would like to concentrate not on a specific tool, but on problems and the search for solutions. The first question, rather trivial, is how to understand that there are problems with performance? Should I think about this if the user does not complain?
')
Sasha Goldstein: If you start thinking about performance only at the moment when your users complain, they will not be with you for long. For many, performance engineering is trashshuting and crisis mode. The phones are ringing, the light is flashing, the system has fallen, the keyboard is on - the usual working life of a performance engineer. In reality, they spend most of their time planning, designing, monitoring and preventing crises.

To begin with, capacity planning is an estimate of the expected system load and resource utilization; designing scalability will help avoid bottlenecks and get significant increases in load; Instrumentation and monitoring are vital for understanding what is happening inside the system so as not to dig blindly; thanks to the installation of the automatic notification, you will know exactly about any problems that arise, as a rule, even before users start complaining; and of course there will be single crises that will have to be resolved in stressful conditions.

It is worth noting that the tula are constantly changing, but the process itself remains unchanged. I will give a couple of concrete examples: you can do capacity planning on a piece of paper on your knee; You can use APM solutions (like New Relic or Plumbr) for end-to-end instrumentation and monitoring, AB and JMeter for quick load testing, and so on. To learn more, you can read Brendan Gregg’s book, Systems Performance , an excellent source on the life cycle and performance methodology, and Google ’s Site Reliability Engineering covers the topic of Service Level Objectives and their monitoring.

- Suppose we understand that there is a problem: where to start? It often seems to me that many (especially not professional performance engineers) are immediately ready to uncover JMH, rewrite everything to unsafe and “hack compilers”. Then watch what happened. But in reality it is better not to start with this?

Sasha Goldstein: This is a fairly common practice, when writing code and performing basic profiler tests, problems arise with performance, which can be easily corrected by changing the code or “hacking compilers”. However, on the sale, based on my experience, this is done not so often. Many problems are inherent in only one environment, caused by changing workload patterns or associated with bottlenecks outside the code of your application, and only a small part can be mixed and improved at the source level by smart hacks.

Here are a couple of examples to illustrate:


I understand that it is often much easier to focus on things that you can manage, for example, application-level hacks. Purely psychologically, this is understandable, does not require in-depth knowledge of the system or environment, and for some reason is considered “cooler” in some cultures. But to address this in the first place is wrong.

- Probably you should first see how the application / service works in production. What tools do you recommend for this, and which ones - not so much?

Sasha Goldstein: Monitoring and profiling on the sale is a set of tools and a technician.

We start with high-level performance metrics, focusing on the use of resources (processor, memory, disk, network) and load characteristics (# of queries, errors, types of requests, # of database requests). There are standard tools for obtaining this data for each operation and execution time. For example, Linux usually uses tools like vmstat, iostat, sar, ifconfig, pidstat; for JVM, use JMX-based tools or jstat. These are metrics that can be continuously collected into a database, perhaps at a 5 or 30 second interval, so that you can analyze jumps and, if necessary, go back in time, to correlate previous deployment operations, releases, world events, or workload changes. . It is important that many focus on collecting only average values; although they are good, but, by definition, do not represent the complete distribution of what you measure. It is much better to collect percentiles, and if possible even histograms.

The next level is operational metrics that usually cannot be continuously collected or stored for a long time. These include: garbage collection log, network requests, database requests, class loads, and so on. Understanding this data after it has been stored somewhere is sometimes much more difficult than actually collecting it. This allows, however, to ask questions, such as “what requests worked while the database CPU load increased to 100%” or “what were the IOPS of the disks and the response time during the execution of this request”. Numbers alone, especially in the form of averages, will not allow you to conduct this kind of research.

And finally, the “hardcore” level: SSH in the server (or remote launch of the body) to collect more internal metrics that cannot be stored during normal operation of the service. These are tools that are commonly called “profilers.”

For Java production profiling, there are a lot of creepy things that not only give you a big overhead and delay, but they can also lie to you. Despite the fact that the ecosystem is already about 20 years old, there are only a few reliable profiling techniques with a low overhead for JVM applications. I can recommend Honest Profiler Richard Worburton, async-profiler Andrey Pangin and, of course, my pet - perf .

By the way, many bodies focus on CPU profiling, understanding which path of code execution causes high CPU utilization. This is great, but often this is not the problem; we need tools that can show the code execution paths responsible for memory allocation (async-profiler can now do this as well), missing page errors, missing cache, disk accesses, network requests, database requests and other events. In this area, I was attracted by the problem of finding the right performance for researching the working environment.

Java profiling for Linux



- I heard that under the Java / Linux stack there are a lot of problems with the accuracy of measurements. Surely you can somehow fight this. How do you do that?

Sasha Goldstein: Yes, it is sad. Here's what the current situation looks like: you have a fast conveyor line with a huge number of different parts that you need to test to find defects and understand the speed of the application / service. You cannot check every part absolutely, so your main strategy is to check 1 part per second and see if everything is in order, and you need to do this through the “tiny window” above this “tape”, because it is dangerous to come closer. It seems not bad, is not it? But then it turns out that when you try to look at it, it shows you not what is happening on the conveyor right now; it waits until the conveyor enters a magical “safe” mode, and only after that gives you everything to see. It also turns out that you will never see many parts, because the pipeline cannot enter its “safe” mode while they are nearby; and it turns out that the process of finding a defect in the window takes as much as 5 seconds, so it is impossible to do this every second.

Approximately in such condition now there is a set of profilers in the world of JVM. YourKit, jstack, JProfiler, VisualVM - they all have the same approach to CPU profiling: they use sampling of threads in a safe state. This means that they use the documented API to suspend all JVM threads and take their stack traces, which are then collected for a report with the hottest methods and stacks.

The problem with such a suspension of the process is as follows: threads do not stop immediately, runtime waits until they reach a safe state, which may be after many instructions and even methods. As a result, you get a biased picture of the application, and different profilers may still disagree with each other!

There is a study showing how bad it is when each profiler has his own point of view about the hottest method in the same workload (Mitkovich et al., "Evaluating the Accuracy of Java Profilers"). Moreover, if you have 1000 threads in a complex call stack of Spring, often you will not be able to collect stack traces. Perhaps no more than 10 times per second. As a result, your stack data will differ from the actual workload even more!

Solving such problems is not easy, but it is worth investing: it is impossible to profile some workloads on the prod using “traditional” tools like those listed above.

There are two separate approaches and one hybrid:


Any of these options are much better than safepoint-biased profilers in terms of accuracy, resource consumption and frequency of reports. They can be complicated, but I think accurate profiling of production with a low overhead is worth the effort.

Container Profiling


- Speaking of environments, it is now fashionable to pack everything in containers, are there any special features here? What should be remembered when working with containerized applications?

Sasha Goldstein: There are interesting problems with containers that many Tula completely ignore and as a result stop working altogether.

In brief, I remind you that Linux containers are built around two key technologies: control groups and namespaces. Monitoring groups allow you to increase the resource quota for a process or for a group of processes: CPU time caps, memory limit, IOPS storage, and so on. Namespaces allow container isolation: mount namespace provides each container with its own mount point (in fact, a separate file system), PID namespace — own process identifiers, network namespace gives each container its own network interface, and so on. Because of the namespace, it is difficult for multiple subsets to properly exchange data with containerized JVM applications (although some of these problems are not peculiar to the JVM).

Before discussing specific issues, it will be better if we briefly describe the different types of observability of the bodies for the JVM. If you have not heard of some of them, it's time to refresh your knowledge:


Here are some problems that arise when profiling and monitoring containers from a host, and how to solve them (in the future I will try to tell you more about this):


Here you can think: what if I just put the performance-tool in the container so that all these problems with isolation did not arise because of me? Although the idea is not bad, many of the bodies will not work with this configuration because of the seccomp. Docker, for example, rejects the perf_event_open system call, which is required for profiling with perf and async-profiler; he also rejects the ptrace system call, which is used by a large number of bodies to read the memory capacity of the JVM process. Changing the seccomp policy to accept these system calls puts the host at risk. Also, by placing the profiling tula in a container, you increase its attack surface.



We wanted to continue the conversation and discuss the effect of iron on profiling ...



Very soon, Sasha will come to St. Petersburg to conduct training on profiling JVM applications in production and speak at the Joker 2017 conference with a report on BPF , therefore, if you want to dive deeper into the topic - you have every chance to meet with Sasha personally.

Source: https://habr.com/ru/post/338928/


All Articles