Tomcat 8 melempar - org.apache.catalina.webresources.Cache.getResource Tidak dapat menambahkan sumber daya

111

Saya baru saja memutakhirkan Tomcat dari versi 7.0.52 ke 8.0.14.

Saya mendapatkan ini untuk banyak file gambar statis:

org.apache.catalina.webresources.Cache.getResource Tidak dapat menambahkan sumber daya di [/base/1325/WA6144-150x112.jpg] ke cache karena tidak tersedia cukup ruang kosong setelah mengeluarkan entri cache yang kedaluwarsa - pertimbangkan untuk meningkatkan ukuran maksimum dari cache

Saya belum menentukan pengaturan sumber daya tertentu, dan saya tidak mendapatkan ini untuk 7.0.52.

Saya telah menemukan penyebutan ini terjadi saat memulai dalam laporan bug yang seharusnya diperbaiki. Bagi saya ini terjadi bukan pada saat startup tetapi terus-menerus ketika sumber daya diminta.

Ada lagi yang mengalami masalah ini?

Mencoba untuk setidaknya menonaktifkan cache, tetapi saya tidak dapat menemukan contoh bagaimana menentukan untuk tidak menggunakan cache. Atribut telah hilang dari konteks di Tomcat versi 8. Telah mencoba menambahkan sumber daya tetapi tidak bisa mendapatkan konfigurasi yang benar.

<Resource name="file" 
    cachingAllowed="false"
    className="org.apache.catalina.webresources.FileResourceSet"
/>  

Terima kasih.

iainmac999
sumber
Tidak ada balasan - Saya kira saya harus menjadi satu-satunya orang dengan masalah ini.
iainmac999
2
Solusinya ada di sini: serverfault.com/questions/644415/…
Dmitry
1
Mengenai atribut yang hilang dalam konteks Tomcat 8, berikut adalah kutipan dari panduan migrasi (penekanan saya): " Pemfaktoran ulang sumber daya juga mengakibatkan sejumlah atribut dihapus dari implementasi Konteks default (org.apache.catalina.core .StandardContext). Atribut berikut sekarang dapat dikonfigurasi melalui implementasi sumber daya yang digunakan oleh aplikasi web ". Info lebih lanjut di pedoman migrasi terkait .
informatik01
@ iainmac999 karena tidak pernah memilih jawaban yang benar setelah 2 tahun, kami setuju bahwa ini berfungsi dua arah?
davidjmcclelland

Jawaban:

161

Di $CATALINA_BASE/conf/context.xmltambahkan blok Anda di bawah ini sebelumnya</Context>

<Resources cachingAllowed="true" cacheMaxSize="100000" />

Untuk informasi lebih lanjut: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Hancurkan
sumber
11
Pembaca individu mungkin ingin menyesuaikan nilai cacheMaxSize menjadi kurang dari 100 MB.
Eric Spiegelberg
sejauh ini pesan kesalahan membanjiri log konsol saya. Sekarang sudah jelas. Terima kasih
Abubacker Siddik
152

Saya mengalami masalah yang sama saat meningkatkan dari Tomcat 7 ke 8: peringatan log membanjir terus menerus tentang cache.

1. Jawaban Singkat

Tambahkan ini di dalam Contextelemen xml Anda $CATALINA_BASE/conf/context.xml:

<!-- The default value is 10240 kbytes, even when not added to context.xml.
So increase it high enough, until the problem disappears, for example set it to 
a value 5 times as high: 51200. -->
<Resources cacheMaxSize="51200" />

Jadi defaultnya adalah 10240 (10 mbyte), jadi setel ukuran lebih tinggi dari ini. Kemudian setel untuk pengaturan optimal di mana peringatan menghilang. Perhatikan bahwa peringatan mungkin muncul kembali dalam situasi lalu lintas yang lebih tinggi.

1.1 Penyebab (penjelasan singkat)

Masalahnya disebabkan oleh Tomcat tidak dapat mencapai ukuran cache targetnya karena entri cache yang lebih kecil dari TTL entri tersebut. Jadi Tomcat tidak memiliki cukup entri cache sehingga dapat kedaluwarsa, karena terlalu segar, sehingga tidak dapat membebaskan cukup cache dan dengan demikian mengeluarkan peringatan.

Masalah tidak muncul di Tomcat 7 karena Tomcat 7 tidak mengeluarkan peringatan dalam situasi ini. (Menyebabkan Anda dan saya menggunakan pengaturan cache yang buruk tanpa diberi tahu.)

