Tôi đã gặp vấn đề tương tự khi nâng cấp từ Tomcat 7 lên 8: một loạt các cảnh báo nhật ký liên tục về bộ nhớ cache.
1. Câu trả lời ngắn
Thêm điều này trong Context
phần tử xml của $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" />
Vì vậy, mặc định là 10240
(10 mbyte), vì vậy hãy đặt kích thước cao hơn mức này. Điều chỉnh để có cài đặt tối ưu, nơi các cảnh báo biến mất. Lưu ý rằng các cảnh báo có thể quay lại trong các tình huống giao thông cao hơn.
1.1 Nguyên nhân (giải thích ngắn gọn)
Vấn đề là do Tomcat không thể đạt được kích thước bộ nhớ cache mục tiêu của nó do các mục nhập bộ nhớ cache nhỏ hơn TTL của các mục nhập đó. Vì vậy, Tomcat không có đủ các mục nhập bộ nhớ cache mà nó có thể hết hạn, vì chúng quá mới, vì vậy nó không thể giải phóng đủ bộ nhớ cache và do đó xuất ra các cảnh báo.
Sự cố không xuất hiện trong Tomcat 7 vì Tomcat 7 đơn giản là không xuất cảnh báo trong tình huống này. (Khiến bạn và tôi sử dụng cài đặt bộ nhớ đệm kém mà không được thông báo.)
Sự cố xuất hiện khi nhận được một lượng lớn tương đối các yêu cầu HTTP cho tài nguyên (thường là tĩnh) trong một khoảng thời gian ngắn tương đối so với kích thước và TTL của bộ nhớ cache. Nếu bộ nhớ cache đạt đến mức tối đa (10mb theo mặc định) với hơn 95% kích thước của nó với các mục nhập bộ nhớ cache mới (mới có nghĩa là ít hơn 5 giây trong bộ nhớ cache), bạn sẽ nhận được thông báo cảnh báo cho mỗi webResource mà Tomcat thử để tải vào bộ nhớ đệm.
1.2 Thông tin tùy chọn
Sử dụng JMX nếu bạn cần điều chỉnh cacheMaxSize trên một máy chủ đang chạy mà không cần khởi động lại nó.
Cách khắc phục nhanh nhất là vô hiệu hóa hoàn toàn bộ nhớ cache <Resources cachingAllowed="false" />
:, nhưng điều đó là chưa tối ưu, vì vậy hãy tăng cacheMaxSize như tôi vừa mô tả.
2. Câu trả lời dài
2.1 Thông tin cơ bản
Một WebSource là một tập tin hoặc thư mục trong một ứng dụng web. Vì lý do hiệu suất, Tomcat có thể lưu WebSources vào bộ nhớ cache. Theo mặc định, tối đa của bộ đệm tài nguyên tĩnh (tổng số tài nguyên) là 10240 kbyte (10 mbyte). Một webResource được tải vào bộ nhớ cache khi webResource được yêu cầu (ví dụ: khi tải một hình ảnh tĩnh), khi đó nó được gọi là một mục nhập bộ nhớ cache. Mọi mục nhập bộ nhớ cache đều có TTL (thời gian tồn tại), là thời gian mục nhập bộ nhớ cache được phép lưu lại trong bộ nhớ cache. Khi TTL hết hạn, mục nhập bộ nhớ cache đủ điều kiện để được xoá khỏi bộ nhớ cache. Giá trị mặc định của cacheTTL là 5000 mili giây (5 giây).
Có nhiều điều để nói về bộ nhớ đệm, nhưng điều đó không liên quan đến vấn đề.
2.2 Nguyên nhân
Đoạn mã sau từ lớp Cache hiển thị chi tiết chính sách bộ nhớ đệm:
152 // Nội dung sẽ không được lưu vào bộ nhớ đệm nhưng chúng ta vẫn cần kích thước siêu dữ liệu
153 long delta = cacheEntry. getSize ();
154 kích thước. addAndGet (delta);
156 nếu (kích thước. Lấy ()> MAXSIZE) {
157 nguồn // Process có thứ tự cho tốc độ. Bộ nhớ đệm giao dịch
158 // hiệu quả (các mục nhập trẻ hơn có thể bị loại bỏ trước các mục nhập cũ hơn
159 //) về tốc độ vì đây là đường dẫn quan trọng để xử lý yêu cầu
160 //
161 long targetSize =
162 maxSize * (100 - TARGET_FREE_PERCENT_GET) / 100;
163 dài newSize = đuổi (
164 . TargetSize, resourceCache giá trị (). Iterator ());
165 if (newSize> maxSize) {
166 // Không thể tạo đủ dung lượng cho tài nguyên này.
167 // Xóa nó khỏi bộ nhớ cache
168 removeCacheEntry (path);
169 nhật ký. cảnh báo (sm. getString ("cache.addFail", đường dẫn));
170 }
171 }
Khi tải một webResource, mã sẽ tính toán kích thước mới của bộ nhớ cache. Nếu kích thước được tính toán lớn hơn kích thước tối đa mặc định, thì phải xóa hơn một hoặc nhiều mục nhập được lưu trong bộ nhớ cache, nếu không kích thước mới sẽ vượt quá kích thước tối đa. Vì vậy, mã sẽ tính toán một "targetSize", là kích thước mà bộ nhớ cache muốn duy trì (như một mức tối ưu), theo mặc định là 95% của mức tối đa. Để đạt được targetSize này, các mục nhập phải được xóa / loại bỏ khỏi bộ đệm. Điều này được thực hiện bằng cách sử dụng mã sau:
215 private long evict ( long targetSize, Iterator < CachedResource > iter) {
217 long now = System. currentTimeMillis ();
219 dài newSize = kích thước. lấy ();
221 while (newSize> targetSize && iter. HasNext ()) {
222 CachedResource resource = iter. tiếp theo ();
224 // Không hết hạn bất kỳ thứ gì đã được kiểm tra trong TTL
225 if (resource. GetNextCheck ()> now) {
226 tiếp tục ;
227 }
229 // Xóa mục nhập khỏi bộ nhớ đệm
230 removeCacheEntry (resource. GetWebappPath ());
232 newSize = kích thước. lấy ();
233 }
235 trả về newSize;
236 }
Vì vậy, mục nhập trong bộ nhớ cache sẽ bị xóa khi TTL của nó hết hạn và targetSize vẫn chưa đạt được.
Sau khi cố gắng giải phóng bộ nhớ cache bằng cách loại bỏ các mục nhập bộ nhớ cache, mã sẽ thực hiện:
165 if (newSize> maxSize) {
166 // Không thể tạo đủ dung lượng cho tài nguyên này.
167 // Xóa nó khỏi bộ nhớ cache
168 removeCacheEntry (path);
169 nhật ký. cảnh báo (sm. getString ("cache.addFail", đường dẫn));
170 }
Vì vậy, nếu sau khi cố gắng giải phóng bộ nhớ cache, kích thước vẫn vượt quá mức tối đa, nó sẽ hiển thị thông báo cảnh báo về việc không thể giải phóng:
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 Vấn đề
Vì vậy, như thông báo cảnh báo cho biết, vấn đề là
không đủ dung lượng trống sau khi loại bỏ các mục nhập bộ nhớ cache đã hết hạn - hãy xem xét tăng kích thước tối đa của bộ nhớ cache
Nếu ứng dụng web của bạn tải nhiều webResources chưa được lưu trữ (khoảng tối đa bộ nhớ cache, theo mặc định là 10mb) trong một thời gian ngắn (5 giây), thì bạn sẽ nhận được cảnh báo.
Phần khó hiểu là Tomcat 7 không hiển thị cảnh báo. Điều này chỉ đơn giản là do mã Tomcat 7 này gây ra:
1606 // Thêm mục mới vào bộ nhớ cache
1607 đồng bộ (cache) {
1608 kích thước bộ nhớ cache // Kiểm tra, và các yếu tố loại bỏ nếu quá lớn
1609 nếu ((cache. Lookup (tên) == rỗng ) && cache. Phân bổ (entry.size) ) {
1610 bộ nhớ cache. tải (nhập);
1611 }
1612 }
kết hợp với:
231 while (toFree> 0) {
232 if (try == maxAllocateIterations) {
233 // Bỏ cuộc, không có thay đổi nào được thực hiện đối với bộ đệm hiện tại
234 return false ;
235 }
Vì vậy, Tomcat 7 chỉ đơn giản là không xuất ra bất kỳ cảnh báo nào khi nó không thể giải phóng bộ nhớ cache, trong khi Tomcat 8 sẽ xuất ra cảnh báo.
Vì vậy, nếu bạn đang sử dụng Tomcat 8 có cùng cấu hình bộ nhớ đệm mặc định như Tomcat 7 và bạn nhận được cảnh báo trong Tomcat 8, thì cài đặt bộ nhớ đệm của bạn (và của tôi) Tomcat 7 hoạt động kém mà không có cảnh báo.
2.4 Giải pháp
Có nhiều giải pháp:
- Tăng bộ nhớ đệm (khuyến nghị)
- Giảm TTL (không được khuyến nghị)
- Chặn cảnh báo nhật ký bộ nhớ cache (không được khuyến nghị)
- Vô hiệu hóa bộ nhớ cache
2.4.1. Tăng bộ nhớ đệm (khuyến nghị)
Như được mô tả ở đây: http://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
Bằng cách thêm vào <Resources cacheMaxSize="XXXXX" />
bên trong Context
phần tử $CATALINA_BASE/conf/context.xml
, trong đó "XXXXX" là viết tắt của kích thước bộ nhớ cache tăng lên, được chỉ định bằng kbyte. Giá trị mặc định là 10240 (10 mbyte), vì vậy hãy đặt kích thước cao hơn kích thước này.
Bạn sẽ phải điều chỉnh các cài đặt tối ưu. Lưu ý rằng sự cố có thể quay trở lại khi bạn đột nhiên có sự gia tăng về lưu lượng / yêu cầu tài nguyên.
Để tránh phải khởi động lại máy chủ mỗi khi bạn muốn thử kích thước bộ nhớ cache mới, bạn có thể thay đổi nó mà không cần khởi động lại bằng cách sử dụng JMX.
Để kích hoạt JMX , hãy thêm nó vào $CATALINA_BASE/conf/server.xml
bên trong Server
phần tử:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="6767" rmiServerPortPlatform="6768" />
và tải xuống catalina-jmx-remote.jar
từ https://tomcat.apache.org/download-80.cgi và đưa nó vào $CATALINA_HOME/lib
. Sau đó, sử dụng jConsole (được vận chuyển theo mặc định với Java JDK) để kết nối qua JMX với máy chủ và xem qua cài đặt cho các cài đặt để tăng kích thước bộ nhớ cache trong khi máy chủ đang chạy. Những thay đổi trong các cài đặt này sẽ ảnh hưởng ngay lập tức.
2.4.2. Giảm TTL (không được khuyến nghị)
Giảm cacheTtl
giá trị thấp hơn 5000 mili giây và điều chỉnh để có cài đặt tối ưu.
Ví dụ: <Resources cacheTtl="2000" />
Điều này có hiệu quả phụ thuộc vào việc có và lấp đầy một bộ nhớ cache trong ram mà không sử dụng nó.
2.4.3. Chặn cảnh báo nhật ký bộ nhớ cache (không được khuyến nghị)
Định cấu hình ghi nhật ký để tắt trình ghi nhật ký cho org.apache.catalina.webresources.Cache
.
Để biết thêm thông tin về cách đăng nhập Tomcat: http://tomcat.apache.org/tomcat-8.0-doc/logging.html
2.4.4. Vô hiệu hóa bộ nhớ cache
Bạn có thể tắt bộ nhớ cache bằng cách đặt cachingAllowed
thành false
.
<Resources cachingAllowed="false" />
Mặc dù tôi có thể nhớ rằng trong phiên bản beta của Tomcat 8, tôi đã sử dụng JMX để tắt bộ nhớ cache. (Không chắc chắn lý do chính xác, nhưng có thể có sự cố khi tắt bộ nhớ cache qua server.xml.)