Original: Coding diary (wechat official ID: Codelogs), welcome to share, reprint please reserve the source.
background
The reason was that we wanted to develop a small script that would use JStack to save Java’s thread stack for later analysis when CPU usage was too high.
Obtaining CPU usage
To get the CPU usage, it is easy to use vmstat. The 15th column id is the CPU free rate, and you can subtract 100 from the CPU usage.
So, I used the following command to get the CPU usage and found it, as follows:
vmstat 1|awk '{print 100-$15}'
Copy the code
Problems arise
However, when I add another script to read the CPU usage, I find that when the CPU exceeds 90%, the script does not output for half a day, as follows:
# Let a core be fully loaded
stress --cpu 1
# Automatic JStack fetching thread stack when CPU is high
vmstat 1|awk '{print 100-$15}'|while read cpu; do [[ $cpu -gt 90 ]] && jstack `pgrep java`; done
Copy the code
I thought it was my script, so I changed the script to CAT, as follows:
vmstat 1|awk '{print 100-$15}'|cat
Copy the code
Found that there is no output, this is more confused, as if the last pipe was blocked!
Problem solving
After a search on the Internet, finally found the answer, the original is the pot cache. Awk does not cache data immediately when the output target is a terminal, but when the output target is a file or pipe, AWK caches data until it reaches a certain size.
Also, you can use the fflush function in AWk to output it immediately, as follows:
vmstat 1|awk '{print 100-$15; fflush()}'|cat
Copy the code
Similarly, grep, sed, python and other commands all have this problem, which can be avoided as follows:
grep --line-buffered
sed -u
python -u
Copy the code
In addition, Linux provides a stdbuf command to avoid caching data during command output.
stdbuf -o L grep
Copy the code
Finally, my little script was modified as follows, and I was able to achieve my goal.
vmstat 1|awk '{print 100-$15; fflush()}'|while read cpu; do [[ $cpu -gt 90 ]] && (jstack `pgrep java` > "$(date +'%FT%T')_stack.log"); done
Copy the code
Content of the past
Awk (BRE,ERE,PCRE) awk (BRE,ERE,PCRE