Tắt trình diệt OOM Linux theo mặc định?


37

Kẻ giết người OOM trên Linux thường xuyên phá hủy các ứng dụng khác nhau và dường như không có nhiều việc thực sự được thực hiện ở phía phát triển kernel để cải thiện điều này. Nó sẽ không tốt hơn, như là một cách tốt nhất khi thiết lập một máy chủ mới , để đảo ngược mặc định trên bộ nhớ quá mức, nghĩa là tắt nó đi ( vm.overcommit_memory=2) trừ khi bạn biết bạn muốn sử dụng nó cho mục đích sử dụng cụ thể của bạn? Và những trường hợp sử dụng đó sẽ là nơi bạn biết bạn muốn xử lý quá mức?

Như một phần thưởng, vì hành vi trong trường hợp vm.overcommit_memory=2phụ thuộc vm.overcommit_ratiovà hoán đổi không gian, điều gì sẽ là một quy tắc tốt để định cỡ hai cái sau để toàn bộ thiết lập này tiếp tục hoạt động hợp lý?

Câu trả lời:


63

Một sự tương tự thú vị (từ http://lwn.net/Articles/104179/ ):

Một công ty máy bay phát hiện ra rằng nó rẻ hơn khi bay máy bay với ít nhiên liệu hơn trên máy bay. Các máy bay sẽ nhẹ hơn và sử dụng ít nhiên liệu hơn và tiền đã được tiết kiệm. Tuy nhiên, trong những dịp hiếm hoi, lượng nhiên liệu không đủ và máy bay sẽ gặp sự cố. Vấn đề này đã được các kỹ sư của công ty giải quyết bằng cách phát triển cơ chế OOF (hết nhiên liệu) đặc biệt. Trong trường hợp khẩn cấp, một hành khách đã được chọn và ném ra khỏi máy bay. (Khi cần thiết, quy trình được lặp lại.) Một cơ thể lớn về lý thuyết đã được phát triển và nhiều ấn phẩm được dành cho vấn đề lựa chọn đúng nạn nhân sẽ bị đẩy ra. Nạn nhân có nên được chọn ngẫu nhiên? Hay người ta nên chọn người nặng nhất? Hay lâu đời nhất? Hành khách nên trả tiền để không bị đẩy ra, để nạn nhân sẽ là người nghèo nhất trên tàu? Và nếu ví dụ người nặng nhất được chọn, liệu có nên có ngoại lệ đặc biệt trong trường hợp đó là phi công không? Hành khách hạng nhất có nên được miễn? Bây giờ cơ chế OOF đã tồn tại, nó sẽ được kích hoạt mọi lúc, và đẩy hành khách ngay cả khi không thiếu nhiên liệu. Các kỹ sư vẫn đang nghiên cứu chính xác làm thế nào sự cố này được gây ra.


11
Tôi rất thích điều đó, cảm ơn vì đã đào nó ra.
Nick Bolton

32

Kẻ giết người OOM chỉ tàn phá nếu bạn làm quá tải hệ thống của mình. Cung cấp cho nó đủ trao đổi và không chạy các ứng dụng đột nhiên quyết định ăn một lượng lớn RAM và bạn sẽ không gặp vấn đề gì.

Để trả lời cụ thể câu hỏi của bạn:

  • Tôi không nghĩ rằng đó là một ý tưởng tốt để tắt quá mức trong trường hợp chung; rất ít ứng dụng được viết để xử lý đúng brk(2) (và các hàm bao sử dụng nó, chẳng hạn như malloc(3)) trả về lỗi. Khi tôi thử nghiệm điều này ở công việc trước đây, nó được coi là rắc rối hơn để có được mọi thứ có khả năng xử lý các lỗi ngoài bộ nhớ hơn là để giải quyết hậu quả của một OOM (trong trường hợp của chúng tôi, tồi tệ hơn nhiều so với việc phải khởi động lại dịch vụ không thường xuyên nếu xảy ra OOM - chúng tôi phải khởi động lại toàn bộ cụm, vì GFS là một đống phân hấp).
  • Bạn muốn quá mức cho bất kỳ quá trình nào vượt quá bộ nhớ. Hai thủ phạm phổ biến nhất ở đây là Apache và JVM, nhưng rất nhiều ứng dụng làm điều này ở mức độ lớn hơn hoặc thấp hơn. Họ nghĩ rằng họ có thể cần rất nhiều bộ nhớ vào một thời điểm nào đó trong tương lai, vì vậy họ chộp lấy một khúc lớn ngay lập tức. Trên một hệ thống hỗ trợ quá mức, kernel sẽ "meh, sao cũng được, làm phiền tôi khi bạn thực sự muốn viết vào những trang đó" và không có gì xấu xảy ra. Trên một hệ thống quá mức, hạt nhân nói "không, bạn không thể có nhiều bộ nhớ như vậy, nếu bạn tình cờ viết cho nó vào một lúc nào đó trong tương lai tôi sẽ bị bỏ rơi, vì vậy không có bộ nhớ cho bạn!" và việc phân bổ thất bại. Vì không có gìngoài kia có "oh, OK, tôi có thể có số lượng phân đoạn dữ liệu quá trình nhỏ hơn không?", sau đó quá trình (a) thoát khỏi lỗi hết bộ nhớ hoặc (b) không kiểm tra mã trả về từ malloc, nghĩ rằng nó ổn để đi và ghi vào một vị trí bộ nhớ không hợp lệ, gây ra một segfault. Rất may, JVM thực hiện tất cả những gì nó khởi động khi khởi động (vì vậy JVM của bạn sẽ khởi động hoặc chết ngay lập tức, mà bạn thường thấy), nhưng Apache thực hiện công cụ thú vị với mỗi đứa trẻ mới, có thể có các hiệu ứng thú vị trong sản xuất (không thể xử lý "không xử lý các kết nối "Các loại phấn khích).
  • Tôi sẽ không muốn đặt overcommit_ratio của mình cao hơn mặc định là 50%. Một lần nữa, từ thử nghiệm của tôi, mặc dù thiết lập khoảng 80 hoặc 90 nghevẻ là một ý tưởng hay, hạt nhân đòi hỏi bộ nhớ lớn vào những thời điểm bất tiện và một hệ thống được nạp đầy đủ với tỷ lệ quá cao có thể sẽ không đủ bộ nhớ dự phòng khi hạt nhân cần nó (dẫn đến sợ hãi, sâu bệnh và oops). Vì vậy, chơi với Overcommit giới thiệu một chế độ thất bại mới, thậm chí thú vị hơn - thay vì chỉ khởi động lại bất kỳ quá trình nào bị OOMed khi bạn hết bộ nhớ, bây giờ máy của bạn gặp sự cố, dẫn đến hết mọi thứ trên máy. TUYỆT VỜI!
  • Hoán đổi không gian trong một hệ thống không có quá nhiều phụ thuộc vào số lượng bộ nhớ được yêu cầu nhưng không sử dụng mà ứng dụng của bạn cần, cộng với một mức an toàn lành mạnh. Tìm ra những gì cần thiết trong một trường hợp cụ thể được để lại như một bài tập cho người đọc.

Về cơ bản, kinh nghiệm của tôi là tắt overcommit là một thử nghiệm hay, hiếm khi hoạt động tốt trong thực tế như trên lý thuyết. Đây độc đáo tương ứng với kinh nghiệm của tôi với tunables khác trong hạt nhân - Linux kernel nhà phát triển là hầu như luôn luôn thông minh hơn bạn, và giá trị mặc định làm việc tốt nhất cho mênh mông, rộng lớn đa số trường hợp. Để chúng một mình, và thay vào đó hãy đi tìm quá trình có rò rỉ và khắc phục nó.


2
Tôi không muốn quá trình sao lưu của mình bị giết vì ai đó là DoS-ing máy chủ web của tôi. Các ngoại lệ là tốt nhưng mặc định phải là an toàn và nhất quán. Tối ưu hóa như OOM nên được bật thủ công IMHO. Nó giống như mã hóa, bạn viết mã sạch sẽ, và sau đó tối ưu hóa. Cam kết quá mức là một tính năng hay, nhưng không nên là mặc định.
Aki

1
Nếu bạn không muốn quá trình sao lưu của mình bị giết vì ai đó đang sử dụng máy chủ web của bạn, đừng cấu hình máy chủ web của bạn theo cách mà DoS có thể khiến tài nguyên trên hệ thống bị quá tải.
womble

Tôi có 8GB RAM và chỉ chạy Firefox và một máy ảo đôi khi dẫn đến kẻ giết người OOM giết chết VM. Biên dịch Unreal Engine 4, mỗi lần gọi clang chiếm 1 ~ 1,5 GB bộ nhớ và một lần nữa, kẻ giết người OOM giết chết từng người một. Bây giờ tôi nói chung là ổn với điều đó, nếu không có kẻ giết người OOM thì có lẽ họ sẽ tách ra bằng mọi cách. Chỉ là mỗi khi kẻ giết người OOM muốn giết một quá trình, hệ thống của tôi sẽ đóng băng trong 10 phút trước khi quá trình tồi tệ thực sự bị giết. Lỗi có lẽ? Nhiều khả năng. Tôi có muốn nó không? Chắc chắn không phải. Và đó là lý do của bạn tại sao người ta có thể muốn vô hiệu hóa kẻ giết người OOM.
Shahbaz

1
Nếu bạn đang làm tất cả những điều đó trên một hộp, bạn cần thêm RAM và việc vô hiệu hóa quá mức sẽ chỉ làm cho nó tồi tệ hơn.
Ben Lutgens

6

Hmm, tôi không hoàn toàn bị thuyết phục bởi những lập luận ủng hộ kẻ giết người quá mức và OOM ... Khi womble viết,

"Kẻ giết người OOM chỉ tàn phá nếu bạn làm quá tải hệ thống của mình. Hãy trao đổi đủ và không chạy các ứng dụng đột nhiên quyết định ăn một lượng lớn RAM và bạn sẽ không gặp vấn đề gì."

Anh ta mô tả một kịch bản môi trường trong đó kẻ giết người quá mức và kẻ giết người OOM không được thi hành hoặc không thực sự hành động (nếu tất cả các ứng dụng được cấp phát bộ nhớ khi cần và có đủ bộ nhớ ảo được phân bổ, bộ nhớ ghi sẽ theo sát việc cấp phát bộ nhớ lỗi, vì vậy chúng tôi thực sự không thể nói về một hệ thống quá mức ngay cả khi chiến lược overcommit được kích hoạt). Đó là về một sự thừa nhận ngầm rằng kẻ giết người quá mức và OOM hoạt động tốt nhất khi không cần sự can thiệp của họ, điều này được chia sẻ bởi hầu hết những người ủng hộ chiến lược này, theo như tôi có thể nói (và tôi thừa nhận tôi không thể nói nhiều ...). Morover, đề cập đến các ứng dụng có hành vi cụ thể khi sắp xếp bộ nhớ khiến tôi nghĩ rằng một cách xử lý cụ thể có thể được điều chỉnh ở mức phân phối, thay vì có mặc định,

Đối với vấn đề liên quan đến JVM, đó là một máy ảo, ở một mức độ nào đó, nó cần phân bổ tất cả các tài nguyên cần thiết khi khởi động, để nó có thể tạo môi trường 'giả' cho các ứng dụng của nó và tách biệt tài nguyên có sẵn của nó khỏi máy chủ môi trường, càng xa càng tốt. Do đó, có thể tốt hơn là nó đã thất bại khi khởi động, thay vì sau một thời gian do hậu quả của tình trạng OOM 'bên ngoài' (gây ra bởi kẻ giết người quá mức / OOM / bất cứ điều gì), hoặc dù sao cũng phải chịu đựng một tình trạng như vậy can thiệp vào chính nó Các chiến lược xử lý OOM nội bộ (nói chung, VM sẽ nhận được bất kỳ tài nguyên cần thiết nào ngay từ đầu và hệ thống máy chủ nên 'bỏ qua' chúng cho đến khi kết thúc, giống như bất kỳ lượng ram vật lý nào được chia sẻ với card đồ họa là không bao giờ - và không thể - xúc động bởi HĐH).

Về Apache, tôi nghi ngờ rằng việc thỉnh thoảng toàn bộ máy chủ bị giết và khởi động lại tốt hơn là để một đứa trẻ, cùng với một kết nối, thất bại từ khi bắt đầu (= đứa trẻ / kết nối) (như thể đó là một trường hợp hoàn toàn mới của JVM được tạo sau khi một cá thể khác chạy một lúc). Tôi đoán "giải pháp" tốt nhất có thể phụ thuộc vào bối cảnh cụ thể. Ví dụ, khi xem xét một dịch vụ thương mại điện tử, đôi khi, một vài kết nối với biểu đồ mua sắm không thành công thay vì mất toàn bộ dịch vụ, với rủi ro, làm gián đoạn việc hoàn tất đơn hàng đang diễn ra, hoặc (có thể tệ hơn) một quy trình thanh toán, với tất cả các hậu quả của vụ án (có thể vô hại, nhưng có thể vô hại - và chắc chắn, khi có vấn đề phát sinh,

Tương tự, trên máy trạm, quy trình tiêu tốn nhiều tài nguyên nhất và do đó, việc trở thành lựa chọn đầu tiên cho kẻ giết người OOM, có thể là một ứng dụng cần nhiều bộ nhớ, như trình chuyển mã video hoặc phần mềm kết xuất, có thể là ứng dụng duy nhất người dùng muốn được chạm đến. Cân nhắc này gợi ý cho tôi rằng chính sách mặc định của kẻ giết người OOM quá mạnh mẽ. Nó sử dụng cách tiếp cận "phù hợp nhất" tương tự như một số hệ thống tập tin (OOMK cố gắng và giải phóng bộ nhớ nhiều nhất có thể, đồng thời giảm số lượng các quy trình con bị giết, để ngăn chặn bất kỳ sự can thiệp nào nữa trong thời gian ngắn, như cũng như một fs có thể phân bổ nhiều không gian đĩa hơn sau đó thực sự cần thiết cho một tệp nhất định, để ngăn chặn bất kỳ sự phân bổ nào nữa nếu tệp phát triển và do đó ngăn chặn sự phân mảnh, ở một mức độ nào đó).

Tuy nhiên, tôi nghĩ rằng một chính sách ngược lại, như cách tiếp cận 'phù hợp nhất', có thể tốt hơn, vì vậy để giải phóng bộ nhớ chính xác cần thiết tại một thời điểm nhất định và không bị làm phiền với các quy trình 'lớn', có thể gây lãng phí bộ nhớ, nhưng cũng có thể không, và hạt nhân không thể biết điều đó (hmm, tôi có thể tưởng tượng rằng việc theo dõi số lần truy cập trang và thời gian có thể gợi ý nếu một quá trình phân bổ bộ nhớ thì nó không cần thêm nữa, vì vậy hãy đoán xem liệu một quy trình đang lãng phí bộ nhớ hoặc chỉ sử dụng nhiều, nhưng độ trễ truy cập nên được tính theo chu kỳ cpu để phân biệt lãng phí bộ nhớ với ứng dụng chuyên sâu về bộ nhớ cpu, nhưng, trong khi có khả năng không chính xác, các heuristic như vậy có thể có quá nhiều chi phí).

Hơn nữa, có thể không đúng khi giết ít quy trình có thể luôn luôn là một lựa chọn tốt. Chẳng hạn, trên môi trường máy tính để bàn (hãy nghĩ về một cái lưới hoặc một chiếc netbook có tài nguyên hạn chế, ví dụ), người dùng có thể đang chạy một trình duyệt có nhiều tab (do đó, tiêu thụ bộ nhớ - giả sử đây là lựa chọn đầu tiên cho OOMK) , cộng với một vài ứng dụng khác (trình xử lý văn bản với dữ liệu không được lưu, ứng dụng thư khách, trình đọc pdf, trình phát đa phương tiện, ...), cùng với một vài trình nền (hệ thống), cùng với một vài phiên bản trình quản lý tệp. Bây giờ, một lỗi OOM xảy ra và OOMK chọn giết trình duyệt trong khi người dùng đang làm điều gì đó được coi là 'quan trọng' qua mạng ... người dùng sẽ thất vọng. Mặt khác, đóng vài trình quản lý tệp '

Dù sao, tôi nghĩ rằng người dùng nên được kích hoạt để tự mình đưa ra quyết định về những việc cần làm. Trong một hệ thống máy tính để bàn (= tương tác), điều đó tương đối dễ thực hiện, cung cấp đủ tài nguyên để yêu cầu người dùng đóng bất kỳ ứng dụng nào (nhưng thậm chí đóng một vài tab có thể là đủ) và xử lý lựa chọn của mình (một tùy chọn có thể bao gồm tạo một tệp hoán đổi bổ sung, nếu có đủ dung lượng). Đối với các dịch vụ (và nói chung), tôi cũng sẽ xem xét hai cải tiến có thể có nữa: một là ghi nhật ký can thiệp giết người OOM, cũng như các quá trình bắt đầu / giả mạo thất bại theo cách mà lỗi có thể dễ dàng gỡ lỗi (ví dụ: API có thể thông báo cho quá trình ban hành quá trình tạo hoặc tạo quy trình mới - do đó, một máy chủ như Apache, với một bản vá thích hợp, có thể cung cấp một bản ghi tốt hơn cho các lỗi nhất định); điều này có thể được thực hiện một cách độc lập từ nỗ lực quá mức / OOMK đang nỗ lực; ở vị trí thứ hai, nhưng không quan trọng, một cơ chế có thể được thiết lập để tinh chỉnh thuật toán OOMK - ở một mức độ nào đó, tôi có thể xác định một chính sách cụ thể trên quy trình theo quy trình, nhưng tôi nhắm đến Cơ chế cấu hình 'tập trung', dựa trên một hoặc nhiều danh sách tên ứng dụng (hoặc id) để xác định các quy trình có liên quan và cung cấp cho chúng một mức độ quan trọng nhất định (theo các thuộc tính được liệt kê); một cơ chế như vậy cũng nên (hoặc ít nhất là có thể) cũng được xếp lớp, để có thể có một danh sách do người dùng xác định cấp cao nhất, danh sách do hệ thống (phân phối-) xác định và các mục được xác định ứng dụng (cấp dưới) , ví dụ, trình quản lý tệp DE có thể ra lệnh cho OOMK tiêu diệt an toàn mọi trường hợp,

Hơn nữa, API có thể được cung cấp để cho phép các ứng dụng tăng hoặc giảm mức độ quan trọng của chúng trong thời gian chạy (liên quan đến mục đích quản lý bộ nhớ và bất kể mức độ ưu tiên thực thi), do đó, ví dụ, bộ xử lý Word có thể bắt đầu mức độ quan trọng thấp nhưng tăng lên khi một số dữ liệu được giữ trước khi xả vào tệp hoặc thao tác ghi đang được thực hiện và mức độ quan trọng thấp hơn một lần nữa khi hoạt động đó kết thúc (tương tự, trình quản lý tệp có thể thay đổi cấp độ khi nó được truyền từ cho phép các tệp xử lý dữ liệu và ngược lại, thay vì sử dụng các quy trình riêng biệt và Apache có thể đưa ra các mức độ quan trọng khác nhau cho những đứa trẻ khác nhau hoặc thay đổi trạng thái con theo một số chính sách được quyết định bởi sysadins và được hiển thị thông qua Apache - hoặc bất kỳ loại máy chủ nào khác - cài đặt). Tất nhiên, một API như vậy có thể và sẽ bị lạm dụng / sử dụng sai, nhưng tôi nghĩ đó là mối quan tâm nhỏ so với hạt nhân tự ý giết chết các quá trình để giải phóng bộ nhớ mà không có bất kỳ thông tin liên quan nào về hệ thống (và mức tiêu thụ bộ nhớ / thời gian tạo hoặc tương tự 'đủ liên quan hoặc' xác thực 'đối với tôi) - chỉ người dùng, quản trị viên và người viết chương trình mới thực sự có thể xác định liệu một quy trình là' vẫn cần thiết 'vì một số lý do, lý do là gì và / hoặc nếu ứng dụng ở trạng thái hàng đầu mất dữ liệu hoặc thiệt hại / rắc rối khác nếu bị giết; tuy nhiên, một số giả định chưa thể được đưa ra, ví dụ như tìm kiếm tài nguyên của một loại nào đó (mô tả tệp, ổ cắm mạng, v.v.) có được bởi một quy trình và với các hoạt động đang chờ xử lý có thể cho biết liệu một quy trình có ở trạng thái 'cao hơn' không một bộ

Hoặc, chỉ cần tránh quá mức và để hạt nhân làm những gì hạt nhân phải làm, phân bổ tài nguyên (nhưng không giải cứu chúng một cách tùy tiện như kẻ giết người OOM), lên lịch xử lý, ngăn chặn nạn đói và bế tắc (hoặc giải cứu chúng), đảm bảo hoàn toàn trước và phân tách không gian bộ nhớ, v.v.

Tôi cũng sẽ dành nhiều lời hơn về các phương pháp tiếp cận quá mức. Từ các cuộc thảo luận khác, tôi đã đưa ra ý tưởng rằng một trong những mối quan tâm chính về vấn đề quá mức (cả lý do muốn nó và là nguồn gốc của những rắc rối có thể xảy ra) bao gồm các cách xử lý: thật lòng, tôi không biết chính xác bản sao như thế nào- chiến lược trên văn bản được thực hiện, nhưng tôi nghĩ rằng bất kỳ chính sách tích cực (hoặc lạc quan) nào cũng có thể được giảm thiểu bằng chiến lược địa phương hoán đổi. Đó là, thay vì chỉ nhân bản (và điều chỉnh) một trang mã quy trình rẽ nhánh và cấu trúc lập lịch, một vài trang dữ liệu khác có thể được sao chép trước khi viết thực tế, chọn trong số các trang mà quy trình cha mẹ đã truy cập để viết thường xuyên hơn (nghĩa là sử dụng một bộ đếm cho các hoạt động ghi).

Tất cả mọi thứ, tất nhiên, IMHO.


5
"Morover, một API có thể được cung cấp để cho phép các ứng dụng tăng hoặc giảm mức độ" quan trọng "của chúng trong thời gian chạy" Tầm quan trọng là /proc/$PID/oom_adj.
Vi.

1
Về JVM, có một vấn đề khiến bạn muốn bộ nhớ quá mức trong một số trường hợp: trong trường hợp bạn muốn tạo một JVM khác từ JVM gốc của mình, nó sẽ gọi fork (). Một cuộc gọi ngã ba sẽ phân bổ nhiều bộ nhớ như quy trình ban đầu (đầu tiên), cho đến khi nó thực sự bắt đầu quá trình. Vì vậy, giả sử bạn có JVM 4GB và muốn tạo JVM 512KB mới từ nó, trừ khi bạn có quá nhiều, bạn sẽ cần 8GB bộ nhớ để làm điều đó ...
alci

4
@Vi. Có vẻ như bây giờ là/proc/$PID/oom_score_adj
erm3nda

1

Nếu bộ nhớ của bạn được sử dụng triệt để bởi các quy trình đến mức có thể đe dọa sự ổn định của hệ thống, thì kẻ giết người OOM sẽ xuất hiện. Nhiệm vụ của OOM Killer là tiêu diệt các tiến trình cho đến khi đủ bộ nhớ được giải phóng cho hoạt động trơn tru của phần còn lại của quá trình. Kẻ giết người OOM phải chọn quy trình tốt nhất để giết. Best Best ở đây đề cập đến quá trình đó sẽ giải phóng bộ nhớ tối đa khi giết và cũng ít quan trọng nhất đối với hệ thống. Mục tiêu chính là tiêu diệt số lượng quá trình ít nhất nhằm giảm thiểu thiệt hại và đồng thời tối đa hóa lượng bộ nhớ được giải phóng. Để tạo điều kiện cho điều này, kernel duy trì oom_score cho mỗi tiến trình. Bạn có thể thấy oom_score của từng quy trình trong hệ thống tập tin / Proc trong thư mục pid

# cat /proc/10292/oom_score

Giá trị của oom_score của bất kỳ quá trình nào càng cao thì khả năng bị giết bởi OOM Killer càng cao trong tình huống hết bộ nhớ.

Tín dụng: - Nhân Linux đang bắt đầu trình diệt OOM

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.