Pull to refresh

Comments 98

Mail.ru как бы намекает, что скоро начнет хантить Go разрабов =)
Интересно, почему python не попал на тестирование? По остальным параметрам более чем подходит:
community size: 509,465
packages count: 71 290
developers: 3 563

p.s. наткнулся на интересный бенчмарк в тему, вот ссылка
Ага, спасибо, тоже изучали бенчмарк по ссылке. В наших тестах, к слову, так же была темная лошадка C++, которая оказалась самой очень быстрой. На python почему-то никто из команды не взялся разрабатывать первый вариант бенчмарка, поэтому его не стали рассматривать и потом. =)
Было бы круто увидеть бенчмарки темной лошадки
Внизу чуть-чуть в комментах приоткрыли завесу по wrk ))
Хороший обзор, спасибо.

К слову, regexp библиотека в Go считается медленной, хотя там использован алгоритм, несколько отличный от C-шного, который гарантирует линейную зависимость времени от размера входных данных.

Для этого случая можно попробовать PCRE (хотя, он оказался медленнее), или наивный split строки:
Код вариантов
package regex

import (
«github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre»
«regexp»
«strings»
)

var (
reg = regexp.MustCompile("^/greeting/([a-z]+)$")
pcreReg = pcre.MustCompile("^/greeting/([a-z]+)$", 0)
)

func RegexOrig(str string) string {
return reg.FindStringSubmatch(str)[1]
}

func RegexPCRE(str string) string {
return pcreReg.MatcherString(str, 0).GroupString(1)
}

func RegexStrings(str string) string {
return strings.Split(str, "/")[2]
}

func RegexNaive(str string) string {
if strings.HasPrefix(str, "/greeting/") {
return str[len("/greeting/"):]
}
return ""
}

Код бенчмарка
package regex

import «testing»

var str = "/greeting/user"

func TestRegexps(t *testing.T) {
if RegexOrig(str) != «user» {
t.Fatal(«RegexpOrig failed on», str, ":", RegexOrig(str))
}
if RegexPCRE(str) != «user» {
t.Fatal(«RegexpPCRE failed on», str, ":", RegexPCRE(str))
}
if RegexStrings(str) != «user» {
t.Fatal(«RegexpStrings failed on», str, ":", RegexStrings(str))
}
if RegexNaive(str) != «user» {
t.Fatal(«RegexpNaive failed on», str, ":", RegexNaive(str))
}
}

func BenchmarkOrig(b *testing.B) {
for i := 0; i < b.N; i++ {
RegexOrig(str)
}
}

func BenchmarkPCRE(b *testing.B) {
for i := 0; i < b.N; i++ {
RegexPCRE(str)
}
}

func BenchmarkStrings(b *testing.B) {
for i := 0; i < b.N; i++ {
RegexStrings(str)
}
}

func BenchmarkNaive(b *testing.B) {
for i := 0; i < b.N; i++ {
RegexNaive(str)
}
}


Результат примерно такой выходит:
$ go test -v -bench . -benchmem .
=== RUN   TestRegexps
--- PASS: TestRegexps (0.00s)
PASS
BenchmarkOrig-4   	 2000000	       845 ns/op	      64 B/op	       2 allocs/op
BenchmarkPCRE-4   	 1000000	      1481 ns/op	     160 B/op	       3 allocs/op
BenchmarkStrings-4	 5000000	       284 ns/op	      48 B/op	       1 allocs/op
BenchmarkNaive-4  	100000000	        11.4 ns/op	       0 B/op	       0 allocs/op
ok  	test/regex	6.879s
Спасибо! Я тоже думал было переписать на split во всех примерах, но потом показалось, что с regexp будет более жизненно. При оказии попробую прогнать wrk со split.
И на чем бы им свой очередной вирус написать? Кто бы написал сервис по вычищению ихних сервисов с компа.
Интересно, что бы показал finagle от твиттера. Всё же там минимум абстракций над netty
Если есть желание – можете напилить проектик на github, мы его соберем и прогоним на той же машине. Ну или можете сами собрать наши сервисы и прогнать их на своей =)
Вот такой код:
  val endpoints: Endpoint[String :+: String :+: CNil] =
    get(/) {Ok("Hello, World!")} :+: get("greeting" / string) { name: String => Ok("Hello, " + name + "!") }

  Await.ready(Http.serve(":8080", endpoints.toService))


