One of my Spring-Boot projects was battling with overloaded CPU and unresponsive / slow server response at times when there is more traffic. I have explored and implemented caching but my problem was with excessive connections coming in and server itself becoming slow. I could have setup multiple instances and do some kind of auto-scaling but given limited budget and hardware I wanted to put in some hard limits on my Spring-Boot app as to how much traffic it can take in and when it can give up gracefully (there is no shame in rejecting traffic with HTTP status 503 if the server infrastructure is overloaded).
I found a blog post entry from Netflix on how to tune Apache Tomcat and another article on how to tune Rest Controller code itself to implement a rudimentary Rate Limiter. I was glad to find the RateLimiter implementation in Goggle Guava library which I ultimately ended up using (for now). However I think the annotation driven RateLimiter is also a very good solution which is certainly very powerful and I will take it out for a spin sometime in near future.
The basic lesson learnt from this exercise:
– Tweak Tomcat and keep a watch on the acceptCount parameter which technically puts in a limit of how much traffic reaches your Rest controller.
– Use a RateLimiter on your hot APIs (which have higher latency) and don’t let your application get abused beyond a limit.
– Scale horizontally if the limits set above result in lot of traffic getting rejected.
I had a old project which was running on JDK 8 and Spring Boot 1.5.x which I just upgraded to JDK 11 and Spring Boot 2.2.5. I faced some hiccups in the process but it is finally done and the application is up and running. I will be documenting some of the issues faced in this process.
All instances of findOne() had to be replaced with findByID() which returns Optional<Entity> reference. I ended up removing lots of null checks by leveraging the Optional features of “orElse”, “orThrow” and “ifPresent” methods provided by Optional interface. It definitely is a better way to handle null.
JAXB runtime error
After migration the application booted up fine but on doing some specific operation I observed this error on console
It seems this class has been moved out of the core library in JDK. This error kind of stumped me as some posts on internet suggested adding the following entry in pom.xml
However this didn’t help and I ended up using the following library to finally get rid of this issue:
Apache POI / Tika Library
This is another runtime issue faced during this application operation.
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.apache.poi.openxml4j.util.ZipSecureFile$1 (file:/Users/562320/.m2/repository/org/apache/tika/tika-app/1.15/tika-app-1.15.jar) to field java.io.FilterInputStream.in
WARNING: Please consider reporting this to the maintainers of org.apache.poi.openxml4j.util.ZipSecureFile$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Jun 29, 2020 3:14:17 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path  threw exception [Request processing failed; nested exception is org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException: Fail to save: an error occurs while saving the package : class org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream cannot be cast to class java.util.zip.ZipFile$ZipFileInputStream (org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream is in unnamed module of loader 'app'; java.util.zip.ZipFile$ZipFileInputStream is in module java.base of loader 'bootstrap')] with root cause
java.lang.ClassCastException: class org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream cannot be cast to class java.util.zip.ZipFile$ZipFileInputStream (org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream is in unnamed module of loader 'app'; java.util.zip.ZipFile$ZipFileInputStream is in module java.base of loader 'bootstrap')
This issue got resolved after upgrading the Apache Tika, Apache POI to latest version. I also had to upgrade the apache-commons-lang package to apache-commons-lang3 package.