Apache + Tomcat có vấn đề giao tiếp. Thông báo lỗi không rõ ràng. Đưa xuống các trang web được lưu trữ dưới Tomcat


22

Thiết lập:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache đang chuyển tiếp các yêu cầu bằng AJP.

Vấn đề:
Sau một khoảng thời gian nhất định (không có hằng số nào, có thể là giữa một hoặc hai giờ hoặc một hoặc nhiều ngày) Tomcat sẽ đi xuống. Hoặc là nó dừng đáp ứng, hoặc nó đưa ra 'Dịch vụ tạm thời không khả dụng'.

Chẩn đoán:
Có hai máy chủ có cùng thiết lập. Một trang web có lưu lượng truy cập cao hơn (một vài yêu cầu mỗi giây), một yêu cầu lưu lượng truy cập thấp (một số ít yêu cầu cứ sau vài phút). Cả hai trang web là các cơ sở mã hoàn toàn khác nhau, nhưng chúng thể hiện các vấn đề tương tự.

Trên máy chủ đầu tiên, khi sự cố xảy ra, tất cả các luồng bắt đầu được xử lý cho đến khi đạt đến giới hạn (MaxThreads 200). Tại thời điểm đó, máy chủ không còn phản hồi (và đi kèm với trang không có dịch vụ sau một thời gian dài).

Trên máy chủ thứ hai, khi sự cố xảy ra, các yêu cầu mất nhiều thời gian và khi chúng được thực hiện, tất cả những gì bạn thấy là trang không có dịch vụ.

Khác với việc đề cập đến vấn đề MaxThreads, nhật ký Tomcat không chỉ ra bất kỳ vấn đề cụ thể nào có thể gây ra sự cố này.

Tuy nhiên, trong nhật ký Apache, chúng ta thấy các thông báo ngẫu nhiên đề cập đến AJP. Đây là một mẫu thông báo ngẫu nhiên mà chúng ta thấy (không theo thứ tự cụ thể):

[error] (70007)The timeout specified has expired: ajp_ilink_receive() can't receive header
[error] (104)Connection reset by peer: ajp_ilink_receive() can't receive header
[error] proxy: AJP: disabled connection for (localhost)
[error] ajp_read_header: ajp_ilink_receive failed
[error] (120006)APR does not understand this error code: proxy: read response failed from 127.0.0.1:8009 (localhost)
[error] ap_proxy_connect_backend disabling worker for (localhost)

Một điều kỳ lạ khác mà chúng tôi nhận thấy trên máy chủ lưu lượng cao hơn là ngay trước khi sự cố bắt đầu xảy ra, các truy vấn cơ sở dữ liệu mất nhiều thời gian hơn trước (2000-5000 ms so với thông thường 5-50ms). Điều này chỉ tồn tại trong 2-4 giây trước khi thông báo MaxThreads xuất hiện. Tôi cho rằng đây là kết quả của việc máy chủ đột nhiên xử lý quá nhiều dữ liệu / lưu lượng / luồng.

Thông tin cơ bản:
Hai máy chủ này đã chạy mà không gặp sự cố trong một thời gian. Các hệ thống đã thực sự thiết lập từng cái bằng cách sử dụng hai NIC trong thời gian đó. Họ tách giao thông nội bộ và bên ngoài. Sau khi nâng cấp mạng, chúng tôi đã chuyển các máy chủ này sang các NIC đơn (điều này được khuyến nghị cho chúng tôi vì lý do bảo mật / đơn giản). Sau thay đổi đó, các máy chủ bắt đầu gặp những vấn đề này.

Giải pháp:
Giải pháp rõ ràng sẽ là quay trở lại thiết lập hai NIC. Vấn đề với điều đó là nó sẽ gây ra một số phức tạp với thiết lập mạng và có vẻ như bỏ qua vấn đề. Chúng tôi muốn thử và chạy nó trên một thiết lập NIC.