Дал такие результаты:
Finch
Server Software:
Server Hostname: localhost
Server Port: 8080

Document Path: /
Document Length: 13 bytes

Concurrency Level: 256
Time taken for tests: 1.154 seconds
Complete requests: 50000
Failed requests: 0
Total transferred: 5800000 bytes
HTML transferred: 650000 bytes
Requests per second: 43328.87 [#/sec] (mean)
Time per request: 5.908 [ms] (mean)
Time per request: 0.023 [ms] (mean, across all concurrent requests)
Transfer rate: 4908.35 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 2 1.1 1 8
Processing: 0 2 1.6 2 15
Waiting: 0 2 1.4 1 15
Total: 0 4 2.6 3 17

Percentage of the requests served within a certain time (ms)
50% 3
66% 5
75% 6
80% 6
90% 8
95% 9
98% 10
99% 11
100% 17 (longest request)

Для сравнения:
Go
Server Software:
Server Hostname: localhost
Server Port: 8080

Document Path: /
Document Length: 12 bytes

Concurrency Level: 256
Time taken for tests: 1.241 seconds
Complete requests: 50000
Failed requests: 0
Total transferred: 6450000 bytes
HTML transferred: 600000 bytes
Requests per second: 40297.59 [#/sec] (mean)
Time per request: 6.353 [ms] (mean)
Time per request: 0.025 [ms] (mean, across all concurrent requests)
Transfer rate: 5076.55 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 3 49.5 0 1000
Processing: 1 3 4.5 3 204
Waiting: 0 3 4.5 3 203
Total: 1 6 51.2 3 1199

Percentage of the requests served within a certain time (ms)
50% 3
66% 3
75% 3
80% 3
90% 4
95% 6
98% 8
99% 15
100% 1199 (longest request)


Но если брать несколько прогонов то там результаты и Go и Finch примерно одинаковы ~6ms.
Найс. Если мне не изменяет память, то Финч где-то на 5-15% добавляет оверхеда, то на то и выходит
Я бы сказал 5-7% по последним данным:

— Очень много опитизаций было сделано Тревисом в Circe
— В Finch как минимум две вещи помогли сократить разрыв: TooFastString и быстрые ридеры

Но, на удивление, этот тест не использует ни того ни другого. В любом случае оч крутой результат!
Ещё интересно было бы посмотреть результаты с Go с использованием fasthttp — ускоренной альтернативы стандартному net/http.
А если сделать замеры, экззотики для и фана ради, на связке Nginx+LUA?
Еще есть вот такая экзотика: H2O+MRuby (неделю назад наткнулся вот на эту статью 25,000+ Req/s for Rack JSON API with MRuby

PS еще конечно не пятница, но вдруг :)
Теоретически – интересно ) Но практически, на lua приложухи сложновато будет писать )
Это уже ближе к вопросу о микросервисах и соответствующей архитектуре.

Сделали же вот такое Kong.

PS: если сложно на Lua, там и второй вариант рядом, еще большая экзотика )
> и, так или иначе, субъективных взглядов мы выбрали Go

