pengembangan-web-mp-pd.com

Apache + Tomcat mengalami masalah dalam berkomunikasi. Pesan kesalahan tidak jelas. Membawa situs web yang dihosting di bawah Tomcat

Setup:
Fedora 8
Apache 2.2.8
Tomcat 5.5.8
Apache meneruskan permintaan menggunakan AJP.

Masalah:
Setelah periode waktu tertentu (tidak ada konstanta sama sekali, bisa antara satu atau dua jam, atau satu hari atau lebih) Tomcat akan turun. Entah itu berhenti merespons, atau memasang generik 'Layanan Sementara Tidak Tersedia'.

Diagnosis:
Ada dua server dengan pengaturan yang sama. Satu rumah situs web lalu lintas yang lebih tinggi (beberapa permintaan per detik), yang lain situs lalu lintas rendah (beberapa permintaan setiap beberapa menit). Kedua situs web ini adalah basis kode yang sama sekali berbeda, tetapi keduanya menunjukkan masalah yang serupa.

Di server pertama, ketika masalah terjadi, semua utas perlahan mulai terangkat hingga mencapai batas (MaxThreads 200). Pada saat itu server tidak lagi merespons (dan muncul dengan halaman layanan tidak tersedia setelah jangka waktu yang lama).

Pada server kedua, ketika masalah terjadi permintaan membutuhkan waktu yang lama dan ketika mereka selesai semua yang Anda lihat adalah halaman layanan tidak tersedia.

Selain menyebutkan masalah MaxThreads, log Tomcat tidak menunjukkan masalah khusus apa pun yang dapat menyebabkan hal ini.

Namun, dalam log Apache kita melihat pesan acak merujuk ke AJP. Berikut contoh pesan acak yang kami lihat (tanpa urutan tertentu):

[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)

Hal aneh lainnya yang kami perhatikan pada server traffic yang lebih tinggi adalah bahwa tepat sebelum masalah mulai terjadi, permintaan basis data lebih lama dari sebelumnya (2000-5000 ms dibandingkan biasanya 5-50ms). Ini hanya berlangsung selama 2-4 detik sebelum pesan MaxThreads muncul. Saya berasumsi ini adalah hasil dari server yang tiba-tiba berurusan dengan terlalu banyak data/traffic/utas.

Informasi Latar Belakang:
Kedua server ini telah berjalan tanpa masalah selama beberapa waktu. Sistem sebenarnya mengatur masing-masing menggunakan dua NIC selama waktu itu. Mereka memisahkan lalu lintas internal dan eksternal. Setelah peningkatan jaringan, kami memindahkan server-server ini ke NIC tunggal (ini direkomendasikan kepada kami karena alasan keamanan/kesederhanaan). Setelah perubahan itu, server mulai mengalami masalah ini.

Resolusi:
Solusi yang jelas adalah kembali ke pengaturan dua NIC. Masalah dengan itu adalah bahwa hal itu akan menyebabkan beberapa komplikasi dengan pengaturan jaringan, dan sepertinya mengabaikan masalahnya. Kami lebih suka mencoba dan menjalankannya pada satu pengaturan NIC.

Menelusuri berbagai pesan kesalahan tidak memberikan apa pun yang berguna (baik solusi lama atau tidak terkait dengan masalah kami).

Kami telah mencoba menyesuaikan berbagai batas waktu tetapi itu hanya membuat server berjalan sedikit lebih lama sebelum mati.

Kami tidak yakin ke mana harus mencari untuk mendiagnosis masalah lebih lanjut. Kami masih memahami apa masalahnya:

1) Pengaturan dengan AJP dan Tomcat salah, atau ketinggalan jaman (mis. Bug yang dikenal?)
2) Pengaturan jaringan (dua NIC versus satu NIC) menyebabkan masalah kebingungan atau throughput.
3) Situs web itu sendiri (tidak ada kode umum, tidak ada platform yang digunakan, hanya dasar Java kode dengan servlets dan JSP)

Pembaruan 1:
Mengikuti saran David Pashley yang membantu, saya melakukan stack trace/thread dump selama masalah ini. Apa yang saya temukan adalah bahwa semua 200 utas berada di salah satu dari keadaan berikut:

"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]

Anehnya, hanya satu utas dari semua 200 utas yang ada di negara ini:

"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]

Mungkin saja driver Oracle di utas ini memaksa semua utas lainnya menunggu sampai selesai. Untuk beberapa alasan itu harus macet dalam keadaan membaca ini (server tidak pernah pulih sendiri, itu membutuhkan restart).

Ini menunjukkan bahwa itu harus terkait dengan jaringan antara server dan database, atau database itu sendiri. Kami sedang melanjutkan upaya diagnosis, tetapi kiat apa pun akan membantu.

22
Jordy Boom

