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 Context
elemen 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:
- Tingkatkan cache (disarankan)
- Turunkan TTL (tidak disarankan)
- Sembunyikan peringatan log cache (tidak disarankan)
- 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 Context
elemen 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.xml
dalam Server
elemen:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />
dan unduh catalina-jmx-remote.jar
dari 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 cacheTtl
nilainya 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 cachingAllowed
ke 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.)