Thiết lập Trình diệt hết bộ nhớ trong Linux cho PostgreSQL

Thiết lập Trình diệt hết bộ nhớ trong Linux cho PostgreSQL

Khi một máy chủ cơ sở dữ liệu thoát đột ngột trong Linux, bạn cần tìm ra nguyên nhân. Có thể có nhiều lý do. Ví dụ, SIGSEGV — lỗi do lỗi ở máy chủ phụ trợ. Nhưng điều này rất hiếm. Thông thường, bạn chỉ cần hết dung lượng ổ đĩa hoặc bộ nhớ. Nếu bạn hết dung lượng ổ đĩa, chỉ có một lối thoát - giải phóng dung lượng và khởi động lại cơ sở dữ liệu.

Kẻ giết người hết bộ nhớ

Khi một máy chủ hoặc tiến trình hết bộ nhớ, Linux đưa ra 2 giải pháp: đánh sập toàn bộ hệ thống hoặc chấm dứt tiến trình (ứng dụng) đang ngốn bộ nhớ. Tất nhiên, tốt hơn hết là bạn nên chấm dứt quá trình này và cứu hệ điều hành khỏi gặp sự cố. Tóm lại, Out-Of-Memory Killer là một quá trình giết chết một ứng dụng để cứu kernel khỏi bị lỗi. Nó hy sinh ứng dụng để giữ cho hệ điều hành hoạt động. Trước tiên hãy thảo luận về cách OOM hoạt động và cách kiểm soát nó, sau đó xem cách OOM Killer quyết định chấm dứt ứng dụng nào.

Một trong những nhiệm vụ chính của Linux là phân bổ bộ nhớ cho các tiến trình khi chúng yêu cầu. Thông thường, một tiến trình hoặc ứng dụng yêu cầu bộ nhớ từ HĐH nhưng không sử dụng hết bộ nhớ đó. Nếu HĐH cung cấp bộ nhớ cho tất cả những người yêu cầu nhưng không có kế hoạch sử dụng nó thì rất nhanh bộ nhớ sẽ hết và hệ thống sẽ bị lỗi. Để tránh điều này, hệ điều hành dự trữ bộ nhớ cho tiến trình nhưng không thực sự giải phóng nó. Bộ nhớ chỉ được cấp phát khi một tiến trình thực sự sử dụng nó. Điều xảy ra là HĐH không có bộ nhớ trống nhưng nó gán bộ nhớ cho một tiến trình và khi một tiến trình cần đến, HĐH sẽ phân bổ bộ nhớ đó nếu có thể. Nhược điểm là đôi khi hệ điều hành dự trữ bộ nhớ nhưng không đúng lúc không còn bộ nhớ trống và hệ thống bị treo. OOM đóng một vai trò quan trọng trong kịch bản này và chấm dứt các tiến trình để ngăn kernel khỏi hoảng loạn. Khi quá trình PostgreSQL buộc phải chấm dứt, một thông báo sẽ xuất hiện trong nhật ký:

Out of Memory: Killed process 12345 (postgres).

Nếu hệ thống sắp hết bộ nhớ và không thể giải phóng được thì hàm này được gọi out_of_memory. Ở giai đoạn này, cô ấy chỉ còn một việc phải làm - hoàn thành một hoặc nhiều quy trình. OOM-killer nên chấm dứt quá trình ngay lập tức hay có thể đợi? Rõ ràng, khi out_of_memory được gọi, đó là do đang chờ thao tác I/O hoặc phân trang vào đĩa. Do đó, kẻ giết người OOM trước tiên phải thực hiện kiểm tra và dựa trên chúng, quyết định rằng quá trình này cần phải được chấm dứt. Nếu tất cả các bước kiểm tra bên dưới đều tích cực, OOM sẽ chấm dứt quá trình.

Lựa chọn quy trình

Khi hết bộ nhớ, hàm này được gọi out_of_memory(). Nó có chức năng select_bad_process(), nhận được đánh giá từ hàm badness(). Quá trình “tồi tệ nhất” sẽ được nhắm mục tiêu. Chức năng badness() chọn một quy trình theo các quy tắc nhất định.

  1. Hạt nhân cần một số bộ nhớ tối thiểu cho chính nó.
  2. Bạn cần giải phóng rất nhiều bộ nhớ.
  3. Không cần phải chấm dứt các tiến trình đang sử dụng ít bộ nhớ.
  4. Các quy trình tối thiểu cần phải được hoàn thành.
  5. Các thuật toán phức tạp giúp tăng cơ hội hoàn thành cho những quy trình mà bản thân người dùng muốn hoàn thành.

Sau khi hoàn thành tất cả các bước kiểm tra này, OOM sẽ kiểm tra điểm (oom_score). OOM chỉ định oom_score mỗi quá trình, sau đó nhân giá trị này với dung lượng bộ nhớ. Các quy trình có giá trị lớn hơn có nhiều khả năng trở thành nạn nhân của OOM Killer hơn. Các quy trình liên quan đến người dùng root có điểm thấp hơn và ít có khả năng bị buộc chấm dứt hơn.

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

ID tiến trình Postgres là 3813, vì vậy trong một shell khác có thể lấy điểm bằng tham số kernel này oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

