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

22

Pengaturan:
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 halaman layanan yang 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 yang merujuk pada 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 lain 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 masalah. 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 kode Java dasar 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 untuk menunggu sampai selesai. Untuk beberapa alasan ia 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.

Jordy Boom
sumber
Pertama, ini adalah pertanyaan yang ditulis dengan luar biasa. Pekerjaan yang fantastis pada detail! Kedua, apakah Anda menggunakan proxy_ajp atau mod_jk untuk menghubungkan server Apache dan Tomcat?
Ophidian
Saya menggunakan proxy_ajp untuk menghubungkan keduanya.
Jordy Boom
Lakukan tes stres menggunakan pengepungan, joedog.org/siege-home .
paalfe

Jawaban:

9

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.

Jordy Boom
sumber
Ini menuntun saya ke solusi saya yang benar: Saya memiliki kunci dalam baris-DB ... dan tidak pernah mendapatkan Pengecualian di App-Server
cljk
6

Dari uraian, saya sarankan masalahnya mungkin karena permintaan database terlalu lama. Jika permintaan lebih lama, permintaan akan lebih lama dan karena itu Anda akan menjalankan lebih banyak permintaan sekaligus. Seperti yang Anda lihat, Anda kehabisan utas kucing jantan. 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 menunggu di kunci.
  • Instal LambdaProbe. Sangat berharga untuk mengetahui apa yang dilakukan kucing jantan Anda.
  • Tingkatkan kucing jantan Anda. 5.5.8 sudah sangat tua. Saya pikir mereka sekarang di 5.5.27.
David Pashley
sumber
David, saya telah memperbarui pertanyaan (lihat Pembaruan 1) dengan temuan baru berdasarkan saran penelusuran dump / stack thread Anda.
Jordy Boom
Saya menyarankan bahwa kumpulan koneksi database Anda terlalu kecil dibandingkan dengan nilai koneksi tomcat max Anda. Tampaknya sebagian besar utas sedang menunggu untuk mendapatkan koneksi basis data.
David Pashley
Satu-satunya alasan ada banyak utas adalah karena utas yang biasanya digunakan dibiarkan menunggu satu utas yang mencoba membaca dari soket. Jumlah koneksi DB yang digunakan setiap saat berkisar antara 1 dan 3. Tidak pernah ada kebutuhan lebih dari itu.
Jordy Boom
5

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 permintaan ditampilkan. Nilai default untuk konektor protokol AJP adalah -1 (yaitu tidak 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 merekomendasikan menginstal psi-probe - manajer canggih dan monitor untuk Tomcat Apache, bercabang dari Lambda Probe. https://code.google.com/p/psi-probe/

paalfe
sumber
4

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 kucing jantan untuk kehidupan selama proses pekerja .

Karena perilaku ini, Anda tidak dapat memiliki lebih banyak pekerja apache daripada utas pekerja kucing jantan. Melakukannya akan menyebabkan pekerja http tambahan gagal terhubung ke kucing jantan (karena antrian terima penuh) dan akan menandai backend Anda sebagai BAWAH!

Dave Cheney
sumber
1
Maaf atas komentar setelah bertahun-tahun, tetapi tidak bisakah ini dijamin dengan mengatur flag-max dalam konfigurasi ProxyPass ke jumlah MaxThreads dari wadah servlet?
Horst Gutmann
2

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

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

Robert Munteanu
sumber
Saya mendapat kesan bahwa mod_proxy memiliki beberapa masalah skalabilitas meskipun lebih mudah untuk dihubungkan. Tampaknya bahwa yayasan Apache merekomendasikan mod_jk ( wiki.apache.org/tomcat/FAQ/Connectors#Q2 )
Ophidian
Itu tidak memberikan sesssion lengket, benar. Tapi selain itu saya tidak pernah punya masalah dengan itu.
Robert Munteanu
1

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 tidak masuk akal; tidak melihat cara yang jelas itu akan terhubung ke NIC. Bagaimanapun, saya sarankan Anda mendapatkan gambaran tentang apa yang terjadi dengan penggunaan memori Anda ketika peristiwa ini terjadi.

Jika Anda kehabisan RAM, Anda mungkin perlu mematikan Apache MaxClientsdan menambah ListenBacklog.

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

kekacauan
sumber
Ketika saya mengamati 'top' saat ini terjadi, penggunaan memori tetap cukup konsisten. Setidaknya tidak ada paku. Hanya ada waktu singkat penggunaan CPU yang tinggi.
Jordy Boom
1

Saya memiliki 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 oleh restart Tomcat.

Itu memperbaikinya bagi saya!

Bas
sumber