Вы ведь его выбрали еще до тестов, к чему тогда был этот карнавал?
Это неправда, Node для нас был изначально ближе, а ещё gobwas возлагал большие надежды на Rust, так что всё по чесноку было сделано. Тест перепроверялись, велись обсуждения и по совокупности факторов, в том числе и субъективных, был выбран Go.
Я имею ввиду Time per request в ab. У меня на локальных тестах с вашим кодом выдает цифры в районе ~10ms.
На локальных тестах – где у кого ~10ms? ) Тесты и серверы запускались на одной виртуалке, да. Естественно, по очереди. Да, может, лучше было бы запустить где-то в облаке, но в среднем, результаты из прогона в прогон – сохраняются. Тем более, что нам важнее было определить не производительность в общем, а производительность относительную.
У go — 6.2ms в среднем, у Scala/Spray — 8.3ms в среднем. Scala после прогрева, потому что до прогрева тестировать смысла нет.
А что по rps и completed requests?
Я выше выложил результаты Scala/Finch и Go. Можете глянуть.
Вы выбирали основной язык для mail.ru или для одного определенного сервиса?
Выбирали язык для новых сервисов внутри команды почты =) В MailRu команд много )
Утилита от Apache ab использует HTTP 1.0 и может передавать заголовок «Connection: Keep-Alive». Если сервер достаточно вменяемый, то он, увидев этот заголовок, будет держать keep-alive соединение. Делается это с помощью флага -k, например:
ab -k -n50000 -c256 -t10 http://service.host/ 
ab -k -n50000 -c256 -t10 http://service.host/greeting/hello 
Спасибо! Keep-Alive в ab нам был не нужен – иначе мы бы получили тот же wrk =)
Ребят, вот честно, ну что вы в самом деле, вот берёте плюшевый плюсовый http-сервер из примеров буста: www.boost.org/doc/libs/1_59_0/doc/html/boost_asio/examples/cpp11_examples.html

Меняете там request_handler.cpp под задачу из поста (которая гораздо проще, чем в примере).

Код метода
void request_handler::handle_request(const request& req, reply& rep)
{
    using namespace std::literals::string_literals;

    static std::regex greeting_regex("^/greeting/([a-z]+)$");

    std::string request_path;
    if (!url_decode(req.uri, request_path))
    {
        rep = reply::stock_reply(reply::bad_request);
        return;
    }

    std::smatch greeting_match;
    if (request_path == "/")
    {
        rep.status = reply::ok;
        rep.content = "Hello, World!";
    }
    else if (std::regex_match(request_path, greeting_match, greeting_regex))
    {
        if (greeting_match.size() == 2)
        {
            rep.content = "Hello, "s + greeting_match[1].str() + "\r\n"s;
        }
        else
        {
            rep = reply::stock_reply(reply::not_found);
            return;
        }
    }
    else {
        rep = reply::stock_reply(reply::not_found);
        return;
    }

    rep.status = reply::ok;
    rep.headers.resize(1);
    rep.headers[0].name = "Content-Length";
    rep.headers[0].value = std::to_string(rep.content.size());
}



И тестируете. Ну рвёт ведь всех просто как тузик грелку.

Спойлер с измерениями
комп
(192.168.1.16 — моя виртуалка)

wrk:

$ wrk -d300s -c1000 -t50 --timeout 2s http://192.168.1.16/
Running 5m test @ http://192.168.1.16/
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    38.56ms  139.88ms   2.00s    95.47%
    Req/Sec   210.75    156.88     4.49k    67.59%
  2963235 requests in 5.00m, 146.95MB read
  Socket errors: connect 0, read 1108, write 31, timeout 3153
Requests/sec:   9874.16
Transfer/sec:    501.42KB


ab:

$ ab -n50000 -c256 -t10 http://192.168.1.16/ 
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.16 (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Completed 50000 requests
Finished 50000 requests


Server Software:        
Server Hostname:        192.168.1.16
Server Port:            80

Document Path:          /
Document Length:        13 bytes

Concurrency Level:      256
Time taken for tests:   2.915 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      1600000 bytes
HTML transferred:       650000 bytes
Requests per second:    17155.15 [#/sec] (mean)
Time per request:       14.923 [ms] (mean)
Time per request:       0.058 [ms] (mean, across all concurrent requests)
Transfer rate:          536.10 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        2    7  30.9      6    1005
Processing:     2    8   2.0      7      25
Waiting:        1    6   1.9      5      17
Total:          9   15  31.0     14    1011

Percentage of the requests served within a certain time (ms)
  50%     14
  66%     15
  75%     15
  80%     15
  90%     17
  95%     20
  98%     22
  99%     24
 100%   1011 (longest request)


$ ab -n50000 -c256 -t10 http://192.168.1.16/greeting/hello 
This is ApacheBench, Version 2.3 <$Revision: 1604373 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.16 (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Completed 50000 requests
Finished 50000 requests


Server Software:        
Server Hostname:        192.168.1.16
Server Port:            80

Document Path:          /greeting/hello
Document Length:        12 bytes

Concurrency Level:      256
Time taken for tests:   2.844 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      1550000 bytes
HTML transferred:       600000 bytes
Requests per second:    17580.17 [#/sec] (mean)
Time per request:       14.562 [ms] (mean)
Time per request:       0.057 [ms] (mean, across all concurrent requests)
Transfer rate:          532.21 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        3    6   1.4      6      15
Processing:     2    8   1.8      8      20
Waiting:        1    6   1.9      6      15
Total:          8   15   1.9     14      28

Percentage of the requests served within a certain time (ms)
  50%     14
  66%     15
  75%     15
  80%     15
  90%     17
  95%     19
  98%     20
  99%     22
 100%     28 (longest request)



Вынесу из-под спойлера:

wrk, 1-й тест:
Average Latency, ms: 38.56
Requests/sec: 9874.16

(лень заморачиваться с nginx, результат понятен).

ab, 1-й тест:
Completed requests: 50000
Time per request, ms: 14.923
Request, #/sec: 17155.15

ab, 2-й тест:
Completed requests: 50000
Time per request, ms: 14.562
Request, #/sec: 17580.17

Причём не просто успевает 50000 запросов за 10 секунд, а даже укладывается менее чем в 3 секунды.

О чём это говорит? Надо выбирать C++ (C++14).

И это ещё я не говорю об использовании памяти и процессора (т.е., в конечном счёте, электроэнергии). Ведь мы хотим не только быстро обслуживать клиентов, но ещё и делать это дешевле на долгом промежутке времени.

Причём даже тут есть куда пооптимизировать.
C++ надо еще выучить.

И желательно не медленнее, чем за 21 день :)
image
Да что-то не верится, что в Mail.ru нет C++-программистов
wrk, 1-й тест:
Average Latency, ms: 38.56
Requests/sec: 9874.16


Если сравнивать наши реализации серверов на go и c++, то у нас они следующие (c++ не представлен в статье):

Go:
Average Latency, ms: 104,83
Requests/sec: 36191.37

C++
Average Latency, ms: 57.88
Requests/sec: 16792.48

Скорость ответа не всегда равно высокая производительность.

Никто не спорит, что C++ может быстрее. Erlang, например, тоже может очень быстро.
И данный обзор никак не пытается определить лучший в мире язык программирования. =)
А покажите код C++ и результаты ab для req/sec.

wrk больше для измерения latency подходит.
В ab его не тестировали. Код показать, к сожалению, нельзя.

Почему wrk подходит больше для latency?
Особенности реализации (предназначен для тестирования nginx).

Например, скорость работы wrk зависит от ресурсов системы (не сервера, а откуда запускаете).

Если, например, запускать подряд, то он может даже выдать `Socket errors: connect: 1000` или что-то типа: `Socket errors: connect 0, read 1490, write 159932, timeout 0`, полная ерунда, т.е. все коннекты свалились в ошибку, хотя при этом на сервер даже не было соединений (я проверял по tcpdump). Соответственно, все такие «несостоявшиеся» соединения уменьшат значение «Requests/sec». А вот latency рассчитывается только по удачным соединениям.

При этом прямо во время этих ошибок коннекта можно проверять банально браузером — всё будет работать.

Вот здесь ещё много «грязных» подробностей: gwan.com/en_apachebench_httperf.html
Или вот прямо сейчас пытаюсь разобраться:

в одном окне терминала запустил сервер, во втором (на той же машине чтобы уж точно не повлияло ничего):

$ ./wrk -d300s -c1000 -t50 --timeout 2m http://localhost/greeting/hello


в третьем:

$ netstat -an | grep tcp 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.1.1:53            0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6942          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:63342         0.0.0.0:*               LISTEN     


т.е. сервер слушает, всё ок, но соединений нет

как результат:


Running 5m test @ http://localhost/greeting/hello
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    81.71ms  174.10ms   1.75s    90.76%
    Req/Sec    62.24    136.83     1.74k    94.96%
  7328 requests in 5.00m, 379.28KB read
  Socket errors: connect 1000, read 0, write 0, timeout 0
Requests/sec:     24.42
Transfer/sec:      1.26KB


Вот что он делал? Я не знаю. И никаких подробностей.

Вывод: wrk — довольно странный инструмент. Или я совсем ничего не понимаю и пора уже переквалифицироваться в дворники. Кто понимает — помогите понять, плз.
А со второй попытки – работает? )
Не знаю, со второй или нет, но сейчас запустил — работает.
Всё слишком странно.
Почему ab работает, а wrk нет?
Ещё попутно вот что нашёл: github.com/giltene/wrk2

Автор утверждает, что wrk считает latency неправильно.
> Код показать, к сожалению, нельзя.

Странно, код на других языках показали, а этот нельзя :-)
Причем еще бустовая реализация — самая медленная из всех C\CPP.
Когда-то давно — нативный модуль к nginx всех уделывал, надо бы перетестить.
Всетроенный libevent-овский и mongoose были не плохи.
Однопоточные библиотеки (libevent/mongoose) в принципе не могут «уделать» Boost.Asio (многопоточность, под линухом использует epoll, под bsd — kqueue, под виндой — iocp).