Nếu bạn không muốn OOM-Killer giết tiến trình này, có một tùy chọn kernel khác: oom_score_adj. Thêm giá trị âm lớn để giảm cơ hội hoàn thành quy trình mà bạn đánh giá cao.

sudo echo -100 > /proc/3813/oom_score_adj

Để đặt một giá trị oom_score_adj, đặt OOMScoreAdjust trong khối dịch vụ:

[Service]
OOMScoreAdjust=-1000

Hoặc dùng oomprotect trong một nhóm rcctl.

rcctl set <i>servicename</i> oomprotect -1000

Buộc chấm dứt một quá trình

Khi một hoặc nhiều quy trình đã được chọn, OOM-Killer gọi hàm oom_kill_task(). Hàm này gửi tín hiệu kết thúc tới tiến trình. Trong trường hợp thiếu bộ nhớ oom_kill() Gọi hàm này để gửi tín hiệu SIGKILL đến tiến trình. Một thông báo được ghi vào nhật ký kernel.

Out of Memory: Killed process [pid] [name].

Cách điều khiển OOM-Killer

Trên Linux, bạn có thể bật hoặc tắt OOM-Killer (mặc dù cách sau không được khuyến khích). Để bật hoặc tắt, hãy sử dụng tham số vm.oom-kill. Để bật OOM-Killer khi chạy, hãy chạy lệnh sysctl.

sudo -s sysctl -w vm.oom-kill = 1

Để tắt OOM-Killer, hãy chỉ định giá trị 0 trong cùng lệnh:

sudo -s sysctl -w vm.oom-kill = 0

Kết quả của lệnh này sẽ không được lưu mãi mãi mà chỉ cho đến lần khởi động lại đầu tiên. Nếu bạn cần kiên trì hơn, hãy thêm dòng này vào tệp /etc/sysctl.conf:

echo vm.oom-kill = 1 >>/etc/sysctl.conf

Một cách khác để bật và tắt là viết một biến panic_on_oom. Giá trị luôn có thể được kiểm tra /proc.

$ cat /proc/sys/vm/panic_on_oom
0

Nếu bạn đặt giá trị thành 0 thì khi hết bộ nhớ, kernel sẽ không bị hoảng loạn.

$ echo 0 > /proc/sys/vm/panic_on_oom

Nếu bạn đặt giá trị thành 1 thì khi hết bộ nhớ, hiện tượng hoảng loạn hạt nhân sẽ xảy ra.

echo 1 > /proc/sys/vm/panic_on_oom

OOM-Killer không chỉ có thể bật và tắt. Chúng tôi đã nói rằng Linux có thể dự trữ nhiều bộ nhớ hơn cho các tiến trình so với mức có sẵn mà không thực sự phân bổ nó và hành vi này được kiểm soát bởi tham số nhân Linux. Biến chịu trách nhiệm cho việc này vm.overcommit_memory.

Bạn có thể chỉ định các giá trị sau cho nó:

0: Bản thân kernel quyết định có dự trữ quá nhiều bộ nhớ hay không. Đây là mặc định trên hầu hết các phiên bản Linux.
1: Hạt nhân sẽ luôn dự trữ thêm bộ nhớ. Điều này rất rủi ro vì bộ nhớ có thể hết vì rất có thể một ngày nào đó các quá trình sẽ yêu cầu nó.
2: kernel sẽ không dự trữ nhiều bộ nhớ hơn mức được chỉ định trong tham số overcommit_ratio.

Với tham số này, bạn chỉ định phần trăm bộ nhớ được phép dự trữ quá mức. Nếu không còn chỗ cho nó, bộ nhớ sẽ không được phân bổ và việc đặt trước sẽ bị từ chối. Đây là tùy chọn an toàn nhất được đề xuất cho PostgreSQL. OOM-Killer bị ảnh hưởng bởi một yếu tố khác - khả năng hoán đổi, được điều khiển bởi biến cat /proc/sys/vm/swappiness. Các giá trị này cho kernel biết cách xử lý phân trang. Giá trị càng cao thì khả năng OOM chấm dứt quá trình càng ít, nhưng do các hoạt động I/O nên nó có tác động tiêu cực đến cơ sở dữ liệu. Và ngược lại - giá trị càng thấp thì khả năng can thiệp OOM-Killer càng cao nhưng hiệu suất cơ sở dữ liệu cũng cao hơn. Giá trị mặc định là 60, nhưng nếu toàn bộ cơ sở dữ liệu nằm gọn trong bộ nhớ thì tốt hơn nên đặt giá trị thành 1.

Kết quả

Đừng để “kẻ sát nhân” trong OOM-Killer làm bạn sợ hãi. Trong trường hợp này, kẻ sát nhân sẽ là vị cứu tinh cho hệ thống của bạn. Nó “giết chết” các tiến trình tồi tệ nhất và cứu hệ thống khỏi bị treo. Để tránh phải sử dụng OOM-Killer để chấm dứt PostgreSQL, hãy đặt thành vm.overcommit_memory giá trị 2. Điều này không đảm bảo rằng OOM-Killer sẽ không phải can thiệp, nhưng nó sẽ làm giảm khả năng buộc quá trình PostgreSQL chấm dứt.

Nguồn: www.habr.com

Thêm một lời nhận xét