Masalahnya muncul saat menerima permintaan HTTP dalam jumlah relatif besar untuk sumber daya (biasanya statis) dalam jangka waktu yang relatif singkat dibandingkan dengan ukuran dan TTL cache. Jika cache mencapai maksimumnya (10mb secara default) dengan lebih dari 95% ukurannya dengan entri cache baru (segar berarti kurang dari 5 detik dalam cache), maka Anda akan mendapatkan pesan peringatan untuk setiap webResource yang dicoba Tomcat untuk memuat di cache.

1.2 Info opsional

Gunakan JMX jika Anda perlu menyetel cacheMaxSize pada server yang sedang berjalan tanpa perlu melakukan boot ulang.

Perbaikan tercepat adalah menonaktifkan cache sepenuhnya: <Resources cachingAllowed="false" /> :, tetapi itu kurang optimal, jadi tingkatkan cacheMaxSize seperti yang baru saja saya jelaskan.

2. Jawaban Panjang

2.1 Informasi latar belakang

Sebuah WebSource adalah file atau direktori dalam aplikasi web. Untuk alasan kinerja, Tomcat dapat menyimpan Sumber Web dalam cache. The maksimum cache sumber daya statis (semua sumber daya total) secara default 10240 kbyte (10 MByte). WebResource dimuat ke dalam cache saat webResource diminta (misalnya saat memuat gambar statis), ini kemudian disebut entri cache. Setiap entri cache memiliki TTL (time to live), yaitu waktu entri cache diizinkan untuk tetap berada di cache. Saat TTL kedaluwarsa, entri cache memenuhi syarat untuk dihapus dari cache. Nilai default dari cacheTTL adalah 5000 milidetik (5 detik).

Ada lebih banyak hal yang dapat diceritakan tentang penyimpanan ke cache, tetapi itu tidak relevan untuk masalah tersebut.

2.2 Penyebabnya

Kode berikut dari kelas Cache menunjukkan kebijakan caching secara rinci:

152   // Konten tidak akan di-cache tapi kita masih membutuhkan ukuran metadata 
153 long delta = cacheEntry. getSize ();
154 ukuran. addAndGet (delta);
156 jika (ukuran. Mendapatkan ()> MAXSIZE) {
157 sumber // Proses unordered untuk kecepatan. Trades cache
158 // efisiensi (entri yang lebih muda mungkin dikeluarkan sebelum yang lebih tua
159 // yang) untuk kecepatan karena ini berada di jalur kritis untuk
160 // meminta pemrosesan
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 newSize panjang = mengusir(
164 targetSize, resourceCache. Values (). Iterator ());
165 if (newSize> maxSize) {
166 // Tidak dapat membuat ruang yang cukup untuk sumber daya ini
167 // Hapus dari cache
168 removeCacheEntry (path);
169 batang kayu. warn (sm. getString ("cache.addFail", path));
170 }
171 }

Saat memuat webResource, kode menghitung ukuran cache yang baru. Jika ukuran yang dihitung lebih besar dari ukuran maksimum default, dari satu atau lebih entri yang disimpan dalam cache harus dihapus, jika tidak, ukuran baru akan melebihi maksimum. Jadi kode akan menghitung "targetSize", yang merupakan ukuran cache yang ingin disimpan (sebagai optimal), yang secara default 95% dari maksimum. Untuk mencapai targetSize ini, entri harus dihapus / dikeluarkan dari cache. Ini dilakukan dengan menggunakan kode berikut:

215   private  long evict ( long targetSize, Iterator < CachedResource > iter) { 
217 long now = System. currentTimeMillis ();
219 newSize = size panjang . get ();
221 sementara (newSize> targetSize && iter. HasNext ()) {
222 CachedResource resource = iter. berikutnya ();
224 // Jangan kadaluwarsa apapun yang telah diperiksa dalam TTL
225 if (resource. GetNextCheck ()> now) {
226 lanjutkan ;
227 }
229 // Hapus entri dari cache
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = size. get ();
233 }
235 mengembalikan newSize;
236 }

Jadi entri cache dihapus ketika TTL-nya kedaluwarsa dan targetSize belum tercapai.

Setelah upaya untuk membebaskan cache dengan menghapus entri cache, kode tersebut akan melakukan:

165   if (newSize> maxSize) { 
166 // Tidak dapat membuat ruang yang cukup untuk sumber daya ini
167 // Hapus dari cache
168 removeCacheEntry (path);
169 batang kayu. warn (sm. getString ("cache.addFail", path));
170 }

