Java, отличные клиенты REST медленнее, чем Postman, более чем в 30 раз

Я написал клиент REST, используя springs RestTemplate в java и в groovy, используя «HTTPBuilder». Оба вызова заняли 10 секунд на моем компьютере. В Postman и других подобных инструментах тот же самый почтовый запрос занимал 300 мс.

Это простой вызов в скрипте groovy. Essential находится между BEGIN REST invocation и END REST invocation:

    @Grapes(
            @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7')
    )


    import groovy.json.JsonOutput
    import groovy.json.internal.LazyMap
    import groovy.transform.ToString
    import groovyx.net.http.HTTPBuilder

    import static groovyx.net.http.ContentType.JSON
    import static groovyx.net.http.Method.POST


    HTTPBuilder http = new HTTPBuilder()
    Forechart forechart = new Forechart(dayInterval: 3, adultCount: 1, childCount: 0,
                                        flightList: [new Flight(departureStation: "WAW", arrivalStation: "CRL", date: new Date(2018, 06, 02))
                                                    ,new Flight(departureStation: "CRL", arrivalStation: "WAW", date: new Date(2018, 10, 26))])

    def jsonRequest = JsonOutput.toJson( forechart )
    LazyMap jsonResponse



    //BEGIN REST invocation
        println "Request: " + JsonOutput.prettyPrint(jsonRequest)
        long start = System.nanoTime()

        http.request( 'https://be.wizzair.com/7.15/Api/asset/farechart', POST, JSON ) { req ->
            body = jsonRequest
            headers.Accept = 'application/json'

            response.success = { resp, json ->
                assert resp.statusLine.statusCode == 200
                jsonResponse = json
            }

            response.'404' = {
                println 'Not found'
            }
        }

        long end = System.nanoTime() - start

        //println "Response: $jsonResponse"
        println "\nDuration: " + end / 1_000_000_000 + " seconds"
    //END REST invocation



    ForechartFlights forechartFlights = new ForechartFlights(jsonResponse)
    //Data Objects
    @ToString(includePackage = false)
    class Forechart {
        boolean wdc
        List<Flight> flightList
        int dayInterval
        int adultCount
        int childCount
        boolean isRescueFare
    }

    @ToString(includePackage = false)
    class Flight {
        String departureStation
        String arrivalStation
        Date date
    }


    //response

    @ToString(includePackage = false)
    class ForechartFlights {
        List<ForechartFlight> outboundFlights
        List<ForechartFlight> returnFlights
    }

    @ToString(includePackage = false)
    class ForechartFlight {
        String departureStation
        String arrivalStation
        String priceType
        String classOfService
        boolean hasMacFlight
        Date date
        Price price;

    }

    @ToString(includePackage = false)
    class Price {
        BigDecimal amount
        String currencyCode
    }

Что такое причина?


person Łukasz Urbański    schedule 27.05.2018    source источник


Ответы (1)


Кажется, этот запрос занимает некоторое время (8+ секунд) с использованием curl:

~> time curl -v -d "@post.data" -H "Content-Type: application/json" https://be.wizzair.com/7.14.0/Api/asset/farechart

*   Trying 104.122.232.212...
* TCP_NODELAY set
* Connected to be.wizzair.com (104.122.232.212) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: wizzair.com
* Server certificate: DigiCert SHA2 Extended Validation Server CA
* Server certificate: DigiCert High Assurance EV Root CA
> POST /7.14.0/Api/asset/farechart HTTP/1.1
> Host: be.wizzair.com
> User-Agent: curl/7.59.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 407
>
* upload completely sent off: 407 out of 407 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Cache-Control: no-cache,no-store
< Pragma: no-cache
< Expires: -1
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< Strict-Transport-Security: max-age=31536000
< Server:
< Date: Sun, 27 May 2018 18:07:43 GMT
< Content-Length: 10023
< Connection: keep-alive
< Set-Cookie: ASP.NET_SessionId=hnrxfwuxvkxo34k3zhcljnce; path=/; secure; HttpOnly
< Set-Cookie: _abck=83611DFC82637AC8726723372C6A8EFC50EFF7BD2A040000EFF30A5B01AC6952~-1~Ip07wEKIXzwehsarZ0eh+sBBuiiRDje8DAQpi80fdXk=~-1~-1; expires=Mon, 27 May 2019 18:07:43 GMT; max-age=31536000; path=/; domain=.wizzair.com
< Set-Cookie: bm_sz=41F805925F8BB0BCFE47CBE64B3531A2~QAAQvffvUJsv45ZjAQAAId/IorrnukpLPnmZ8H7WRPTEdCk0rMrrIOdi+wLlRh3DFodvGU9Mu5gq0MDfhTtHxwo4hm0DC2IT5Ql6PrXWlY59p5wf57bBed+P4Lq5+bX7XtlNRFTFda9yjVVzYbgknJ30w8JOrE2prYAGu1mh/9qkFPzvKkJXjGcz7QA8eLUS; Domain=.wizzair.com; Path=/; Expires=Sun, 27 May 2018 22:07:35 GMT; Max-Age=14392; HttpOnly
<
<snip>response data here</snip>
real  0m8.386s
user  0m0.024s
sys 0m0.022s

