Một máy chủ Linux, giống như bất kỳ máy tính hiện đại nào, có thể chạy nhiều ứng dụng cùng lúc. Những ứng dụng này được gọi là các tiến trình (processes) và được quản lý riêng lẻ.
Mặc dù Linux sẽ tự động xử lý các tác vụ cấp thấp trong vòng đời của một tiến trình như khởi động, tắt, cấp phát bộ nhớ, v.v. bạn vẫn cần một cách để tương tác với hệ điều hành nhằm quản lý các tiến trình ở cấp độ cao hơn.
Trong hướng dẫn này, bạn sẽ tìm hiểu những khái niệm cơ bản về quản lý tiến trình trong Linux. Linux cung cấp một số công cụ tiêu chuẩn, được tích hợp sẵn để phục vụ cho mục đích này.
Bạn sẽ thực hành các khái niệm này trong môi trường Ubuntu 20.04, tuy nhiên hầu hết các bản phân phối Linux hiện đại khác đều hoạt động theo cách tương tự.
Bước 1: Cách xem các tiến trình đang chạy trong Linux
Bạn có thể xem tất cả các tiến trình đang chạy trên máy chủ của mình bằng cách sử dụng lệnh top
:
top
top
Output
top - 15:14:40 up 46 min, 1 user, load average: 0.00, 0.01, 0.05
Tasks: 56 total, 1 running, 55 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1019600k total, 316576k used, 703024k free, 7652k buffers
Swap: 0k total, 0k used, 0k free, 258976k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.07 ksoftirqd/0
6 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
7 root RT 0 0 0 0 S 0.0 0.0 0:00.03 watchdog/0
8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset
9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper
10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
Những dòng đầu tiên trong kết quả của lệnh top
hiển thị thống kê hệ thống, chẳng hạn như mức sử dụng CPU/bộ nhớ và tổng số tiến trình đang chạy.
Bạn có thể thấy rằng hiện có 1 tiến trình đang chạy, và 55 tiến trình đang ở trạng thái “ngủ” (sleeping), tức là chúng không sử dụng chu kỳ CPU tại thời điểm đó.
Phần còn lại của bảng hiển thị sẽ liệt kê các tiến trình đang hoạt động cùng với các thông số sử dụng tài nguyên tương ứng. Theo mặc định, top
sẽ tự động sắp xếp các tiến trình theo mức sử dụng CPU, do đó bạn có thể nhanh chóng xác định các tiến trình đang chiếm nhiều tài nguyên nhất.
Lệnh top
sẽ tiếp tục chạy trong terminal của bạn cho đến khi bạn tự dừng nó bằng tổ hợp phím Ctrl+C
. Tổ hợp này gửi một tín hiệu **kill**,
yêu cầu tiến trình đang chạy thoát ra một cách an toàn (nếu tiến trình có khả năng xử lý tín hiệu đó).
Một phiên bản nâng cấp của top
có tên là htop
cũng có sẵn trong hầu hết các kho phần mềm. Trên Ubuntu 20.04, bạn có thể cài đặt htop
bằng lệnh apt
như sau:
sudo apt install htop
Sau khi cài đặt xong, bạn có thể sử dụng lệnh htop
:
htop
Output
Mem[||||||||||| 49/995MB] Load average: 0.00 0.03 0.05
CPU[ 0.0%] Tasks: 21, 3 thr; 1 running
Swp[ 0/0MB] Uptime: 00:58:11
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
1259 root 20 0 25660 1880 1368 R 0.0 0.2 0:00.06 htop
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 /sbin/init
311 root 20 0 17224 636 440 S 0.0 0.1 0:00.07 upstart-udev-brid
314 root 20 0 21592 1280 760 S 0.0 0.1 0:00.06 /sbin/udevd --dae
389 messagebu 20 0 23808 688 444 S 0.0 0.1 0:00.01 dbus-daemon --sys
407 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.02 rsyslogd -c5
408 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5
409 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5
406 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.04 rsyslogd -c5
553 root 20 0 15180 400 204 S 0.0 0.0 0:00.01 upstart-socket-br
htop
cung cấp khả năng hiển thị tốt hơn đối với các luồng CPU đa nhân, hỗ trợ màu sắc tốt hơn trong các terminal hiện đại, và có nhiều tuỳ chọn sắp xếp hơn so với top
, cùng với một số tính năng khác. Không giống như top
, htop
không phải lúc nào cũng được cài sẵn theo mặc định, nhưng bạn có thể coi nó như một công cụ thay thế tương đương và dễ sử dụng hơn.
Bạn có thể thoát khỏi htop
bằng cách nhấn Ctrl+C
, tương tự như với top
.
Bước 2: Cách sử dụng ps để liệt kê các tiến trình
top
và htop
cung cấp giao diện dạng dashboard để xem các tiến trình đang chạy, tương tự như trình quản lý tác vụ đồ họa. Giao diện dashboard giúp bạn có cái nhìn tổng quan, nhưng thường không cho kết quả đầu ra có thể sử dụng trực tiếp trong các script hay thao tác tự động.
Để phục vụ mục đích đó, Linux cung cấp một công cụ dòng lệnh tiêu chuẩn khác có tên là ps
, cho phép truy vấn các tiến trình đang chạy.
Khi chạy ps
mà không truyền vào bất kỳ đối số nào, lệnh này chỉ hiển thị thông tin rất cơ bản:
ps
Output
PID TTY TIME CMD
1017 pts/0 00:00:00 bash
1262 pts/0 00:00:00 ps
Kết quả này hiển thị tất cả các tiến trình liên quan đến người dùng hiện tại và phiên làm việc trong terminal hiện tại. Điều này hoàn toàn hợp lý nếu bạn chỉ đang chạy shell bash
và lệnh ps
trong cùng một cửa sổ terminal vào thời điểm đó.
Để có cái nhìn đầy đủ hơn về tất cả các tiến trình đang chạy trên hệ thống, bạn có thể sử dụng lệnh sau:
ps aux
Output
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 24188 2120 ? Ss 14:28 0:00 /sbin/init
root 2 0.0 0.0 0 0 ? S 14:28 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 14:28 0:00 [ksoftirqd/0]
root 6 0.0 0.0 0 0 ? S 14:28 0:00 [migration/0]
root 7 0.0 0.0 0 0 ? S 14:28 0:00 [watchdog/0]
root 8 0.0 0.0 0 0 ? S< 14:28 0:00 [cpuset]
root 9 0.0 0.0 0 0 ? S< 14:28 0:00 [khelper]
…
Các tùy chọn trong lệnh ps aux
yêu cầu ps
hiển thị các tiến trình của tất cả người dùng, bất kể chúng có liên kết với terminal nào hay không, và trình bày kết quả ở dạng dễ đọc hơn cho con người.
Bằng cách kết hợp với toán tử pipes, bạn có thể tìm kiếm trong kết quả của ps aux
bằng lệnh grep
, để lọc ra một tiến trình cụ thể theo tên. Cách làm này rất hữu ích trong trường hợp bạn nghi ngờ tiến trình đó đã bị treo hoặc cần dừng nó vì một lý do nào đó.
ps aux | grep bash
Output
sammy 41664 0.7 0.0 34162880 2528 s000 S 1:35pm 0:00.04 -bash
sammy 41748 0.0 0.0 34122844 828 s000 S+ 1:35pm 0:00.00 grep bash
Kết quả trả về sẽ bao gồm cả tiến trình grep
mà bạn vừa chạy, và cả shell bash
hiện đang hoạt động. Ngoài ra, nó cũng hiển thị mức sử dụng CPU và bộ nhớ, thời gian tiến trình đã chạy, và quan trọng nhất trong phần kết quả được đánh dấu là mã định danh tiến trình, còn gọi là PID (Process ID).
Trong Linux và các hệ điều hành giống Unix, mỗi tiến trình đều được gán một PID duy nhất. Đây là cách mà hệ điều hành nhận diện và theo dõi các tiến trình đang chạy.
Một cách nhanh hơn để lấy PID của một tiến trình cụ thể là sử dụng lệnh pgrep
:
pgrep bash
Output
1017
Tiến trình đầu tiên được khởi chạy khi hệ thống boot, được gọi là init
, sẽ được gán PID là “1”.
pgrep init
Output
1
Tiến trình init
chịu trách nhiệm khởi chạy tất cả các tiến trình khác trên hệ thống. Các tiến trình được tạo ra sau sẽ được gán các PID lớn hơn.
Parent process là tiến trình chịu trách nhiệm tạo ra một tiến trình khác. Mỗi tiến trình đều có một PPID, tức là ID của tiến trình cha. Bạn có thể thấy cột PPID trong các công cụ quản lý tiến trình như top
, htop
, và ps
.
Mọi sự tương tác giữa người dùng và hệ điều hành liên quan đến tiến trình đều phải dịch qua lại giữa tên tiến trình và PID tại một thời điểm nào đó trong quá trình thao tác. Chính vì vậy, các công cụ quản lý tiến trình luôn hiển thị PID trong kết quả của chúng.
Bước 3: Cách gửi tín hiệu đến tiến trình trong Linux
Tất cả các tiến trình trong Linux đều có thể phản hồi tín hiệu. Tín hiệu là một cơ chế ở cấp độ hệ điều hành dùng để yêu cầu chương trình dừng hoặc thay đổi hành vi của nó.
Cách phổ biến nhất để gửi tín hiệu đến một tiến trình là sử dụng lệnh kill
. Như tên gọi gợi ý, chức năng mặc định của lệnh này là cố gắng kết thúc một tiến trình:
kill PID_of_target_process
Lệnh kill
sẽ gửi tín hiệu TERM đến tiến trình. Tín hiệu TERM yêu cầu tiến trình kết thúc một cách lịch sự. Điều này cho phép chương trình thực hiện các thao tác dọn dẹp cần thiết trước khi thoát ra một cách an toàn.
Tuy nhiên, nếu chương trình không phản hồi hoặc hoạt động không đúng và không thoát khi nhận được tín hiệu TERM, bạn có thể nâng cấp mức độ tín hiệu bằng cách gửi tín hiệu KILL
mạnh hơn:
kill -KILL PID_of_target_process
Đây là một tín hiệu đặc biệt, không được gửi trực tiếp đến chương trình.
Thay vào đó, tín hiệu được gửi đến kernel, và kernel sẽ ép tiến trình phải dừng ngay lập tức. Cách này thường được sử dụng khi chương trình bỏ qua các tín hiệu bình thường mà bạn đã gửi cho nó.
Mỗi tín hiệu đều có một số định danh tương ứng, bạn có thể sử dụng số thay vì tên khi gửi tín hiệu. Ví dụ:
15
tương đương vớiTERM
9
tương đương vớiKILL
Tín hiệu không chỉ được dùng để tắt chương trình, mà còn có thể kích hoạt các hành vi khác.
Ví dụ, nhiều tiến trình được thiết kế để chạy liên tục dưới nền (thường được gọi là “daemon”) sẽ tự động khởi động lại khi nhận được tín hiệu HUP
, hoặc tiến hiệu hang-up. Máy chủ web Apache là một ví dụ điển hình hoạt động theo cách này.
sudo kill -HUP pid_of_apache
Lệnh trên sẽ khiến Apache tải lại tập tin cấu hình và tiếp tục phục vụ nội dung như bình thường.
Lưu ý: Nhiều tiến trình chạy nền như vậy thường được quản lý thông qua các dịch vụ hệ thống, vốn cung cấp một lớp tương tác bổ sung để kiểm soát chúng. Vì vậy, việc khởi động lại toàn bộ dịch vụ thường là lựa chọn tốt hơn thay vì gửi trực tiếp tín hiệu HUP
đến một tiến trình đang chạy.
Nếu bạn xem xét các tập tin cấu hình của các dịch vụ khác nhau, bạn có thể thấy rằng các cơ chế restart
trong dịch vụ thực chất cũng đang gửi tín hiệu đến tiến trình, nhưng đồng thời còn ghi lại nhật ký và cung cấp thêm báo cáo chi tiết.
Bạn có thể liệt kê tất cả các tín hiệu mà lệnh kill
có thể gửi bằng cách sử dụng tùy chọn -l
:
kill -l
Output
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
Mặc dù cách truyền thống để gửi tín hiệu là thông qua PID, nhưng vẫn có những phương pháp khác cho phép bạn làm điều đó bằng cách sử dụng tên tiến trình.
Lệnh pkill
hoạt động gần như giống hệt với kill
, nhưng thay vì sử dụng PID, nó dựa vào tên tiến trình:
pkill -9 ping
Lệnh trên tương đương với:
kill -9 `pgrep ping`
Nếu bạn muốn gửi tín hiệu đến tất cả các phiên bản của một tiến trình cụ thể, bạn có thể sử dụng lệnh killall
:
killall firefox
Lệnh trên sẽ gửi tín hiệu TERM đến tất cả các phiên bản của firefox
đang chạy trên máy tính.
Bước 4: Cách điều chỉnh mức độ ưu tiên của tiến trình
Trong môi trường máy chủ, đôi khi bạn sẽ muốn điều chỉnh mức độ ưu tiên của các tiến trình.
Một số tiến trình có thể được xem là rất quan trọng đối với hệ thống, trong khi các tiến trình khác có thể được thực thi khi hệ thống còn dư tài nguyên.
Linux quản lý mức độ ưu tiên này thông qua một giá trị gọi là niceness.
- Tiến trình có độ ưu tiên cao sẽ được coi là ít “nice” hơn, vì chúng không chia sẻ tài nguyên một cách “lịch sự”.
- Ngược lại, tiến trình ưu tiên thấp được gọi là “nice” hơn, vì chúng sẵn sàng chỉ sử dụng tài nguyên khi hệ thống còn dư.
Khi bạn chạy lệnh top
ở phần đầu bài viết, có một cột được đánh dấu là “NI”, đó chính là giá trị nice của tiến trình.
top
[secondary_label Output]
Tasks: 56 total, 1 running, 55 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1019600k total, 324496k used, 695104k free, 8512k buffers
Swap: 0k total, 0k used, 0k free, 264812k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1635 root 20 0 17300 1200 920 R 0.3 0.1 0:00.01 top
1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 init
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.11 ksoftirqd/0
Giá trị nice có thể nằm trong khoảng từ -19 hoặc -20 (mức ưu tiên cao nhất) đến 19 hoặc 20 (mức ưu tiên thấp nhất).
Để chạy một chương trình với một giá trị nice cụ thể, bạn có thể sử dụng lệnh nice
như sau:
nice -n 15 command_to_execute
Cách sử dụng chỉ áp dụng khi bạn khởi chạy một chương trình mới.
Nếu bạn muốn thay đổi giá trị nice của một chương trình đang chạy, bạn sẽ cần dùng một công cụ có tên là renice
:
renice 0 PID_to_prioritize
Kết luận
Quản lý tiến trình trong Linux là một phần cốt lõi và có ích trong hầu hết mọi tình huống. Ngay cả khi bạn không trực tiếp quản trị hệ thống, thì việc xác định và xử lý các tiến trình bị treo hoặc hoạt động không đúng cũng là một kỹ năng rất hữu ích và thực tế.