Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

OkHttp transparent compression, 10 times the harvest performance, plus one fault


May 31, 2021 Article blog


Table of contents


The article comes from the public number: little sister taste, the author's little sister dog

To use OkHttp be sure to know its 透明压缩 otherwise you don't know how to die, or you don't know why you live.

It's not a good thing anyway.

What do you mean 透明压缩 ttps automatically adds the gzip request header Accept-Encoding:gzip when the request is sent. S o, when the returned data comes with a gzip response Content-Encoding=gzip OkHttps automatically unzip the data. Accept-Encoding and Content-Encoding are a pair of request heads that correspond to requests and returns, respectively)

Why compression? B ecause it can significantly reduce the capacity of the transfer. Like some cpu-intensive services, such as Kafka, we can turn on gzip compression and speed up the flow of information.

How high is this compression ratio? You can see the real screenshot below, for a normal xml or json the data can be compressed from 9MB to 350KB the compression ratio is enough to 26

 OkHttp transparent compression, 10 times the harvest performance, plus one fault1

It lets system performance fly

SpringCloud microservices, there are now a lot of companies working. Even some traditional businesses, some big data toB companies, want to try crabs.

For a simple SpringBoot service, we just need to configure the corresponding compression in the yml file. I n this way, we get through this part of the browser to the Web service. This compression method, for the big data volume of services, is life-saving!

The configuration is as follows.

server:
  port: 8082
  compression:
    enabled: true
    min-response-size: 1024
    mime-types: ["text/html","text/xml","application/xml","application/json","application/octet-stream"]

The Spring configuration class it corresponds to is org.springframework.boot.web.server.Compression

But don't be happy too early. B ecause it's a distributed environment, the call chain is longer. Even on the intranet, moving a dozen MB of network transmission can take considerable time.

 OkHttp transparent compression, 10 times the harvest performance, plus one fault2

As shown above, a request to reach a real service node from the browser can go through many processes.

  • nginx forwards requests to the microservice gateway zuul
  • Zuul forwards to specific microservices A
  • Microservices A invokes microservices B through the Feign interface

If most of our data is provided by microservices B, any of these links are transmitted slowly, affecting the performance of the request.

So we need to turn on gzip compression for the Feign interface. Using a transparent proxy for OkHttps is the easiest way.

First, introduce feign's jar package into the project.

<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
</dependency>

Second, enable OkHttps in the yml file as a client request kit for feign. To be sure, we blocked httpclient at the same time, which is too heavy and too old.

feign:
  httpclient:
    enabled: false
  okhttp:
    enabled: true

At this point, we can enjoy the convenience of OkHttps' transparent proxy.

If your app packets are large and the call chain is long, this approach can even give your service a performance boost 数秒 x jjdog used to let a snail system fly by adjusting a few parameters. Everyone exclaimed: the original B side can also C a.

How does OkHttp achieve transparent compression?

OkHttps handles transparent compression with interceptors. The specific class is okhttp3.internal.http.BridgeInterceptor

The code is as follows, and when you decide that there is no Accept-Encoding add one yourself.

// If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
// the transfer stream.
boolean transparentGzip = false;
if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
  transparentGzip = true;
  requestBuilder.header("Accept-Encoding", "gzip");
}

The most critical code is below.

if (transparentGzip
    && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
    && HttpHeaders.hasBody(networkResponse)) {
  GzipSource responseBody = new GzipSource(networkResponse.body().source());
  Headers strippedHeaders = networkResponse.headers().newBuilder()
      .removeAll("Content-Encoding")
      .removeAll("Content-Length")
      .build();
  responseBuilder.headers(strippedHeaders);
  String contentType = networkResponse.header("Content-Type");
  responseBuilder.body(new RealResponseBody(contentType, -1L, Okio.buffer(responseBody)));
}

You can see that there are three conditions in the if statement.

  • The program does not have Accept-Encoding set up and transparent compression is enabled
  • The service side has a Content-Encoding header and gzip compression is enabled
  • There are packets

Only if these three conditions are met at the same time will the transparent compression of OkHttps work, helping us to unzip automatically.

It digs a little deep

Unfortunately, the above key code, only if no else that is, when any of these conditions are not met, the back-end packets will be returned intact.

2, 3 two conditions is no problem, as is to return back-end data and no damage, the problem is in the first condition.

If you're in code, use the following code:

Request.Builder builder = chain.request()
                .newBuilder()
                .addHeader("Accept", "application/json")
                .addHeader("Accept-Encoding", "gzip");

That is, Accept-Encoding information is set manually. This is common because it reflects the rigour of the programmer's mind.

It is this rigour that is causing the problem.

If your back-end app doesn't turn on gzip compression at first, it's okay, but if your back-end app suddenly turns on gzip compression one day, your code will be all over.

The reason is that the service-side gzip packet returns as is, and you need to manually process the gzip packet.

So, if you don't add it, it's a bad thing to add it, unless you want to handle the gzip data yourself.

Because OkHttp is also widely used on Android if you don't know this detail, the consequences can be disastrous. Client updates are slow and can only be honestly rolled back to the service side.

Behind the intelligence, there are always details that are invisible to the naked eye. I t's like behind xjjdog's pure feelings, there's always a shyness. Only if you know more will you know its beauty.

Above is W3Cschool编程狮 about OkHttp transparent compression, harvest performance 10 times, plus a fault of a related introduction, I hope to help you.