"Something is on port 8080" and "it is up but does nothing"
Two incident questions come up every week: which process holds this port or this file? and this process looks healthy, so what is it actually waiting for? lsof answers the first, strace the second.
What you need to know already: 1.7 (file descriptors 0, 1, 2), 2.1 (systemctl status), 3.1 (PIDs), 3.3 (system calls).
Words first
- A file descriptor (fd) is the small number a process uses for each thing it has open - 0, 1, 2 are stdin, stdout, stderr (1.7), and every file it opens gets the next free number.
- A socket is an open network connection (or a listening point for new ones). On Linux it is also a file descriptor - "everything is a file".
- A port is the number (0-65535) that tells one machine's network services apart: SSH listens on 22, the web server on 80, the orders service on 8080. A process listening on a port is waiting for new connections to it.
lsof: list open files
lsof lists every file descriptor of every process - files, sockets, pipes:
sudo lsof -i :8080 -i :PORT = network sockets on that port (who listens, who is connected)
sudo lsof -p 1210 -p PID = everything this process has open
sudo lsof /var/log/app.log a path = who has this file open
sudo lsof -u appuser -u USER = everything this user's processes have open
sudo lsof +L1 files with a link count below 1: DELETED but still open (Chapter 4)
sudo lsof -t -i :8080 -t = just the PIDs, for feeding into kill
Its main columns: COMMAND (program name), PID, USER, FD (the fd number plus r/w/u for read/write/both), TYPE (REG file, DIR, IPv4 socket...), NAME (the path, or the address and port, with (LISTEN) for a listener).
Run it with sudo. Without root, lsof can only look at your processes, so lsof -i :8080 comes back empty and you conclude nothing is listening. It is the single most common way to be misled by this tool.
ss -tlnp is the faster answer for "what is listening": -t TCP, -l only listening sockets, -n show numbers not names, -p show the process. (It also needs sudo to show other users' processes.) lsof wins when you want which files, not just which sockets.
From a PID back to a unit
systemctl status 1210
Give systemctl status a PID instead of a unit name and it tells you which unit that process belongs to. Very useful when lsof or top hands you a number and you need to know what owns it - and if the answer is "no unit", you have found something started by hand that nobody supervises.
strace: what is it actually doing?
strace prints every system call a process makes - "open this file", "read from that socket", "wait for data" - one per line, as it happens:
sudo strace -p 1210 -p PID: attach to a running process (only its main thread)
sudo strace -f -p 1210 -f: also its other threads, and anything it starts
sudo strace -e trace=openat ls -e trace=: only these system calls (here: run ls and show its file opens)
sudo strace -c -p 1210 -c: count and time system calls instead of printing each one
sudo timeout 5 strace -p 1210 timeout 5: stop strace after five seconds
A thread (3.1) is one line of work inside a process. Busy servers keep a thread pool: a fixed set of threads, each handling one request at a time. On a multi-threaded program like the orders Java service, plain -p shows only the main thread, which just waits for the others: one futex(... FUTEX_WAIT ...) line (futex = "wait until another thread wakes me") and silence. Use -f; each line then starts with [pid NNNN], the thread it came from.
What you are looking for is the last, unfinished line:
read(214, <unfinished ...> waiting for data on fd 214
epoll_pwait(88, waiting for any of many sockets (normal for servers)
futex(0xffff8c0008b8, FUTEX_WAIT_BITSET_PRIVATE, ... waiting for another thread
read() that never returns means it is waiting for the other end of a socket to send something. If that socket is a call to another service (an upstream) with no timeout configured - no "give up after N seconds" - it will wait forever. So will the request behind it, and the thread. Eventually every thread in the pool is stuck, and the service is down while every process looks perfectly healthy.
A note on cost: strace pauses the process at every system call. On a busy production service it can slow it down tenfold. Attach briefly, prefer -c, and use timeout.
What you can now do
- Find which process listens on a port or holds a file (
sudo lsof,sudo ss -tlnp). - Turn a PID into the unit that owns it (
systemctl status <PID>). - See what a "healthy but stuck" process is blocked on (
sudo strace -f -p).