Где я сначала сохранил данные запроса в файле post.data.

Я подозреваю, что в запросе есть какой-то заголовок или другая деталь, которая не идентична между вызовами, которые занимают много времени (например, этот curl и пример groovy), и теми, которые этого не делают.

Если вы используете такой инструмент, как Postman, проверьте заголовки запросов и посмотрите, есть ли что-то, что мы не отправляем в тех, которые занимают много времени.

обновить после дальнейшего тестирования

Я проверил это и с почтальоном (т.е. быстро с почтальоном, медленно с java и curl), и никакой разницы в заголовках. Я совершенно убежден, что это связано с обработкой https и TLSv1.2.

Потенциальным, хотя, возможно, и далеким виновником может быть заявленное медленное (не аппаратное ускорение) шифрование AES GCM, которое позволяет TLSv1.2 (которое используется сайтом в соответствии с приведенной выше трассировкой curl):

Сервер Java, TLSv1 .1 быстро, TLSv1.2 очень медленно (90 МБ/с против 4 МБ/с)

Медленное шифрование и дешифрование AES GCM с помощью Java 8u20

обновление 2 после дополнительной экспертизы

отправив следующий флаг в groovy (или java) при запуске теста:

-Djavax.net.debug=all

мы видим, что клиентский скрипт получает зашифрованные данные:

<snip a ton of network and tls detail>
05B0: 9E EA 98 06 6B 91 EC 2A   76 C8 F3 39 81 88 C5 30  ....k..*v..9...0
05C0: 02 34 45 E9 8C 12 EE 07   E3 31 C7 5C 8F DB FD C9  .4E......1.\....
05D0: 80 F4 0A F7 B4 57 CC 68   EF 96 70 7C 5E B6        .....W.h..p.^.
main, READ: TLSv1.2 Application Data, length = 1502
Padded plaintext after DECRYPTION:  len = 1478
0000: 48 54 54 50 2F 31 2E 31   20 32 30 30 20 4F 4B 0D  HTTP/1.1 200 OK.
0010: 0A 43 6F 6E 74 65 6E 74   2D 54 79 70 65 3A 20 61  .Content-Type: a
0020: 70 70 6C 69 63 61 74 69   6F 6E 2F 6A 73 6F 6E 3B  pplication/json;
0030: 20 63 68 61 72 73 65 74   3D 75 74 66 2D 38 0D 0A   charset=utf-8..
00
<snip - HttpOnly is the end of the last response cookie, after that 
I'm assuming the encrypted data starts> 
0410: 3B 20 48 74 74 70 4F 6E   6C 79 0D 0A 0D 0A 1F 8B  ; HttpOnly......
0420: 08 00 00 00 00 00 00 03   CD 98 C1 4A C3 40 14 45  [email protected]
0430: FF 65 D6 09 CC 4C 6D D4   EC A4 E2 AA 45 B0 85 2E  .e...Lm.....E...
<snip - more encrypted data>
0590: 1C 78 6E C4 5E C0 16 39   F0 DC 68 77 99 22 C7 16  .xn.^..9..hw."..
05A0: 39 EC DC B0 45 0E CC 46   BC 2F 60 8B 1C 78 6E C4  9...E..F./`..xn.
05B0: FB 02 B6 C8 81 E7 46 BC   2F 9C 5D E4 4E 6F FC FF  ......F./.].No..
05C0: 20 5E 27 27 00 00                                   ^''..
<THIS IS WHERE WE HANG FOR A LONG TIME>
Duration: 10.904149839 seconds

(ну мы видим тонну вывода, но в конце получаем зашифрованные данные)

а потом просто долго там висит.

Другими словами, это не получение данных или сервер, занимающий много времени. У нас уже есть данные, а затем зависание.

Я предполагаю, что расшифровка полученных данных требует времени, и я бы приписал это вышеупомянутой медленной расшифровке или какой-либо аналогичной проблеме с java ssl.

Не совсем твердая, но кажется, по крайней мере, правдоподобной теорией.

Предполагая, что приведенная выше теория верна, мы все еще не можем понять, почему curl работает медленно.

person Matias Bjarland    schedule 27.05.2018