cpp-netlib не в счёт, это очень плохая реализация и не зря заброшена на текущий момент.
libevent — то же самое (кастомные асинхр. механизмы, он изначально для этого и создан), с помощью fork-ов поднимается любое кол-во процессов на одном порте без оверхеда на переключение потоков.

Pion тоже на boost.asio, результаты у него очень скромные были.
Не зря Pion тоже заброшен :-)
go: 92838.98 rps
java: 200127.00 rps
./wrk -c 512 -t 2 -d 60 http://localhost:8080/
Running 1m test @ http://localhost:8080/
  2 threads and 512 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.22ms    3.58ms  77.45ms   77.41%
    Req/Sec    46.68k     5.97k   73.15k    69.77%
  5577230 requests in 1.00m, 686.13MB read
Requests/sec:  92838.98
Transfer/sec:     11.42MB

./wrk -c 512 -t 2 -d 60 http://localhost:8084/
Running 1m test @ http://localhost:8084/
  2 threads and 512 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.56ms    2.73ms  49.36ms   87.17%
    Req/Sec   100.61k    11.36k  130.28k    74.87%
  12009644 requests in 1.00m, 1.29GB read
Requests/sec: 200127.00
Transfer/sec:     21.95MB
А можно на `htop` посмотреть во время теста явы? :-)
только завтра, код на рабочем ноутбуке… не знаю, правда на что смотреть, все четыре ядра заняты на 100%
ой-ой, тогда можно не показывать htop :-)

вот тот код на с++ использует 1% cpu

вообще, я, конечно, хотел спросить про потребление памяти, но теперь уже не имеет смысла
м… отличный бенчмарк, что он меряет, если фактически не напрягает программу?
измеряет производительность

программе на c++, чтобы обработать 1000 параллельных запросов, нужно менее 1% cpu, и, на x86_64 — 3 МБ памяти.

а программе на яве… ну увы.

кстати, мерить на локалхосте неспортивно :-)
Такие бенчмарки — полная туфта.