Googling các thông báo lỗi khác nhau không cung cấp bất cứ điều gì hữu ích (giải pháp cũ hoặc không liên quan đến vấn đề của chúng tôi).

Chúng tôi đã thử điều chỉnh thời gian chờ khác nhau nhưng điều đó chỉ khiến máy chủ chạy lâu hơn một chút trước khi chết.

Chúng tôi không chắc chắn nơi để tìm chẩn đoán vấn đề hơn nữa. Chúng tôi vẫn đang nắm bắt được ống hút về vấn đề có thể là gì:

1) Thiết lập với AJP và Tomcat không chính xác hoặc lỗi thời (nghĩa là các lỗi đã biết?)
2) Thiết lập mạng (hai NIC so với một NIC) đang gây ra sự cố nhầm lẫn hoặc thông lượng.
3) Bản thân các trang web (không có mã chung, không có nền tảng nào được sử dụng, chỉ có mã Java cơ bản với servlets và JSP)

Cập nhật 1:
Theo lời khuyên hữu ích của David Pashley, tôi đã thực hiện một dấu vết ngăn xếp / luồng trong suốt vấn đề. Những gì tôi tìm thấy là tất cả 200 chủ đề ở một trong các trạng thái sau:

"TP-Processor200" daemon prio=1 tid=0x73a4dbf0 nid=0x70dd waiting for monitor entry [0x6d3ef000..0x6d3efeb0]
at  oracle.jdbc.pool.OracleConnectionCacheImpl.getActiveSize(OracleConnectionCacheImpl.java:988)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

"TP-Processor3" daemon prio=1 tid=0x08f142a8 nid=0x652a waiting for monitor entry [0x75c7d000..0x75c7ddb0]
at oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection(OracleConnectionCacheImpl.java:268)
- waiting to lock <0x7e3455a0> (a oracle.jdbc.pool.OracleConnectionCacheImpl)
[further stack trace removed for brevity]

Thật kỳ lạ, chỉ có một chủ đề trong số 200 chủ đề ở trạng thái này:

"TP-Processor2" daemon prio=1 tid=0x08f135a8 nid=0x6529 runnable [0x75cfe000..0x75cfef30]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at oracle.net.ns.Packet.receive(Unknown Source)
at oracle.net.ns.DataPacket.receive(Unknown Source)
at oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
at oracle.net.ns.NetInputStream.read(Unknown Source)
[further stack trace removed for brevity]

Có thể là trình điều khiển Oracle trong luồng này đang buộc tất cả các luồng khác phải đợi nó hoàn thành. Vì một số lý do, nó phải bị kẹt trong trạng thái đọc này (máy chủ không bao giờ tự phục hồi, nó yêu cầu khởi động lại).

Điều này cho thấy rằng nó phải liên quan đến mạng giữa máy chủ và cơ sở dữ liệu hoặc chính cơ sở dữ liệu. Chúng tôi đang tiếp tục nỗ lực chẩn đoán, nhưng bất kỳ lời khuyên nào cũng hữu ích.


Trước hết, đây là một câu hỏi khủng khiếp bằng văn bản. Công việc tuyệt vời trên các chi tiết! Thứ hai, bạn đang sử dụng proxy_ajp hoặc mod_jk để kết nối máy chủ Apache và Tomcat?
Ophidian

Tôi đang sử dụng proxy_ajp để kết nối cả hai.
Jordy Boom

Làm các bài kiểm tra căng thẳng bằng cách sử dụng bao vây, joedog.org/siege-home .
paalfe

Câu trả lời:


9

Hóa ra phiên bản này (lớp 12 - khá cũ) của trình điều khiển Oracle có nhiều lỗi khác nhau gây ra sự bế tắc (như đã thấy trong trạng thái TP-Processor2 được trích dẫn ở trên). Nó không hoạt động cho đến khi chúng tôi chuyển sang môi trường mới. Nâng cấp lên phiên bản mới nhất (ojdbc14) đã giải quyết vấn đề trên máy chủ chính.


