Giới Thiệu
Nếu có một tập hợp khái niệm và câu chuyện mà tôi luôn thích, đó chính là những liên quan đến vật lý, thần thoại, và lập trình. Trong khi làm việc và khám phá trên mạng, tôi đã tình cờ gặp phải DAEMONS. Cái tên này ngay lập tức thu hút sự chú ý, và theo tôi, cả khái niệm này cũng vậy. Hãy cùng tìm hiểu kĩ hơn về nó.
Khái Niệm Daemon
Vào năm 1871, James Clerk Maxwell, để lý giải định luật thứ hai của nhiệt động lực học, đã đề xuất một thí nghiệm tư tưởng nhằm bác bỏ nó. Ông tưởng tượng ra một sinh vật hữu hạn, có khả năng thao túng các phân tử trong một hệ thống kín, người có thể quan sát và quyết định mở hay đóng cửa để cho phép phân tử nhanh di chuyển qua—về cơ bản, một sinh vật mà ông cho là không thể tồn tại. Sau đó, Lord Kelvin đã gọi sinh vật này là một "daemon," không mang nghĩa tiêu cực (ông không đang nói về cái ba lô của trẻ em hay những điều tương tự), mà ám chỉ đến một sinh vật siêu nhiên làm việc âm thầm, tương tự như khái niệm daemon trong thần thoại Hy Lạp: những thực thể vô hình đối với con người, thực hiện những nhiệm vụ quan trọng.
Khái niệm "daemon" này thường được liên kết với lập trình, mặc dù mối liên hệ có thể không tồn tại, vì trong ngữ cảnh của máy tính, thuật ngữ này đã mang một ý nghĩa kỹ thuật riêng (nhưng giả sử có mối liên hệ thì sẽ làm mọi thứ thú vị hơn).
Mối Liên Hệ Giữa Daemon và Hệ Điều Hành
Vậy tại sao lại có mối liên hệ này?
Ý tưởng chung là tương tự, nhưng không còn là một thí nghiệm tư tưởng, mà là một thứ gì đó ảo. Trong các hệ điều hành, chúng ta phải giữ cho hệ thống phức tạp luôn được theo dõi và hành động, mà không cần sự can thiệp trực tiếp từ người dùng—đó chính là một daemon Hy Lạp thực thụ.
Và voilà, chúng ta có Daemon trong Linux. Chúng ở trong trạng thái ngủ (chúng không thực sự tắt, nhưng tôi sẽ giải thích điều này rõ hơn sau), được kích hoạt bởi một sự kiện, theo khoảng thời gian nhất định (thường là giây hoặc mili giây), hoặc xử lý liên tục các hàng đợi. Chúng tồn tại cho tất cả các loại và chức năng, nhưng điểm chung là: chúng hoạt động tự động, không phụ thuộc vào hành động của người dùng, duy trì hoạt động của hệ điều hành hoặc quản lý các chức năng có thể được sử dụng bởi các quy trình tương tác.
Một ví dụ quan trọng về hệ thống quản lý daemon, được áp dụng rộng rãi trong nhiều bản phân phối hiện đại, là systemd. Nó hoạt động như một bộ quản lý trung tâm: nó khởi động và điều khiển nhiều dịch vụ khác, phân tích các tệp .service để xác định thứ tự thực thi, vị trí của nhị phân quá trình, và cách quản lý đầu vào và đầu ra của nó.
Trong thực tế, các daemon là nền tảng của Linux, hoạt động ở nhiều cấp độ, từ các chức năng gần với phần cứng đến các ứng dụng người dùng. Hầu như mọi thứ chúng ta sử dụng hoặc thấy trong quy trình làm việc của mình đều có một daemon đứng sau. Và phần tốt nhất là, chúng ta có thể tạo ra các daemon riêng của mình để thực hiện các tác vụ không cần sự chú ý trực tiếp, chạy trong nền.
Các Loại Daemon
Ngày nay, trong nhiều hệ thống hiện đại, systemd là một bộ quản lý daemon được sử dụng rộng rãi, mặc dù các lựa chọn thay thế như OpenRC, runit, và s6 cũng có những ưu điểm và người ủng hộ riêng. Với systemd, chúng ta có thể, ví dụ, tạo một dịch vụ theo dõi nhiệt độ phần cứng và tự động tạo nhật ký, hoặc chạy các ứng dụng "one-shot" dưới sự kiểm soát của nó, quản lý việc thực thi, trạng thái và các lỗi có thể xảy ra.
Tất nhiên, còn nhiều daemon khác—như tôi đã đề cập, chúng hiện diện khắp nơi, ngay cả những nơi mà chúng ta không mong đợi. Hãy xem Apache HTTP Server (httpd), một máy chủ web phổ biến hoạt động như một daemon (tôi không biết điều này cho đến khi tìm hiểu). Cũng có crond, chịu trách nhiệm cho các tác vụ theo lịch trong cronjobs, và điều này có một điểm thú vị: nếu chúng ta nghĩ một cách trực tiếp, nó thực hiện các tác vụ mà chúng ta tạo ra và yêu cầu chạy vào những thời điểm nhất định hoặc theo khoảng thời gian đều đặn, và khi chúng không chạy, chúng đang ở trạng thái nhàn rỗi—rất tương tự với chính các daemon!
Vậy, liệu các scheduler của tôi cũng là daemon không? Ranh giới có thể rất mỏng, vì chúng có những đặc điểm chung. Sự khác biệt chính là nhiều daemon không thực sự "ngủ"; chúng thực sự đang ở những "trạng thái" khác nhau. (Tôi đã nói rằng tôi sẽ đề cập điều này lại)
Các Trạng Thái của Daemon
- Ngủ Có Thể Gián Đoạn (S): Trong trạng thái này, chúng đang thực hiện các tác vụ, theo dõi các sự kiện, giao diện hoặc cổng. Ví dụ,
sshdluôn chờ kết nối trên cổng 22, hoặccupsdđang chờ ai đó gửi tài liệu để in. - Ngủ Không Thể Gián Đoạn (D): Trong trạng thái này, nó đang chờ một thao tác I/O hoàn thành. Ví dụ, trong quá trình sao chép tệp lớn,
rsynccó thể xuất hiện ở trạng thái D.
Nói cách khác, một số daemon sử dụng polling, trong khi những cái khác hoạt động dựa trên sự kiện hệ thống hoặc hàng đợi tác vụ, v.v. Thực tế, cả daemon và scheduler đều có thể gặp phải độ trễ do điều kiện hệ thống, mặc dù daemon thường được thiết kế để tối đa hóa hiệu suất và độ nhạy.
Cách Tạo Daemon
Cũng thú vị khi biết rằng có nhiều cách để tạo một daemon—một số cổ điển và truyền thống, một số hiện đại và rất bền bỉ, hoặc nằm ở đâu đó giữa hai cái đó.
Một cách truyền thống là sử dụng một kịch bản trong init.d, là một phần của hệ thống khởi động SysV. Mô hình này đã có trước systemd và là tiêu chuẩn trong các bản phân phối Linux trong nhiều năm. SysV init sử dụng các kịch bản trong /etc/init.d/ để khởi động, dừng và quản lý các dịch vụ ở các runlevels khác nhau, cung cấp một hệ thống đơn giản hơn nhưng ít song song hơn so với systemd. Cách tiếp cận này vẫn được hỗ trợ trong nhiều bản phân phối vì lý do tương thích.
Chúng ta cũng có thể tạo các kịch bản trực tiếp với một vòng lặp hoặc bằng cách quan sát hàng đợi mà không có bất kỳ kiểm soát nào—có thể là cách dễ nhất, nhưng cũng là cách có nhiều vấn đề nhất: ứng dụng chạy mà không có quản lý, kiểm soát, v.v.
Nhưng không phải mọi thứ đều đen trắng. Trong cộng đồng Linux, có những người xem systemd là một sự thay đổi mô hình không thể chấp nhận. Triết lý Unix khuyên rằng "Làm một việc và làm tốt nó". Systemd làm nhiều việc; đối với một số người, điều này là thực tế và một thiết kế ứng dụng rất thuận lợi; đối với những người khác, đó là sự phức tạp và rủi ro gia tăng.
Thực Hành - Systemd
Chúng ta đã thấy lý thuyết, và mặc dù tôi thấy ý tưởng này rất thú vị, hãy chuyển sang một số thực hành bây giờ.
Tôi phải cảnh báo rằng tôi sẽ chỉ đề cập đến systemd trong phần thực hành này; tôi không có gì chống lại các cách khác để tạo ra một daemon, đó chỉ là vì tính thực tiễn và trực quan mà chúng ta sẽ có.
Phòng Thí Nghiệm:
Phòng Thí Nghiệm Xử Lý Sự Cố Với Systemd và Journal
Ý tưởng trong phòng thí nghiệm này là thực hành cách tạo một daemon sử dụng systemd và thực hiện xử lý sự cố bằng cách sử dụng journalctl và chính systemd.
Phần 1:
- Tạo một kịch bản đơn giản mà sẽ phục vụ như dịch vụ của chúng ta:
bash
sudo vi /usr/local/bin/my-service.sh
Và bên trong dịch vụ, hãy thêm một vòng lặp nhỏ được tạo bằng bash:
bash
#!/bin/bash
echo "Bắt đầu my-service"
logger "my-service started"
count=1
while true; do
echo "my-service đang chạy: vòng lặp $count"
logger "my-service đang chạy: kiểm tra #$count"
count=$((count+1))
sleep 15
done
Lưu ý: Bất kỳ nội dung nào cũng có thể được sử dụng, nhưng bạn có thể sử dụng đoạn mã này nếu bạn muốn một cái gì đó sẵn sàng.
- Bây giờ hãy cho phép dịch vụ này chạy:
bash
sudo chmod +x /usr/local/bin/my-service.sh
- Tạo một tệp cấu hình systemd cho dịch vụ:
bash
sudo vi /etc/systemd/system/my-service.service
Thêm nội dung sau:
bash
[Unit]
Description=Dịch vụ thử nghiệm của tôi
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/my-service.sh
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=my-service
[Install]
WantedBy=multi-user.target
- Khởi động mọi thứ. Để làm điều này, hãy làm theo các bước sau:
bash
sudo systemctl daemon-reload
sudo systemctl enable my-service.service
sudo systemctl start my-service.service
- Để kiểm tra xem dịch vụ có đang chạy đúng không, ta có thể thực hiện lệnh sau:
bash
sudo systemctl status my-service.service
Nếu bạn thấy nó đang chạy, xin chúc mừng! Chúng ta đã tạo thành công daemon đầu tiên bằng systemd.
- Bây giờ hãy kiểm tra nhật ký của dịch vụ:
bash
sudo journalctl -u my-service.service -f
Tham số -f (theo dõi) hiển thị các thông điệp trong thời gian thực.
Phần 2:
Tuyệt vời, daemon của chúng ta đang chạy, mọi thứ đều ổn. Nhưng đã đến lúc phá hủy mọi thứ...
Chúng ta sẽ phá hủy dịch vụ theo nhiều cách để thực hành xử lý sự cố.
Kịch bản 1: Làm hỏng kịch bản dịch vụ
Hãy truy cập lại mã kịch bản:
bash
sudo vi /usr/local/bin/my-service.sh
Chèn một số lỗi cú pháp:
Khởi động lại dịch vụ:
bash
sudo systemctl restart my-service.service
Kịch bản 2: Chỉnh sửa quyền của kịch bản
bash
sudo chmod -x /usr/local/bin/my-service.sh
sudo systemctl restart my-service.service
Phần 3:
Bây giờ hãy sử dụng các công cụ systemd và journal để chẩn đoán các vấn đề.
- Kiểm tra trạng thái dịch vụ
bash
sudo systemctl status my-service.service
Quan sát các mã lỗi, thông điệp và trạng thái.
bash
# Xem tất cả nhật ký dịch vụ
sudo journalctl -u my-service.service
# Xem chỉ nhật ký lỗi
sudo journalctl -u my-service.service -p err
# Xem nhật ký từ một khoảng thời gian cụ thể
sudo journalctl -u my-service.service --since "10 minutes ago"
# Xem nhật ký từ khởi động hiện tại
sudo journalctl -u my-service.service -b
# Kiểm tra các phụ thuộc của dịch vụ
sudo systemctl list-dependencies my-service.service
# Kiểm tra cấu hình dịch vụ
sudo systemctl cat my-service.service
# Kiểm tra tiến trình
ps aux | grep my-service
Tất cả các lệnh này sẽ giúp bạn trong việc xử lý sự cố. Tôi khuyên bạn nên chạy chúng và xem mỗi lệnh làm gì, cố gắng hiểu mọi chi tiết. Bây giờ, hãy thử tìm các lỗi trong nhật ký, phá nó một lần nữa (hoặc nhiều hơn), sửa chữa chúng và khởi động lại daemon. Cuối cùng, đó chính là ý tưởng...
Thực hành để nếu một ngày bạn phải tạo và làm việc trên nó, mọi thứ sẽ suôn sẻ.