Enable gzip compression on ES Java REST client#4784
Conversation
|
This might actually make more of a difference to the AI search than to normal, because we request more images (2 x 200) than normal search and we need the vectors returned with all of them |
twrichards
left a comment
There was a problem hiding this comment.
see comment, but I think this a worthwhile improvement... 👏 (particularly in light of comment from @joelochlann re benefit for AI search responses)
| val hosts = ElasticProperties(url).endpoints.collect { | ||
| case ElasticNodeEndpoint(protocol, host, port, _) => | ||
| new org.apache.http.HttpHost(host, port, protocol) | ||
| } | ||
| val restClient = org.elasticsearch.client.RestClient | ||
| .builder(hosts: _*) | ||
| .setCompressionEnabled(true) // request gzip from ES; reduces response body ~5-6× | ||
| .build() |
There was a problem hiding this comment.
as explained IRL...
Minus the setCompressionEnabled line, this is essentially the internals of the JavaClient.apply(properties: ElasticProperties) so if ever that were to change in future versions of elastic4s we would end up with divergence (from any beneficial defaults changed in the lib)... this is very unlikely, and arguably in some ways safer as protected from changes to defaults on their side that could be detrimental... I think the trade-off is definitely worth it for the benefits.
One thought would be (in addition to this PR) to raise a PR against elastic4s to make this an argument to either JavaClient.apply or ElasticProperties.apply then assuming they approve/merge, then whenever we upgrade our elastic4s version we can remove the code from this PR in favour of passing the flag (plus nice for the open source spirit).
Co-authored by Claude.
What does this change?
This is to test the effect of enabling GZip between media-api and ES. It’s got dramatic effect for local dev, but the question is: how will it affect TEST/PROD. If at all… After I gather measurements, I will present them ’ere…
BTW, I hear there isn’t a nicer way of doing it.
🤖 narrative after measuring DEV and this deployed to TEST vs main:
Performance measurements
What this patch does: makes the ES Java REST client send
Accept-Encoding: gzipsoES returns compressed responses. The elastic4s
JavaClient.apply()doesn't exposesetCompressionEnabled, so we build theRestClientdirectly and wrap it viaJavaClient.fromRestClient(). The response handler already decodes gzip(
isEntityGziped → GZIPInputStream) — only the request-side opt-in was missing.Blast radius:
common-lib/ElasticSearchClient— affects all services that extend it(media-api, thrall, cropper, usage, …). Behaviour is transparent: same JSON in and out.
Arena A — local dev (media-api → TEST ES over SSH tunnel)
Signal:
durationin media-api log = time from sending ES request to fully reading andparsing the response body. This leg is bandwidth-limited by the tunnel (~800 KB/s).
durationbeforedurationafterlength=1length=50length=200(max)The tunnel is bandwidth-limited; the uncompressed payload dominates latency there.
This is a dev-only latency win — a direct consequence of tunnel topology, not a prod speed-up.
Arena B — TEST environment (media-api → ES intra-VPC, fast link)
Signal: same
durationfield, read from Kibana. Both runs pre-warmed (20 throwaway requestsper length), 100 reps, identical query and pinned
untiltimestamp.durationbefore (main)durationafter (patch)length=1length=50length=200(max)¹ The after-run for
length=50had a cluster load burst at the end of the batch(144–254 ms spike, visible in the raw data) that inflated its median. The steady-state
warm values overlap: 104–136 ms before vs 117–145 ms after.
² The −13 ms at
length=200appears consistently across three independent after-runs.Likely reduced heap/GC pressure: media-api reads a 291 KB buffer from the socket instead
of 1742 KB, even though the decompressed JSON is the same size.
Conclusion: no latency regression on the prod-like intra-VPC link. Worst case is +14 ms
at
length=50, explained by measurement noise. The intra-VPC link is fast enough that6× fewer bytes-on-wire barely registers as latency — exactly as the topology predicts.
Unmeasured trade-off
ES-side compression and media-api-side decompression add CPU. This cost is invisible at
TEST's near-zero QPS but is real at editorial-load PROD QPS. It should be small relative
to the existing JSON-parse work (~137 ms Argo envelope build per 200-hit page), but it
hasn't been directly measured under sustained load. Worth monitoring after deploy.
Tested? Documented?