Điều này dẫn tôi đến giải pháp chính xác của mình : Tôi đã có một khóa trong hàng DB ... và không bao giờ có bất kỳ Ngoại lệ nào trong Máy chủ ứng dụng
cljk

6

Từ mô tả, tôi đề nghị vấn đề có thể là do các truy vấn cơ sở dữ liệu mất quá nhiều thời gian. Nếu các truy vấn mất nhiều thời gian hơn, yêu cầu sẽ mất nhiều thời gian hơn và do đó bạn sẽ có nhiều truy vấn hơn cùng một lúc. Như bạn đang thấy, bạn đang chạy ra khỏi chủ đề tomcat. Khi bạn giải quyết vấn đề với cơ sở dữ liệu, bạn sẽ ổn thôi.

  • Nhận một dấu vết ngăn xếp, bằng cách sử dụng jstack hoặc sử dụng kill -3 $ process_id. Xem những gì chủ đề của bạn đang làm khi nó chết. Nếu tất cả họ đang chờ đợi trên cơ sở dữ liệu, đó là một con trỏ tốt cho lý thuyết của tôi. Tất cả họ có thể đang chờ đợi trên một số khóa.
  • Cài đặt LambdaProbe. Nó là vô giá để tìm hiểu những gì tomcat của bạn đang làm.
  • Nâng cấp tomcat của bạn. 5.5.8 là vô cùng cũ. Tôi nghĩ rằng họ bây giờ vào ngày 5.5.27.

David, tôi đã cập nhật câu hỏi (xem Cập nhật 1) với những phát hiện mới dựa trên đề xuất theo dõi ngăn xếp / ngăn xếp luồng của bạn.
Jordy Boom

Tôi muốn đề xuất rằng nhóm kết nối cơ sở dữ liệu của bạn quá nhỏ so với giá trị kết nối tối đa tomcat của bạn. Có vẻ như hầu hết các luồng đang chờ để có được kết nối cơ sở dữ liệu.
David Pashley

Lý do duy nhất có nhiều luồng là vì các luồng thường được sử dụng bị bỏ lại chờ đợi một luồng cố đọc từ ổ cắm. Số lượng kết nối DB được sử dụng bất cứ lúc nào trong khoảng từ 1 đến 3. Không bao giờ cần nhiều hơn thế.
Jordy Boom

5

Thêm ConnectionTimeout và keepAliveTimeout vào trình kết nối AJP của bạn được tìm thấy trong /etc/tomcat7/server.xml.

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
           connectionTimeout="10000" keepAliveTimeout="10000" />

Thông tin về trình kết nối AJP tại https://tomcat.apache.org/tomcat-7.0-doc/config/ajp.html

  • ConnectionTimeout = Số mili giây mà Trình kết nối này sẽ đợi, sau khi chấp nhận kết nối, cho dòng URI yêu cầu được trình bày. Giá trị mặc định cho các đầu nối giao thức AJP là -1 (tức là vô hạn).

  • keepAliveTimeout = Số mili giây Trình kết nối này sẽ đợi một yêu cầu AJP khác trước khi đóng kết nối. Giá trị mặc định là sử dụng giá trị đã được đặt cho thuộc tính ConnectionTimeout.

Nếu các giá trị ConnectionTimeout và keepAliveTimeout không được xác định, thì các kết nối AJP sẽ được duy trì ở mức vô hạn. Gây ra nhiều luồng, luồng tối đa mặc định là 200.

Tôi khuyên bạn nên cài đặt psi-thăm dò - một trình quản lý và giám sát nâng cao cho Apache Tomcat, rẽ nhánh từ Lambda thăm dò. https://code.google.com.vn/p/psi-probe/


4

