Ổ cắm được tìm thấy bởi lsof nhưng không phải bởi netstat


19

Tôi có một ứng dụng sắp hết các mô tả tập tin, rõ ràng bằng cách mở các socket, nhưng tôi không thể tìm ra chính xác những gì các socket này làm. Chúng xuất hiện trong đầu ra lsof như

java    9689 appuser 1010u  sock       0,5          263746675 can't identify protocol
java    9689 appuser 1011u  sock       0,5          263746676 can't identify protocol
java    9689 appuser 1012u  sock       0,5          263746677 can't identify protocol
java    9689 appuser 1014u  sock       0,5          263746678 can't identify protocol
java    9689 appuser 1015u  sock       0,5          263746679 can't identify protocol
java    9689 appuser 1016u  sock       0,5          263746681 can't identify protocol

và trong / Proc / $ PID / fd là

lrwx------ 1 appuser appuser 64 Jun 23 11:49 990 -> socket:[263732085]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 991 -> socket:[263732086]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 992 -> socket:[263735307]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 993 -> socket:[263732088]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 995 -> socket:[263735308]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 996 -> socket:[263735309]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 997 -> socket:[263745434]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 998 -> socket:[263745435]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 999 -> socket:[263745436]

nhưng không có đầu ra tương tự trong netstat -a.

Những ổ cắm này là gì và làm thế nào tôi có thể tìm ra chúng làm gì?

Chỉnh sửa : Tôi đã thử chạy grep $SOCKET /proc/net, như được đề xuất trong Câu hỏi thường gặp của lsof , trong đó $ SOCKET là ví dụ 263746679, nhưng điều đó cũng không cho kết quả.


Là nền tảng, ứng dụng là một thùng chứa cho nhiều tác vụ, trong số các tác vụ khác, thực hiện các cuộc gọi mạng. Tôi cần phải tìm ra một trong những người điên loạn, nhưng cho đến khi tôi tìm ra những người đó liên lạc với ai, tôi bị mắc kẹt.


Gần đây, chúng tôi cũng đang gặp phải vấn đề này với một trong những ứng dụng web .NET Core (máy chủ Ubuntu có Kestrel), nhưng thiết bị được ghi là "0,9" với tên "giao thức: TCP". Cố gắng tìm hiểu chính xác những thiết bị 0 và 9 nào được chứng minh là khó. Nhưng tất cả các triệu chứng cảm thấy giống như trường hợp mở ổ cắm mà không ràng buộc và sử dụng chúng.
icelava

Câu trả lời:


17

Điều này có thể xảy ra nếu bạn tạo một ổ cắm, nhưng không bao giờ kết nối () hoặc liên kết () với nó. Đặt cược tốt nhất của bạn có thể là sải bước (-fF) ứng dụng, và sau đó tham chiếu chéo với đầu ra của lsof để xác định ổ cắm nào gây ra sự cố. Là một phương pháp gỡ lỗi bổ sung: nếu bạn bọc các cuộc gọi ổ cắm của mình bằng thông tin gỡ lỗi và ghi chúng ra / dev / null, nó sẽ xuất hiện theo từng bước mà không cung cấp cho bạn các tệp nhật ký lớn.


Cảm ơn, điều này nghe có vẻ thú vị. Tôi sẽ cố gắng tìm hiểu nếu đó thực sự là trường hợp với ứng dụng của chúng tôi.
Robert Munteanu

1
Một phần nào đó trên cùng một dòng, bởi vì đây là Java có thể rất khó sử dụng strace; một phương pháp tốt hơn có thể là tạo lớp con socket riêng của bạn để ghi thông tin trước khi truyền nó tới socket JDK (thật). strace chỉ có thể thấy các lệnh gọi Java cơ bản đến HĐH và không thể thấy bên trong các luồng của bạn để biết những gì thực sự thực hiện các cuộc gọi socket đó, để strace tất cả trông giống như một quả bóng lớn của java.
troyengel

@troyengel: Tôi (đã) phát hiện ra Byteman ( jboss.org/byteman ) một công cụ rất gọn gàng cho phép tôi tiêm mã byte cần thiết để theo dõi các cuộc gọi này.
Robert Munteanu

Câu trả lời hữu ích nhất, vì vậy điều này nhận được tiền thưởng. Cảm ơn!
Robert Munteanu

2

Sử dụng Python, tôi đã gặp phải vấn đề tương tự trên các socket SSL:

  • Khi tôi sử dụng socket.close (), ổ cắm vẫn ở trạng thái CLOSE_WAIT trong một thời gian không xác định
  • Khi tôi sử dụng socket.shutdown (), lsof nói "không thể xác định giao thức"

Giải pháp là mở lớp SSL trước khi đóng:

  • origsock = socket.unwrap ()
  • origsock.c Đóng ()

Điều này sẽ đóng các ổ cắm đúng cách trong ứng dụng của tôi.


1

Điều đầu tiên tôi sẽ làm là khắc phục nếu giới hạn mô tả tệp của bạn:

~# vi /etc/sysctl.conf
fs.file-max = 331287

Tiếp theo tôi sẽ đảm bảo hệ thống của bạn được cập nhật, điều này bao gồm tất cả các thư viện và máy chủ. Có thể máy chủ ứng dụng Java của bạn đã hết hạn (nếu bạn đang sử dụng một máy chủ). Cũng có khả năng máy chủ ứng dụng của bạn bị định cấu hình sai, bạn nên xem tệp cấu hình của mình và hạ thấp connectionTimeoutvà / hoặc của bạn maxKeepAliveRequests(Tôi không chắc máy chủ ứng dụng nào bạn đang sử dụng hoặc nếu bạn đang sử dụng một ...).

Tôi không chắc ứng dụng này làm gì, nhưng nếu bạn không nghĩ rằng nó cần hàng chục nghìn ổ cắm thì đây gần như chắc chắn là một "rò rỉ mô tả tệp" trong ứng dụng Java của bạn. Bạn có thể phải gửi một báo cáo lỗi cho nhà cung cấp. Trong báo cáo lỗi này, bạn nên bao gồm thông tin về cách tạo lại vấn đề.

Dưới đây là một số cách để gỡ lỗi vấn đề.

Wireshark (hoặc twireshark cho cli) là công cụ tốt nhất để xem các ổ cắm này đang được sử dụng như thế nào. Wireshark sẽ cung cấp cho bạn thông tin về loại lưu lượng truy cập bị ném qua dây. Có khả năng một vài kết nối đầu tiên sẽ thành công và sau đó nó sẽ đạt giới hạn mô tả tệp. Khi giới hạn mô tả tệp được nhấn thì Wireshark sẽ không chọn bất cứ thứ gì (và gọn gàng hơn là vấn đề đó), nhưng điều này sẽ giúp thu hẹp vấn đề. Có thể có trường hợp rất nhiều các SYN gửi đi đang được gửi, tuy nhiên không có các SYN / ACK nào được nhận, do đó, rất nhiều kết nối tcp bị kẹt trong trạng thái SYN_WAIT.

Nếu bạn có quyền truy cập vào mã nguồn và bạn biết loại ổ cắm được tạo (chẳng hạn như sử dụng strace hoặc chỉ tìm kiếm mã) thì bạn có thể mở dự án trong Eclipse (hoặc IDE khác) và đặt điểm dừng tại chức năng đó đang tạo ra các ổ cắm này. Khi điểm dừng bị tấn công, sau đó bạn có thể nhìn vào dấu vết ngăn xếp. Rò rỉ mô tả tập tin này có thể là một vòng lặp vô hạn đơn giản hoặc có lẽ giá trị thời gian chờ của ổ cắm quá lớn. Một khả năng khác là ứng dụng java không làm socket.close()sạch các kết nối. Thực hiện đóng thường được thực hiện trong một finelykhối của một try/catch(Có một ổ cắm phải luôn có một lần thử / bắt trong Java hoặc nó sẽ không được xây dựng :). Vào cuối ngày, có khả năng ứng dụng Java không xử lý đúng cách IOException của nó.


Cảm ơn câu trả lời. Tôi thực sự đang phát triển ứng dụng này - phần container - thay vì chỉ quản lý nó và tôi không thể tìm thấy bất kỳ vấn đề nào liên quan đến ổ cắm không bị đóng. Nhưng gợi ý wireshark / twireshark là tốt, tôi sẽ sử dụng nó.
Robert Munteanu

@Robert Munteanu Nếu bạn đang xây dựng ứng dụng này thì đây là một câu hỏi cho stackoverflow. Không bao giờ bạn ít mở quá nhiều ổ cắm.
Rook

Rook: Tôi đã từ bỏ việc tìm ra mã này một cách khôn ngoan và cố gắng theo dõi nó như một sysadmin. Đó là lý do tại sao tôi đăng trên SF. Và vâng, tôi biết bằng cách nào đó có quá nhiều ổ cắm được mở. Nhưng không có manh mối nào về nơi ...
Robert Munteanu

@Robert Munteanu Bạn phải đặt điểm dừng khi tạo ổ cắm và xem dấu vết ngăn xếp và bộ nhớ tại điểm đó. Tôi nghi ngờ bạn đang rơi vào một vòng lặp vô hạn. Có thể xem xét bất kỳ biến và bước nào mặc dù mã của bạn sẽ là cách tiếp cận tốt nhất cho các vấn đề phức tạp như thế này.
Rook

Thật không may, điều này xảy ra dường như ngẫu nhiên trên một trong 20 máy chủ - không phải lúc nào cũng giống nhau -, chỉ trong môi trường sản xuất và có lẽ hai lần mỗi tuần. Nếu không, nó sẽ khá đơn giản để ra tay. Tôi hiện đang sử dụng Byteman ( jboss.org/byteman ) để theo dõi các cuộc gọi tạo / liên kết / kết nối / đóng ổ cắm. Hy vọng một cái gì đó sẽ ra khỏi nó.
Robert Munteanu
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.