Jadi jika setelah mencoba membebaskan cache, ukurannya masih melebihi maksimum, maka akan muncul pesan peringatan tentang tidak dapat membebaskan:

cache.addFail=Unable to add the resource at [{0}] to the cache for web application [{1}] because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache

2.3 Masalahnya

Jadi seperti yang dikatakan pesan peringatan itu, masalahnya adalah

ruang kosong yang tersedia tidak mencukupi setelah mengeluarkan entri cache yang kadaluwarsa - pertimbangkan untuk meningkatkan ukuran maksimum cache

Jika aplikasi web Anda memuat banyak webResources yang tidak di-cache (sekitar maksimum cache, secara default 10mb) dalam waktu singkat (5 detik), maka Anda akan mendapatkan peringatan.

Bagian yang membingungkan adalah Tomcat 7 tidak menampilkan peringatan tersebut. Ini hanya disebabkan oleh kode Tomcat 7 ini:

1606   // Tambahkan entri baru ke cache 
1607 tersinkronisasi (cache) {
1608 // Periksa ukuran cache, dan hapus elemen jika terlalu besar
1609 jika ((cache. Lookup (name) == null ) && cache. Alokasikan (entry.size) ) {
1610 cache. memuat (entri);
1611 }
1612 }

dikombinasikan dengan:

231   sementara (toFree> 0) { 
232 if (mencoba == maxAllocateIterations) {
233 // Menyerah, tidak ada perubahan yang dibuat ke cache saat ini
234 return false ;
235 }

Jadi Tomcat 7 sama sekali tidak mengeluarkan peringatan sama sekali ketika tidak dapat membebaskan cache, sedangkan Tomcat 8 akan mengeluarkan peringatan.

Jadi, jika Anda menggunakan Tomcat 8 dengan konfigurasi cache default yang sama dengan Tomcat 7, dan Anda mendapat peringatan di Tomcat 8, maka pengaturan cache Tomcat 7 Anda (dan saya) berkinerja buruk tanpa peringatan.

2.4 Solusi

Ada beberapa solusi:

  1. Tingkatkan cache (disarankan)
  2. Turunkan TTL (tidak disarankan)
  3. Sembunyikan peringatan log cache (tidak disarankan)
  4. Nonaktifkan cache

2.4.1. Tingkatkan cache (disarankan)

Seperti dijelaskan di sini: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html

Dengan menambahkan <Resources cacheMaxSize="XXXXX" />dalam Contextelemen di $CATALINA_BASE/conf/context.xml, di mana "XXXXX" berarti peningkatan ukuran cache, ditentukan dalam kbytes. Standarnya adalah 10240 (10 mbyte), jadi tetapkan ukuran yang lebih tinggi dari ini.

Anda harus menyetel untuk pengaturan optimal. Perhatikan bahwa masalah dapat muncul kembali ketika Anda tiba-tiba mengalami peningkatan dalam permintaan lalu lintas / sumber daya.

Untuk menghindari restart server setiap kali Anda ingin mencoba ukuran cache yang baru, Anda dapat mengubahnya tanpa restart dengan menggunakan JMX.

Untuk mengaktifkan JMX , tambahkan ini ke $CATALINA_BASE/conf/server.xmldalam Serverelemen: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />dan unduh catalina-jmx-remote.jardari https://tomcat.apache.org/download-80.cgi dan masukkan $CATALINA_HOME/lib. Kemudian gunakan jConsole (dikirimkan secara default dengan Java JDK) untuk terhubung melalui JMX ke server dan melihat melalui pengaturan pengaturan untuk meningkatkan ukuran cache saat server sedang berjalan. Perubahan dalam pengaturan ini akan segera berpengaruh.

2.4.2. Turunkan TTL (tidak disarankan)

Turunkan cacheTtlnilainya dengan sesuatu yang lebih rendah dari 5000 milidetik dan sesuaikan untuk pengaturan optimal.

Sebagai contoh: <Resources cacheTtl="2000" />

Ini secara efektif turun untuk memiliki dan mengisi cache di ram tanpa menggunakannya.

2.4.3. Sembunyikan peringatan log cache (tidak disarankan)

Konfigurasi logging untuk menonaktifkan logger untuk org.apache.catalina.webresources.Cache.

Untuk info lebih lanjut tentang masuk ke Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html

2.4.4. Nonaktifkan cache

Anda dapat menonaktifkan cache dengan mengatur cachingAllowedke false. <Resources cachingAllowed="false" />

Meskipun saya ingat bahwa dalam versi beta dari Tomcat 8, saya menggunakan JMX untuk menonaktifkan cache. (Tidak yakin mengapa tepatnya, tetapi mungkin ada masalah dengan menonaktifkan cache melalui server.xml.)

Devabc
sumber
Tingkatkan cache? Saya ragu ini akan berhasil ... Saya melihat ini: private long maxSize = 10 * 1024 * 1024; di sumbernya. grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/…
HoaPhan
apakah Anda menemukan jawaban mengapa tomcat8 membanjiri peringatan cache
PHP Avenger
@HoaPhan 10 * 1024 * 1024 adalah maksimum 10mb untuk semua cache secara total. Bergantung pada lalu lintas aplikasi web, ini dapat dicapai dalam beberapa detik. Meningkatkannya cukup jauh, akan berhasil.
Devabc
@PHPAvenger Tomcat 7 tidak memberikan peringatan sama sekali dalam situasi ini, sedangkan Tomcat 8 melakukannya, sehingga dapat dilihat sebagai fitur peringatan. Masalahnya adalah ia memperingatkan tidak hanya sekali, tetapi juga pada setiap permintaan sumber daya ke-cache. Ini akan menjadi perbaikan untuk hanya memperingatkan setelah jangka waktu tertentu atau target cache tercapai.
Devabc
@Devabc jawaban yang sempurna! Sangat klasik!
gaurav
9

Anda memiliki lebih banyak sumber daya statis yang memiliki ruang untuk cache. Anda dapat melakukan salah satu dari berikut ini:

  • Tingkatkan ukuran cache
  • Kurangi TTL untuk cache
  • Nonaktifkan penyimpanan ke cache

Untuk detail selengkapnya, lihat dokumentasi untuk opsi konfigurasi ini.

Mark Thomas
sumber
1
Terima kasih atas komentarnya. Saya mengerti arti dari pengecualian, dan tentu saja saya membaca dokumentasi yang Anda tautkan, namun saya tidak mengerti mengapa ini akan berubah dari 7 menjadi 8 tanpa perubahan konfigurasi. Itulah, mengapa penangan Sumber Daya Sistem File default berbeda dalam 8 hingga 7, tanpa referensi ke perubahan apa pun, dan mencurigakan bahwa bug start up dilaporkan dan seharusnya diperbaiki.
iainmac999
1
Mungkin jika Anda telah membaca panduan migrasi - khususnya tomcat.apache.org/migration-8.html#Web_application_resources - semuanya akan menjadi lebih jelas.
Mark Thomas
Akan membantu jika dokumentasi melakukan sedikit lebih banyak untuk a) menjelaskan sumber daya apa yang masuk ke dalam cache ini dan mengapa (banyak kesalahpahaman berlimpah tentang itu!) Dan b) apa dampak pengaturan yang berbeda dapat memiliki (misalnya hanya membuat secara membabi buta membuat pengaturan cache setiap aplikasi web cukup besar dapat memakan banyak memori) dan cara menyetelnya dengan benar. Ini juga akan membantu jika ada perbedaan dalam kode dan konfigurasi antara caching sumber daya statis yang digunakan oleh aplikasi itu sendiri vs file statis yang diminta oleh agen pengguna dan hanya dikirimkan oleh aplikasi.
relawan
4

Ini bukan solusi dalam artian tidak menyelesaikan kondisi yang menyebabkan pesan muncul di log, tetapi pesan tersebut dapat disembunyikan dengan menambahkan yang berikut ini ke conf/logging.properties:

org.apache.catalina.webresources.Cache.level = SEVERE

Ini memfilter log "Tidak dapat menambahkan sumber daya", yang berada di level PERINGATAN.

Dalam pandangan saya a WARNINGbelum tentu merupakan kesalahan yang perlu ditangani, melainkan dapat diabaikan jika diinginkan.

Geoffrey Booth
sumber
8
Ha ha. ini tidak menyelesaikan masalah. Itu tidak menunjukkannya. WTF!
T3rm1
Ini memecahkan masalah penebangan yang berlebihan, yang bisa menjadi masalah yang signifikan dengan sendirinya. Ini kembali ke perilaku versi kucing jantan sebelumnya, di mana hal-hal bekerja cukup baik untuk banyak orang, jadi dalam arti itu "memecahkan" masalah. Itu tidak mengatasi masalah sebenarnya menyetel cache tomcat, yang jawaban oleh devabc mencakup dengan sangat baik.
Pekerja sukarela