Improve memory usage by serializing the response object directly#159
Improve memory usage by serializing the response object directly#159tangiel merged 2 commits intocloudendpoints:masterfrom
Conversation
- Prevents an intermediate String object from being created - Content-Length header is not set calculated by default anymore - Content-Length can be reenabled with addContentLength=true init param
Codecov Report
@@ Coverage Diff @@
## master #159 +/- ##
============================================
+ Coverage 80% 80.05% +0.04%
- Complexity 1680 1681 +1
============================================
Files 156 156
Lines 5597 5601 +4
Branches 731 733 +2
============================================
+ Hits 4478 4484 +6
+ Misses 839 837 -2
Partials 280 280
Continue to review full report at Codecov.
|
|
Hmm, do you happen to be using API management? I have a hunch that it was programmed this way specifically because of API management. We may need to make adjustments to accommodate this change. |
|
I don't use it on production projects, but I performed tests both on Flex with ESP and Standard with ServiceManagementConfigFilter + GoogleAppEngineControlFilter, and everything seems to work fine. Also, it seems like the Flex + ESP behaves mostly like Standard + GSE:
So at least for App Engine (Flex or Standard), the Content-Length header is never needed. What part of the changes do you think could cause issues with API management? |
|
I don't remember, it's mostly dejavu feelings in my head :) since you've tested it, I think it's no worry. |
When serializing big responses as JSON (tens of MBs), Cloud Endpoints can easily trigger OOMEs, even on the relatively "big" F4 App Engine instances. This is caused by the creation of an intermediate String object containing the whole JSON response.
This change does not create the intermediate String anymore, and streams the JSON output directly to the response (even if it's not real streaming on App Engine).
As a side effect, the Content-Length header is not set by default, as it's not necessary anyway on App Engine (removed or changed by front-end servers).
The header can be reenabled if necessary with the servlet init parameter addContentLength=true, with a negligible performance penalty (requires the object to be serialized twice). However, I don't see any obvious use case for it.
After this change, F2 instance can reach the maximum response size of 32MB without OOME. Previously, OOME started to happen around 22MB reponse size.
It also provides a significant latency improvement (3.5s vs. 4.5s on a F2 instance for a quite complex 12MB JSON reponse).
Note: if you intend to perform performance tests, you should not map the EndpointsServlet to the default /_ah/api/* path, as the request would be going through the legacy Endpoints v1 servers, that add a very significant latency to big responses (even if Endpoints v1 is officially shut down since August 2, 2018)