Ternyata versi ini (kelas 12 - cukup tua) dari driver Oracle memiliki berbagai bug di dalamnya yang menyebabkan jalan buntu (seperti yang terlihat di negara TP-Processor2 yang dikutip di atas). Itu tidak menjadi aktif sampai kami beralih ke lingkungan baru. Memutakhirkan ke versi terbaru (ojdbc14) telah menyelesaikan masalah pada server utama.

9
Jordy Boom

Dari uraian, saya menyarankan masalah mungkin karena permintaan database terlalu lama. Jika kueri membutuhkan waktu lebih lama, permintaan akan lebih lama dan karena itu Anda akan menjalankan lebih banyak permintaan sekaligus. Seperti yang Anda lihat, Anda kehabisan utas Tomcat. Ketika Anda memecahkan masalah dengan database Anda harus baik-baik saja.

  • Dapatkan jejak stack, baik menggunakan jstack atau menggunakan kill -3 $ process_id. Lihat apa yang sedang dilakukan utas Anda saat mati. Jika mereka semua menunggu di database, itu adalah petunjuk yang bagus untuk teori saya. Mereka semua mungkin sedang menunggu kunci.
  • Instal LambdaProbe. Sangat berharga untuk mengetahui apa yang dilakukan Tomcat Anda.
  • Tingkatkan Tomcat Anda. 5.5.8 sudah sangat tua. Saya pikir mereka sekarang di 5.5.27.
6
David Pashley

Tambahkan connectionTimeout dan keepAliveTimeout ke konektor AJP Anda yang ditemukan di /etc/Tomcat7/server.xml.

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

Info tentang konektor AJP di https://Tomcat.Apache.org/Tomcat-7.0-doc/config/ajp.html

  • connectionTimeout = Jumlah milidetik Konektor ini akan menunggu, setelah menerima koneksi, agar garis URI yang diajukan disajikan. Nilai default untuk konektor protokol AJP adalah -1 (mis. Tak terbatas).

  • keepAliveTimeout = Jumlah milidetik Konektor ini akan menunggu permintaan AJP lain sebelum menutup koneksi. Nilai default adalah menggunakan nilai yang telah ditetapkan untuk atribut connectionTimeout.

Jika nilai connectionTimeout dan keepAliveTimeout tidak ditentukan, maka koneksi AJP akan tetap hidup selama tak terbatas. Menyebabkan banyak utas, utas maksimum bawaan adalah 200.

Saya sarankan menginstal psi-probe - manajer dan monitor canggih untuk Tomcat Apache, bercabang dari Lambda Probe. https://code.google.com/p/psi-probe/

5
paalfe

Karena cara kerja AJP, koneksi persisten antara Apache (menggunakan mod_proxy_ajp atau mod_jk) hanya dapat ditutup dengan aman oleh klien. Dalam hal ini, klien adalah pekerja Apache yang membuka, dan kemudian memegang koneksi ke Tomcat untuk kehidupan untuk proses pekerja.

Karena perilaku ini, Anda tidak dapat memiliki lebih banyak pekerja Apache daripada utas pekerja Tomcat. Melakukan hal itu akan menyebabkan pekerja http tambahan gagal terhubung ke Tomcat (karena antrian terima penuh) dan akan menandai backend Anda sebagai BAWAH!

4
Dave Cheney

Saya memiliki hasil yang lebih baik dengan mod_proxy daripada mod_ajp dalam hal stabilitas, jadi cobalah solusi itu. Ini non-invasif - yang terbaik itu akan menyelesaikan masalah dan paling buruk itu akan mengesampingkan mod_ajp.

Selain itu, sepertinya Tomcats Anda berhenti merespons dan semua utas permintaan diikat. Mintalah tim dev Anda melihat apa yang sedang terjadi - mengambil thread dump dan mengirimkannya kepada mereka akan berguna.

2
Robert Munteanu

Hal pertama yang saya pikirkan ketika saya mendengar bahwa server berjalan untuk sementara waktu, tiba-tiba melambat dan kemudian mulai mengalami kegagalan layanan adalah kehabisan RAM dan meronta-ronta swap. Saya tidak jelas apakah kegagalan AJP yang Anda lihat dapat menjadi konsekuensi dari timeout, tetapi tampaknya tidak sepenuhnya masuk akal; tidak melihat cara yang jelas itu akan terhubung ke NIC. Namun, dalam hal apa pun, saya sarankan Anda mendapatkan gambar apa yang terjadi dengan penggunaan memori Anda ketika peristiwa ini terjadi.

Jika Anda kehabisan RAM, Anda mungkin perlu mematikan Apache MaxClients Anda dan meningkatkan ListenBacklog Anda.

Ngomong-ngomong, terima kasih telah membuat pertanyaan Anda begitu terorganisir dan lengkap.

1
chaos

Saya mengalami kesalahan log yang serupa di lingkungan Redhat dengan proxy_ajp dan Tomcat. Diselesaikan dengan memperbarui paket httpd:

yum update httpd

dari:

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

untuk:

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

Kemudian restart Apache, diikuti dengan restart Tomcat.

Itu memperbaikinya bagi saya!

1
Bass