Кто доставляет большее количество одновременных запросов?
Мы разрабатываем что-то вроде рекламного прокси или Google Ad Buffer. Сервис просто перенаправляет рекламные HTTP-запросы на сервер SSP. Для этого необходимо создавать множество HTTP-запросов с минимальными аппаратными ресурсами. Поэтому мы решили провести исследование и сравнить языки программирования с виртуальными машинами и скомпилировали их.
Мы хорошо знакомы с технологиями NodeJS и JavaScript. Поэтому мы начали тестировать HTTP-соединение с движком V8. Конечно, мы не начинали с нуля, мы использовали пакет fastify. На самом деле он основан на HTTP-пакете NodeJS. Таким образом, в нижней части стека программного обеспечения находится скомпилированный HTTP-сервер низкого уровня. Но в любом случае есть крошечный слой, работающий под V8. Вопрос в том, как этот слой замедляет выполнение.
NodeJS
Сценарий довольно прост.
const fastify = require(“fastify”)({ logger: false, }); fastify.get(“/fillbuffer”, async (request, reply) => { reply.type(“application/json”).code(200); return { result: `{result: “Hello world”}`, }; }); fastify.listen(3008, (err, address) => { if (err) throw err; });
Для тестирования я использовал инструмент ApacheBench (ab). Давайте пропустим полную спецификацию оборудования. Могу лишь сказать, что использовал процессор I7–8550U.
ab -n 1000000 -c 100 localhost:3008/fillbuffer Requests per second: 12925.33 [#/sec] (mean) Time per request: 7.737 [ms] (mean) Time per request: 0.077 [ms] (mean, across all concurrent requests) Percentage of the requests served within a certain time (ms) 50% 8 66% 8 75% 8 80% 8 90% 9 95% 10 98% 12 99% 13 100% 106 (longest request)
Давайте попробуем больше одновременных подключений.
ab -n 1000000 -c 500 localhost:3008/fillbuffer Results: Requests per second: 9673.37 [#/sec] (mean) Time per request: 51.688 [ms] (mean) Time per request: 0.103 [ms] (mean, across all concurrent request Percentage of the requests served within a certain time (ms) 50% 48 66% 49 75% 50 80% 51 90% 58 95% 79 98% 137 99% 156 100% 286 (longest request)
Все идет нормально. 500 одновременных подключений превышают лимит ЦП, и решение Node начинает испытывать трудности, но давайте получим цифры Go.
Go
Сценарий немного длиннее, но все же короткий.
package main import ( “encoding/json” “fmt” “log” “github.com/valyala/fasthttp” ) var ( addr = “:3008” strContentType = []byte(“Content-Type”) strApplicationJSON = []byte(“application/json”) httpClient *fasthttp.Client ) func main() { fmt.Println(“Starting server…”) h := requestHandler h = fasthttp.CompressHandler(h) httpClient = &fasthttp.Client{ MaxConnsPerHost: 2048, } if err := fasthttp.ListenAndServe(addr, h); err != nil { log.Fatalf(“Error in ListenAndServe: %s”, err) } } func requestHandler(ctx *fasthttp.RequestCtx) { if string(ctx.Method()) == “GET” { switch string(ctx.Path()) { case “/fillbuffer”: ctx.Response.Header.SetCanonical(strContentType, strApplicationJSON) ctx.Response.SetStatusCode(200) response := map[string]string{“result”: fmt.Sprintf(“hello world”)} if err := json.NewEncoder(ctx).Encode(response); err != nil { log.Fatal(err) } } } }
Как видите, я решил использовать fasthttp
в качестве HTTP-сервера. Сервер не основан на какой-либо HTTP-библиотеке. Так что это действительно чистая реализация протокола HTTP. Давайте посмотрим результат для 100 одновременных запросов.
ab -n 1000000 -c 100 localhost:3008/fillbuffer Requests per second: 15847.80 [#/sec] (mean) Time per request: 6.310 [ms] (mean) Time per request: 0.063 [ms] (mean, across all concurrent requests) Percentage of the requests served within a certain time (ms) 50% 6 66% 7 75% 7 80% 7 90% 7 95% 7 98% 8 99% 8 100% 18 (longest request)
Что ж, цифры действительно велики по сравнению с решением NodeJS. Особенно запросы, обслуживаемые в течение определенного времени. Он почти плоский. Начнем последний тест.
ab -n 1000000 -c 500 localhost:3008/fillbuffer Requests per second: 14682.27 [#/sec] (mean) Time per request: 34.055 [ms] (mean) Time per request: 0.068 [ms] (mean, across all concurrent requests) Percentage of the requests served within a certain time (ms) 50% 34 66% 36 75% 37 80% 37 90% 39 95% 40 98% 41 99% 41 100% 62 (longest request)
Заключение
Как видите, время обслуживания решения Go по-прежнему не меняется. Похоже, что еще есть место для получения большего количества одновременных запросов, но давайте просто сравним основные цифры.
Go — единственный победитель, особенно с большим количеством одновременных запросов.
Так что крошечный слой под двигателем V8 не такой уж и крошечный. Со 100 одновременными запросами доставляйте на 18 % больше запросов. 500 одновременных запросов увеличили прибыль до более чем 34%.