Do cách thức hoạt động của AJP, các kết nối liên tục giữa apache (sử dụng mod_proxy_ajp hoặc mod_jk) chỉ có thể được đóng bởi khách hàng một cách an toàn . Trong trường hợp này, khách hàng là công nhân apache mở ra, và sau đó giữ một kết nối với tomcat suốt đời cho quy trình công nhân .

Bởi vì hành vi này, bạn không thể có nhiều công nhân apache hơn chủ đề công nhân tomcat. Làm như vậy sẽ khiến các nhân viên http bổ sung không thể kết nối với tomcat (vì hàng đợi chấp nhận đã đầy) và sẽ đánh dấu phần phụ trợ của bạn là DOWN!


1
Xin lỗi vì nhận xét sau nhiều năm, nhưng điều này không được đảm bảo bằng cách đặt cờ tối đa trong cấu hình ProxyPass thành số lượng MaxThread của bộ chứa servlet?
Horst Gutmann

2

Tôi đã có kết quả tốt hơn với mod_proxy thay vì mod_ajp về độ ổn định, vì vậy hãy thử giải pháp đó. Nó không xâm lấn - tốt nhất là nó sẽ giải quyết vấn đề và tệ nhất là nó sẽ loại trừ mod_ajp.

Mặt khác, âm thanh như Tomcats của bạn ngừng đáp ứng và tất cả các chuỗi yêu cầu được gắn kết. Yêu cầu nhóm phát triển của bạn xem xét những gì đang diễn ra - lấy một luồng xử lý và gửi nó cho họ sẽ hữu ích.


Tôi có ấn tượng rằng mod_proxy có một số vấn đề về khả năng mở rộng mặc dù dễ dàng kết nối hơn. Dường như nền tảng Apache khuyến nghị mod_jk ( wiki.apache.org/tomcat/FAQ/Connector#Q2 )
Ophidian

Nó không cung cấp sesssion dính, đúng. Nhưng khác hơn là tôi chưa bao giờ gặp vấn đề với nó.
Robert Munteanu

1

Điều đầu tiên tôi nghĩ đến khi tôi nghe rằng một máy chủ chạy được một lúc, đột nhiên chậm lại và sau đó bắt đầu gặp sự cố dịch vụ là nó hết RAM và làm hỏng trao đổi. Tôi không rõ liệu các lỗi AJP mà bạn nhìn thấy có thể là do thời gian chờ hay không, nhưng có vẻ như nó không hoàn toàn vô lý; Mặc dù vậy, không thấy bất kỳ cách rõ ràng nào nó sẽ kết nối với NIC. Trong mọi trường hợp, tôi khuyên bạn nên có một bức tranh về những gì đang xảy ra với việc sử dụng bộ nhớ của bạn khi những sự kiện này xảy ra.

Nếu bạn sắp hết RAM, bạn có thể cần phải tắt Apache MaxClientsvà tăng ListenBacklog.

Nhân tiện, cảm ơn vì đã làm cho câu hỏi của bạn được tổ chức tốt và đầy đủ.


Khi tôi quan sát 'đỉnh' trong khi điều này đang xảy ra, việc sử dụng bộ nhớ vẫn khá nhất quán. Ít nhất là không có gai. Chỉ có một khoảnh khắc ngắn của việc sử dụng CPU cao.
Jordy Boom

1

Tôi đã có lỗi đăng nhập tương tự trong môi trường Redhat với proxy_ajp và Tomcat. Đã giải quyết bằng cách cập nhật gói httpd:

yum update httpd

từ:

  • httpd-devel-2.2.3-43.el5_5.3.x86_64
  • httpd-2.2.3-43.el5_5.3.x86_64

đến:

  • httpd-2.2.3-45.el5_6.3.x86_64
  • httpd-devel-2.2.3-45.el5_6.3.x86_64

Sau đó khởi động lại apache, tiếp theo là khởi động lại Tomcat.

Điều đó đã sửa nó cho tôi!

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.