2010-01-11 13 views
22

Tôi đang cố gắng gỡ lỗi rò rỉ bộ mô tả tệp trong một ứng dụng web Java chạy trong Jetty 7.0.1 trên Linux.IOException: Quá nhiều tệp đang mở

Ứng dụng đã hoạt động một cách vui vẻ trong một tháng hoặc lâu hơn khi yêu cầu bắt đầu không thành công do quá nhiều tệp mở và Jetty phải được khởi động lại.

java.io.IOException: Cannot run program [external program]: java.io.IOException: error=24, Too many open files 
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:459) 
    at java.lang.Runtime.exec(Runtime.java:593) 
    at org.apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.java:58) 
    at org.apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.java:246) 

Lúc đầu, tôi nghĩ vấn đề là với mã mà ra mắt chương trình bên ngoài, nhưng nó sử dụng commons-exec và tôi không thấy bất cứ điều gì sai với nó:

CommandLine command = new CommandLine("/path/to/command") 
    .addArgument("..."); 
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream(); 
Executor executor = new DefaultExecutor(); 
executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT)); 
executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer)); 
try { 
    executor.execute(command); 
} catch (ExecuteException executeException) { 
    if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) { 
     throw new MyCommandException("timeout"); 
    } else { 
     throw new MyCommandException(errorBuffer.toString("UTF-8")); 
    } 
} 

Bảng liệt kê các file mở trên máy chủ Tôi có thể thấy số lượng FIFO cao:

# lsof -u jetty 
... 
java 524 jetty 218w FIFO  0,6  0t0 19404236 pipe 
java 524 jetty 219r FIFO  0,6  0t0 19404008 pipe 
java 524 jetty 220r FIFO  0,6  0t0 19404237 pipe 
java 524 jetty 222r FIFO  0,6  0t0 19404238 pipe 

khi Jetty bắt đầu chỉ có 10 FIFO, sau vài ngày có hàng trăm FIFO.

Tôi biết có chút mơ hồ ở giai đoạn này, nhưng bạn có bất kỳ đề xuất nào về vị trí tiếp theo hay cách nhận thông tin chi tiết hơn về các bộ mô tả tệp đó không?

+0

Hãy xem một số mã –

+0

Đã thêm mã khởi chạy chương trình bên ngoài. –

+0

Là nguồn bổ sung của informaiton netstat -anp --tcp | grep --color có thể là – zaletniy

Trả lời

7

Chương trình bên ngoài của bạn không hoạt động đúng cách. Hãy xem tại sao nó không làm điều đó.

+0

Vì vậy, bạn đang nói đó là chương trình bên ngoài làm rò rỉ các bộ mô tả tệp? Nhưng tại sao ngăn chặn Jetty xóa tất cả các FIFO? –

+0

Nó thực sự có thể chấm dứt bất thường trong một số trường hợp, và tôi không thể tránh điều đó: nó phụ thuộc vào đầu vào của người dùng. Nhưng đó cũng có thể là vấn đề. –

+0

Đây là vấn đề Hudson: https://hudson.dev.java.net/issues/show_bug.cgi?id=715 –

8

Khi bạn đang chạy trên Linux, tôi nghi ngờ bạn đang hết bộ mô tả tệp. Kiểm tra ulimit. Đây là bài viết mô tả sự cố: http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

+6

Điều này có thể giúp bạn có được tới 2 tháng thời gian chạy! (Đây là một băng cứu trợ tốt nhất.) –

+1

Bạn đã tái lặp lại triệu chứng nhưng không phải là cách chữa trị thực sự. –

+0

Thực ra tôi đã tăng giới hạn trong '/ etc/security/limits.conf' vì những lý do khác. –

5

Không biết tính chất của ứng dụng, nhưng tôi đã thấy lỗi này được biểu hiện nhiều lần do rò rỉ hồ bơi kết nối, vì vậy sẽ đáng để kiểm tra. Trên Linux, các kết nối ổ cắm tiêu thụ các bộ mô tả tập tin cũng như các tệp hệ thống tệp. Chỉ là một ý nghĩ.

2

Bạn có thể tự xử lý các fds. Các exec trong java trả về một đối tượng Process. Kiểm tra liên tục nếu quá trình vẫn đang chạy. Khi đã hoàn tất, hãy đóng các quy trình STDERR, STDIN và luồng STDOUT (ví dụ: proc.getErrorStream.close()). Điều đó sẽ giảm thiểu rò rỉ.

22

Sự cố xuất phát từ ứng dụng Java của bạn (hoặc thư viện bạn đang sử dụng).

Đầu tiên, bạn nên đọc toàn bộ kết quả đầu ra (Google cho StreamGobbler) và tiếp tục!

Javadoc nói:

Quá trình cha mẹ sử dụng những con suối để nuôi góp ý kiến ​​và nhận được kết quả từ các tiến trình con. Bởi vì một số nền tảng bản địa chỉ cung cấp đệm hạn chế kích thước cho đầu vào tiêu chuẩn và đầu ra suối, thất bại trong việc kịp thời viết input stream hoặc đọc các dòng sản lượng của tiến trình con có thể làm cho subprocess chặn, và thậm chí bế tắc.

Thứ hai, waitFor() quá trình chấm dứt. Sau đó, bạn phải đóng luồng đầu vào, đầu ra và lỗi.

Cuối cùngdestroy() Quy trình của bạn.

nguồn của tôi:

+1

Đây là câu trả lời đúng thực sự chứa thông tin hữu ích. –

+2

Bạn không cần phải hủy quá trình nếu 'waitFor()' đã thành công. Quá trình đã thoát. – EJP

4

Bên cạnh nhìn vào vấn đề nguyên nhân gốc rễ như rò rỉ tập tin, vv để làm một sự gia tăng hợp pháp " mở các tệp "giới hạn và có tồn tại trong quá trình khởi động lại, hãy xem xét chỉnh sửa

/etc/security/limits.conf 

bằng cách thêm một cái gì đó như thế này

jetty soft nofile 2048 
jetty hard nofile 4096 

nơi "cầu cảng" là tên người dùng trong trường hợp này. Để biết thêm chi tiết về limits.conf, xem http://linux.die.net/man/5/limits.conf

log off và sau đó đăng nhập lại và chạy

ulimit -n 

để xác minh rằng sự thay đổi đã diễn ra. Các quy trình mới của người dùng này giờ đây sẽ tuân thủ thay đổi này. This link dường như mô tả cách áp dụng giới hạn cho các quy trình đã chạy nhưng tôi chưa thử.

Giới hạn mặc định 1024 có thể quá thấp đối với các ứng dụng Java lớn.