Делать их весело, но как себя поведет приложение, когда в него добавится логика, когда начнется сборка мусора, проявятся прочие нюансы — эти тесты не показывают.
Зато эти тесты показывают, как ведут себя голые серверы, без «прочих нюансов» которые зависят от рук программистов. И оверхед каждого из претендентов никуда не денется, если «в него добавится логика и начнется сборка мусора».
Вот только оверхед может потеряться на фоне основной задачи. Потому что при пустом коде вы меряете не производительность языка, а производительность тест-драйвера, ядра, и http-библиотеки, которую специально оптимизировали в языках, заточенных на создание web-сервисов
Тест-драйвер и ядро исключаем, ибо они равны. В итоге измеряем http-библиотеки в выбранных языках. Ой, разве не этого мы и хотели? =)
Я думал, что мы хотим померить скорость нашего будущего приложения.
Странно, что вы не добавили maintainability в список показателей.
Написать сервер с «hello world» и тестировать производительность языка? Окай…
Могу сказать про Rust, его производительность ± такая же, что и C++. Писал небольшой сервис для неточного сравнения текстов и сравнивал производительность.
Очевидно, что Rust будет быстрее работать Go, поскольку в Rust нет сборщика мусора.
Тоже целиком за Раст, единственный минус его — то, что сегодня написанная программа через 2 недели может устареть: «Too old compiler version» :-)
Вроде как это выражение уже не особо актуально.
Еще смущает выбор hyper для теста.
меня смущает отсутствие в расте stackless coroutines
А что бы выбрали вы?
Так пишите не на nightly, а на stable — до выхода 2.х никаких проблем.
ну а минусовать зачем?

только недавно осенью был 1.3, теперь уже 1.5

а вообще у раста есть проблема, похожая на проблему рельсов: сегодня такой-то гем популярен, а завтра буквально он может выйти из моды
Это просто выражение согласия/несогласия, не относитесь к этому серьёзно.

Они каждые 6 недель будут выпускать новую версию.
При этом гарантируют, что в пределах мажорной версии (1.хх) обратная совместимость не сломается.
говоря про гемы, я не имел в виду сам язык, а говорил о моде на те или иные библиотеки
А какой смысле стрелять по серверу с того же хоста, более того в виртуалке. Сама программа бенчмарка будет неслабо афектить http-сервер. Да и куча всего остального может афектить процесс виртуалки на макбуке. Мне кажется лучше исключать внешние факторы по максимуму.
hyper на сколько я смотрел в его код некоторое время назад, выглядел довольно тормозной либой. Выглядело тогда, что он использует штатный TcpStream с блокирующими сокетами. Тут скорее измерение скорости тормозной либы, а не языка. Но в го, же да есть горутины, которые по логике сильно лучше должны быть, чем треды с синхронными read/write.
Вроде MIO должно быть лучше, но там нет http.
+ я совсем не знаю про дебагеры для го и раста. Как то пункт про дебаг у вас мимо.
И go и rust можно дебажить с gdb. По поводу mio – да, его и пытаются прикрутить создатели hyper (есть ссылка на issue в статье). Меня еще расстраивает тот факт, что в Rust выпилили аналогичные «горутины» или «green threads» после, вроде 0.9 версии со смыслом, типа, если вам нужно – сами напилите планировщик для этих дел.

Про тесты с локального хоста – где-то выше я уже говорил, что расклады от прогона к прогону остаются прежними, соответственно, все в равных условиях.

Про «измерение скорости тормозный либы» – какую не тормозную http либу для Rust знаете вы? Или вы предлагает писать для такого бенчмарка свой http сервер? )
Я не искал быстрого http-сервера на rust. Возможно его вообще нет. Из-за молодости и не очень большой популярности языка.
Про выпиливание корутит из раста я тоже был не рад. Он стал более общим языком, но из-за этого проиграл в легкости написания высокопроизводительных многопоточных приложений.
Ну http сервер на либе с корутинами на расте я думаю по силам написал в mail.ru ) Tarantool, например, сильно более сложный проект.
Собственно, все что нужно это откопать зарытую либу корутин из версии 0.9, взять MIO, либу парсинга http протокола и слепить все вместе с хорошим API!
Лучше бы Swift и D сравнили. Куда более простые языки, чем предложенная выборка.
Community size по предложенной в статье методике у D будет 1 887. На hh разработчиков — 1.
Судя по githut.info и stackoverflow, D уже менее популярен, чем Rust, а значит пакетов у него скорее всего меньше. И что-то мне подсказывает, что разрыв будет все больше. С производительностью там тоже не все однозначно.
Swift только-только вышел в opensource.

Зачем сравнивать заведомо проигрышные варианты? Особенно если есть уже положительный опыт с другими.
>, то первый претендент — это, конечно, Node.js

