Một lần khởi động OpenVPN thất bại thường đến dưới dạng phàn nàn về tài nguyên kèm theo một đề xuất thiện chí nâng một giới hạn nào đó, và đề xuất ấy chỉ hiệu quả trong khoảng một nửa số trường hợp. Đằng sau những thất bại đó là hai bộ đếm không liên quan. Một là giới hạn của nhân về số tác vụ thuộc một ID người dùng thực, và nó được kế thừa khi tiến trình được thực thi. Còn lại là ngân sách cgroup mà trình quản lý dịch vụ áp lên một đơn vị và mọi thứ nó phân nhánh. Đọc giá trị hiệu lực của từng cái, cho đơn vị thực sự chạy, tốn ít hơn một phỏng đoán.

Hai bộ đếm, hai câu hỏi

LimitNPROC là RLIMIT_NPROC dưới một tên systemd, và đơn vị hạch toán của nó là ID người dùng thực. Mọi tiến trình mà người dùng đó sở hữu đều được tính vào cùng một tổng, kể cả công việc do các đơn vị khác, một phiên đăng nhập hay một tác vụ lập lịch khởi động. Vì vậy giới hạn này không phải mức trần cho từng dịch vụ ngay cả khi nó được đặt bên trong một đơn vị dịch vụ, và một dịch vụ phân nhánh trình trợ giúp cho mỗi khách hàng sẽ cạnh tranh với mọi thứ khác chạy dưới tài khoản đó. Một tác vụ cron bận rộn dưới cùng người dùng có thể đẩy một đơn vị VPN vượt qua ranh giới mà bản thân nó chưa bao giờ vượt qua.

TasksMax có chủ sở hữu khác: bộ điều khiển pids trên cgroup của đơn vị, thứ đếm tác vụ chứ không phải tiến trình. Luồng cũng là tác vụ, nên một tiến trình trông như đơn luồng nhưng có nhóm công nhân có thể tiêu thụ một ngân sách mà thoạt nhìn lớn hơn nhiều so với số tiến trình của nó. EffectiveTasksMax báo cáo điều mà hệ thống phân cấp cgroup thực sự cho phép sau khi các lát cha đã nói lời của chúng.

Vì sao ngoại lệ root thay đổi câu trả lời

Nhân không áp dụng RLIMIT_NPROC cho một tiến trình mang CAP_SYS_RESOURCE hoặc CAP_SYS_ADMIN, đó là lý do một đơn vị chạy dưới dạng root mà không từ bỏ đặc quyền trên thực tế không bị giới hạn bởi thiết lập đó. Chính ngoại lệ duy nhất này giải thích những lời khuyên trái ngược mà người ta trao đổi: nâng LimitNPROC sửa một triển khai đã từ bỏ đặc quyền và không làm gì cả cho một triển khai vẫn giữ đặc quyền. Hãy kiểm tra User= và việc tiến trình nền có đổi danh tính sau khi khởi động hay không trước khi quy công hay quy tội cho thiết lập đó. Một đơn vị có đặc quyền mà sau đó chuyển sang tài khoản không đặc quyền sẽ lại rơi xuống dưới giới hạn ngay tại thời điểm chuyển, điều này khiến dòng thời gian của sự cố cũng đáng để đọc.

Giai đoạn thất bại thu hẹp điều đó hơn nữa. Một lần từ chối trong lúc chuẩn bị thực thi, một lỗi phân nhánh do chính tiến trình nền báo cáo và một lần tạo tác vụ bị từ chối bên trong cgroup tạo ra các dòng journal khác nhau, và chỉ một trong số đó được trả lời bằng một ngân sách lớn hơn.

Đọc các giá trị hiệu lực, không đọc giá trị của shell

ulimit -u của một shell tương tác mô tả chính shell đó. Nó không mô tả điều trình quản lý dịch vụ đã truyền cho tiến trình nền, và không nói gì về hạch toán cgroup. Hãy hỏi đơn vị thay vào đó, dùng tên phiên bản tồn tại trên máy chủ chứ không phải một ví dụ trong hướng dẫn.

systemctl show [email protected] -p User -p LimitNPROC -p TasksCurrent -p TasksMax -p EffectiveTasksMax
cat /proc/$(systemctl show -p MainPID --value [email protected])/limits | grep -i processes

Bên trong một vùng chứa, câu trả lời cần thêm hai lần đọc, vì một giá trị bên trong của infinity chỉ mô tả góc nhìn của khách. Hãy hỏi chủ sở hữu máy chủ về mức trần pids của chính vùng chứa, và xác nhận liệu trình quản lý dịch vụ bên trong có thể ủy quyền bộ điều khiển đó hay không. Một đơn vị lồng nhau không thể giữ một ngân sách mà cgroup cha của nó chưa bao giờ cấp.

Đo quy mô của bản sửa và chứng minh nó dưới tải

Hãy chọn con số từ khối lượng công việc chứ không từ văn bản lỗi. Đếm các tiến trình mà tiến trình nền khởi động cho mỗi khách hàng được kết nối hoặc mỗi lần gọi trình trợ giúp, nhân với mức đồng thời mà triển khai được kỳ vọng phải chịu, thêm biên cho các phiên quản trị, rồi so sánh con số đó với hai giá trị hiệu lực. Một ghi đè drop-in cục bộ giữ thay đổi có thể xem xét lại và sống sót qua các lần nâng cấp gói, trong khi sửa một tệp đơn vị được phát hành sẽ giấu thay đổi cho đến khi bản cập nhật tiếp theo thay thế nó. Viết phép tính bên cạnh phần ghi đè, vì người tiếp theo nâng hoặc hạ nó cần các giả định chứ không phải con số cuối cùng.

Các thay đổi ngân sách được áp dụng khi thực thi, nên chỉ tải lại thôi thì không thay đổi kích thước của các tiến trình đang chạy. Hãy khởi động lại đơn vị theo vòng đời bình thường của nó, chấp nhận gián đoạn phiên, rồi đọc lại các bộ đếm trên phiên bản mới.

sudo systemctl daemon-reload
sudo systemctl restart [email protected]
systemctl show [email protected] -p TasksCurrent -p EffectiveTasksMax
sudo journalctl -u [email protected] -b --no-pager | tail -n 20

Điều chứng minh bản sửa là một đơn vị đã khởi động lại có số tác vụ nằm dưới cả hai mức trần trong khi vẫn mang tải dự kiến, cùng với một journal không còn báo cáo việc cạn tác vụ hay phân nhánh ở cùng giai đoạn. Hãy giữ các con số trước và sau cùng với thay đổi để cuộc điều tra tiếp theo bắt đầu từ một phép đo chứ không phải từ lời khuyên cũ. Nếu con số vẫn chạm mức trần, thì phép tính đã sai chứ không phải giới hạn tình cờ quá nhỏ, và sự khác biệt đó đáng để biết trước lần khởi động lại tiếp theo.

Bài viết liên quan