Лол, месяц сравнения nodejs со всем подряд.
Ладно я понимаю еще с PHP тут пытались сравнить, но cо Scala…
Кто бы вот объяснил — какой скрытый смысл в КДПВ?
Скрытого не нашёл, открытый — гонки.
Ваш кэп
Кэп, на инвалидных креслах?
Вовсе нет, на самоходных тележках для супермаркетов.
Немного несерьёзно, но не Formula 1 же было ставить.
Мы буквально на днях проводили похожие тесты для поиска основы для наших веб серверов. Только мы стреляли яндекс танком с одной машины в другую. Ну и среди участников также были haskell и clojure.
Вот результаты по Responses Per Second

source Yandex.Tank response per second(ubuntu vm 8 cores)
target ubuntu vm 8 cores
golang fast http 30k+
nginx 20k
golang http 20k-
haskell wai warp 15k+
clojure http-kit 15k-
node.js 7k
rust hyper 10k+
rust iron 10k-
fsharp suave.io 4k+ (best result ever for .net web servers)
asp.net 5 kestrel coreclr/mono ??? 400-

В чистом итоге видно что golang fast http абсолютный лидер. Хотя изначально мы возлагали большие надежды на nginx с lua(openresty). Забавно что мы также уперлись в регексп в голанг и решили его просто через слайс по FindIndex.
Также интересно что я так и не решил проблему с fsharp там можно было поднять скорость через libuv. Но видать баг в suave и скорость упала. Кестрел еще сыроват но ребята вроде его уже почти допилили по скорости до нетти. бенчмарк.

По компиляции я не заметил разницы для голанг флагов go build -ldflags "-s -w". gccgo так и не удалось проверить.
Rust версия была скомпилирована не как релиз версия.
Haskell был скомпилирован с тредами и запущен +RTS -A4M -N8 -qg0 -qb -g1
HttpKit был запущен как java -server -Xms3072m -Xmx3072m -cp `lein classpath` clojure.main -m main
Я пробовал gccgo, у меня он с флагом fast оказался медленнее (на той же виртуалке, что и тесты) ~ на 20-25% =(
Rust версия была скомпилирована не как релиз версия

А какой смысл мерить код без оптимизаций?
Все было скомпилировано с оптимизациями за исключением Rust. Это обнаружилось уже после проведения тестов. Вторичный прогон уже был невозможен.
Класс! И еще забавно, что мы тоже использовали rust iron, который по итогу просто исключили за ненадобностью =)
divan0 тоже предложил fasthttp (и ребята из golang-russian slack) и наивный split – в понедельник обновлю пост, думаю, что fasthttp подтвердит ваш результат.
 Только сейчас заметил что таблица не включает nim и h2o. nim стандартная либа http дала 6к и h2o был в районе 10к.
Чтобы nginx не так сильно затормаживал обработку запросов его надо правильно настроить: gist.github.com/hgfischer/7965620

Сам недавно сталкивался с вопросом оптимизации nginx перед сервисом на Go. Без оптимизации Go напрямую показывал 39k rps, через nginx пролазило только 13k rps. После настройки как в статье по ссылке — nginx увеличил скорость до 32k rps.
мы используем практически идентичные настройки и нет нгинкс у нас медленней чем го фаст хттп а когда возишся с модулями тот там дело вообще не очень становится.
Ваши тесты показывают большую разницу между чистым запуском go fast http и go через nginx. Именно поэтому я и посоветовал посмотреть в сторону настроек nginx, чтобы сократить этот разрыв. Хотя общей картины, конечно, это не изменит.
Видать тут недопонимание, сравнение идет чистого go, go с библиотекой fast http и nginx. Под nginx понимается голый nginx с модулями который самодостаточен(OpenResty)
Прошу прощения, я думал это ответ на мой комментарий, а оказывается к статье.
Спасибо! Натыкался на этот бенчмарк во время наших тестов. Безусловно, можно ускорить nginx, но в контексте статьи производительность nginx не столь критична, так как все серверы находились в равных условиях.
gobwas может стоит сделать новый банчмарк с обновленными версиями языков программирования?
Sign up to leave a comment.