Pull to refresh

Comments 57

а можно еще раз запустить бенчмарк, только с keep-alive'ом?
ab -k -c 200 -n 50000…
Не совсем понимаю значение, этого флага: если соединение остаётся поднятым сервер должен меньше работы выполнять?
Когда соединение остаётся открытым? Например если я установлю связь с сервером через websocket?

Прогнал такой тест: ab -k -c500 -n100000 http://localhost:8100/

dlang
Concurrency Level: 500
Time taken for tests: 1.654 seconds
Complete requests: 100000
Failed requests: 0
Keep-Alive requests: 100000
Total transferred: 35300000 bytes
HTML transferred: 18200000 bytes
Requests per second: 60450.25 [#/sec] (mean)
Time per request: 8.271 [ms] (mean)
Time per request: 0.017 [ms] (mean, across all concurrent requests)
Transfer rate: 20838.81 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.1 0 50
Processing: 0 8 14.0 2 178
Waiting: 0 8 14.0 2 178
Total: 0 8 14.6 2 178

Percentage of the requests served within a certain time (ms)
50% 2
66% 8
75% 14
80% 15
90% 19
95% 22
98% 32
99% 92
100% 178 (longest request)

golang
Concurrency Level: 500
Time taken for tests: 3.297 seconds
Complete requests: 100000
Failed requests: 0
Keep-Alive requests: 100000
Total transferred: 32300000 bytes
HTML transferred: 18200000 bytes
Requests per second: 30330.25 [#/sec] (mean)
Time per request: 16.485 [ms] (mean)
Time per request: 0.033 [ms] (mean, across all concurrent requests)
Transfer rate: 9567.06 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.0 0 45
Processing: 0 16 15.7 12 139
Waiting: 0 16 15.7 12 139
Total: 0 16 15.8 12 139

Percentage of the requests served within a certain time (ms)
50% 12
66% 18
75% 25
80% 28
90% 39
95% 48
98% 60
99% 68
100% 139 (longest request)



В этой ситуации D выигрывает в 2 раза.
А учитывая загрузку процессора, так совсем впереди


Слева D, справа Go
Без кипалайва тестировать не интересно — упираемся в скорость открытия соединения. Используется он почти всегда, это часть стандарта http 1.1, браузер открывает страницу, получается хтмл, а затем, через уже открытый коннекшен, запрашивает картинки, стили, скрипты, следующую страницу… ну и чтобы не упираться в одно соединение, браузер открывает несколько.

Похоже, пора переходить на wrk и увеличивать количество запросов, ab все равно не выдаст больше ~120к рпс
Можете попробовать Go1.7Beta2? В 1.7 используется новый компилятор и очень хорошо оптимизирована внутренняя библиотека в некоторых случаях код работает чуть ли не в 2 раза быстрее. Ну и GC стал оптимальнее. Шустрее алгоритмически, и меньше циклов CPU кушает в некоторых других моментах ожидания.

Как вы видимо уже сами поняли, без keepalive это превращается в тест обработчиков соединений.

Понекропощу
А вы думаете когда по рекламе залетает тонна посетителей они открывают 200 страниц подряд?
Кипалив это не правильно для тестирования динамики, перед беком стоит обычно какой-то сервер который статику отдает, он то и будет обратабывать все ваши «кипаливы».

Боюсь, здесь ситуация не про клиентов. Естественно, перед беком стоит балансировщик. Этот балансировщик лезет на сервер бека и мы имеем общение "балансер — бекенд". Здесь мы можем настроить все, как нам нужно.
И вот тут есть выбор "создавать новое соединение на каждый запрос" или "держать соединение и отправлять новые запросы в нем". В первом случае есть накладные расходы на установление соединения. Во втором случае — нет.
Когда у вас rps начинает исчисляться тысячами, это начинает чувствоваться. Ну и вылезают другие проблемы, например, на балансировщике могут кончиться порты для исходящих соединений. Поэтому желательно настраивать keepalive от балансировщика ко всем бекендам.

Аргументный аргумент, в таком виде согласен с кипаливом
может быть стоило увеличить время выполнения тестов? 4 секунды мне кажется маловато. и к тому же это получается сравнение производительности встроенных веб-серверов
4 секунды мало, потому что сборщик мусора не успевает включиться в бой?
А вторую часть не до конца понял. Веб-сервера не встроены ни в D ни в Go — это библиотечные реализации. В целом я их хотел их сравнить: кто шустрее, меньше памяти ест, процессор грузит. Или вы имели ввиду что ещё можно что-то сравнивать в производительности веб приложений? Я только начинаю этим заниматься, поэтому не знаю, какие ещё могут быть критерии.
4 секунды мало так как помимо ab у вас работают еще и другие приложения ( как я понимаю, тесты делались на десктопе), и они могли давать дополнительную нагрузку
а еще самое главное — замеров надо делать несколько и брать среднее от них.
библиотечные реализации

Исправлюсь — сравнение производительности библиотечных реализаций. Не знаю, пользуются ли библиотечными реализации веб-серверов Go и D в продакшине
Веб-сервера не встроены ни в D ни в Go — это библиотечные реализации

В go пакеты из стандартной библиотеки не всегда самые быстрые и функциональные. К примеру для websocket используют github.com/gorilla/websocket. Про быструю реализацию http уже написал @OlegFX
Ну тогда бы стоило смотреть на fasthttp для Go.
Ну тогда D будет в полных аутсайдерах, таки разница в производительности чуть ли не в 10 раз.

Извиняюсь, вы сравнивали скорость работы существенно разных шаблонизаторов или что-то ещё?

Мне кажется шаблонизатор тут малую роль играет, там очень мало кода (подставляется лишь 1 переменная в коротком шаблоне). Я всё-таки пытался сравнить именно работу остальной части приложений.

При таких "кажется" надо измерять. Ни там, ни там не используется кэширование шаблонов после парсинга, как оно рекомендуется ибо эта стадия обычно довольно дорогая, хотя в случае html/template может быть относительно дешевой относительно шаблонизатора vibe.d, который более-менее сопоставим с jade/slim по функциональности.

Если вас интересует именно скорость и память — попробуйте FastHTTP: github.com/valyala/fasthttp
Попробуйте вместе с ab использовать так же и wrk. Например: wrk -t100 -c500 -d30s http://127.0.0.1:8000/. С помощью wrk можно задать продолжительность тестирования, а так же написать на lua собственный сценарий.
В плане Go можно попробовать использовать: https://github.com/valyala/fasthttp, https://github.com/celrenheit/lion, https://github.com/labstack/echo
Потребление памяти и цпу в связке echo + fasthttp + quicktemplate должно быть ниже. Для REST-а можно заменить encoding/json на ffjson.
В Go 1.6 планировщик более оптимизирован. Если лень ставить руками, то можно использовать gvm (https://github.com/moovweb/gvm). Таким образом сравнить производительность в разных версиях языка.

Вы бы исходники выложили на гитхаб — я бы вам пулреквестов накидал :-)


vibe.d по умолчанию тянет с собой кучу мусора (всякие редисы, монги и прочий хлам), поэтому лучше явно указывать конкретные подмодули:


dependency "vibe-d:core" version="~>0.7.23"
dependency "vibe-d:diet" version="~>0.7.23"

import vibe.http.server;
import vibe.templ.diet;

Сравнение получается не совсем честным — реализация на го выдаёт чуть больше текста. Это не должно существенно сказываться на скорости, тем не менее нет смысла вносить лишнюю погрешность.


Кроме того diet шаблоны компилируются один раз при компиляции приложения. А го шаблоны судя по всему парсятся при каждом запросе — нужно кешировать результат парсинга.

Не думаю, что убрав так называемый «мусор» можно добиться хоть какого-нибудь прироста производительности, так как это влияет только на время компиляции, а не на работу приложения. Но на всякий случай измерил и ощутимой разницы не обнаружил (разница в пределах 5%, от запуска к запуску).

Насчёт больше/меньше текста: значение Document Length одинаково, оба приложения отдают 182 байта.

А вот по поводу шаблонов в го ничего сказать не могу. Может быть вы подскажите как реализовать «честное» сравнение?
В вашем примере:
у D — «Total transferred: 16450000 bytes»
у Go — «Total transferred: 14950000 bytes»
может быть Go какие-либо заголовки не передаёт или vibe.d что-то большее передаёт (как я понимаю у него много функционала из коробки, может быть стоит что-то отключить, если есть возможность)
Вынести парсинг шаблона на GO за пределы обработчика запросов

func main() {
t, _ := template.ParseFiles(«index.html»)
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
p := Page{Var:«hello habr»}
t.Execute(w, p)
});
http.ListenAndServe(":8100", nil);
}
Реквестирую замеры при использовании для D компиляторов LDC и GDC.
Результаты сборок с ldc и gdc практически не отличаются скоростью.
за что минус, я не понял. скомпилировал, сравнил, ответил на вопрос…
Вам не верят те, кто тоже компилировал свои проекты и сравнивал. Для веба действительно не так заметно, там больше libevent работает, но имеет смысл проводить более чистый эксперимент. В реальном коде будет что оптимизировать, и тогда выбор компилятора будет вносить существенный вклад.
И всё-таки хочется конкретных опций компилятора (inline, O3, nobounds-check вкл или выкл).
P.S. минус не мой, не подумайте.
я не против минусов, только когда я понимаю за что
по сути вы правы, надо было приводить все параметры
все 3 варианта собирались с помощью dub --build=release

ps: а насчёт libevent я добавил в текст статьи ещё когда проверял сборки с ldc и gdc
Вот что я искал, перед тем как писать эту статью…
Нашёл один момент
vibe 0.7.28 вышел 27 февраля (hot fix версия), а этот тест производился 25 февраля
возможно эти 2 бага сильно влияли на производительность

Баги влияли на производительность в положительную сторону?

https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/D/vibed

The tests were run with:

Vibe.D v0.7.19

P.S. а в самих файлах в зависимостях 0.7.28
UFO just landed and posted this here
Он прост как пробка. Там нечего развивать.
тут первый комментарий, второй пункт, хотя, возможно, чисто субъективное мнение отвечающего, я подумал, что так и обстоят дела
Ваша информация устарела лет на пять.

gizmo, go-micro, gocircuit, h2, Kite, Beego, Gin, Goji, Gorilla, Martini, Negroni, Revel, echo
Ваш тест, как минимум не корректный.

Собрать Ваш код на D не удалось. (та и время тратить не хотел)

Проведя тест(test1.go) на среднестатистическом сервере, у меня получилось ~16970.795 rps

Первое что бросается в глаза — отсутствие url роутера.
Без роутера(test2.go) получаем +~88.51 rps.

Во время сборки кода на D, заметил интересную строку: Compiling diet template 'index.dt'…
Будем считать, что D загружает шаблон в память.
Третей тест (test3.go) показывает ~55588.8625 rps, что дает ~+38618 rps

Исходя из Ваших тестов, возьмем среднепальцеве число производительности кода D в 17000 rps.
Если этот код на D загружает все в память, то этот тест показывает, на сколько в хлам GO разбивает производительность D. Это выглядит как 17000 vs 55000 rps

Сам код: github.com/vitalvas/go-benchmark
Правильно ли я понял, что Вы сейчас прооперировали среднепальцевыми значениями, даже не запустив код (ни мой, ни тот, корректный, который Вы написали)?
Не правильно. Не запускал только код на D.
На Go запускал как и Ваш, так и свой. Результаты тестов в репозиторию

Хотя теоретически D — должен работать быстрее GO.
В go пожертвовали некоторою производительностью для простоты.
Прошу заметить, что я не пытался сделать максимально производительный или правильный код, а пытался сделать эквивалентный (в силу своих познаний) код на двух разных языках.

Хотя теоретически D — должен работать быстрее GO.

мне хотелось поднять вопрос не «кто быстрее в целом» (который я для других языков уже пытался поднять), а именно для веб… и тут, по всей видимости, компилятор и язык не будут играть большой роли, а будут играть: подход к сборке мусора, архитектура библиотеки (в vibe радуют compile-time шаблоны страниц), алгоритмы роутинга и тд

Хотелось проверить всё в целом, в сумме (кроме работы с базой данных). На самом деле я думал D проиграет в веб значительно, просто было интересно во сколько раз, но оказалось не всё так просто.

Для тех, кто всё же захочет собрать код на D, последовательность действий такова:


  1. Создаём проект на VibeD: dub init go-vs-d vibe.d
  2. Для студии можем сгенерить солюшен: dub generate visuald
  3. Исходники помещаем в source/app.d
  4. Шаблоны в views/
  5. Билдим и запускаем: dub --build=release
Когда речь идёт о сравнении языков по скорости работы, это напоминает сравнение машин по глубине протектора — ну хорошо, у кого-то на 2см длиннее, что это даёт?? (кроме чувства «я пишу на лучшем языке») На мой взгляд, сравнение должно идти в совсем других плоскостях:
1. Начинаем сравнивать только когда выявлены реально важные критерии. Например, где-то важно потребление памяти, где-то — поддерживаемость или «интуитивная понятность» (напр. у VBScript). Критерии «от балды» — не интересны, особенно когда сравнивают МИКРОсекунды в вебе, где страницу можно ждать секундами! К чему там скорость??
2. До сих пор один из важных критериев языков — поддерживаемость, которая вытекает из простоты и выразительная мощность, которая должна соблюдать баланс с простотой. Писать на очень простом языке — нудно (спросите джабистов), на оч выразительном — мозг вывихнешь (любители Хаскеля не поняли вопроса :) ). Мне кажется, у D в этом плане хороший баланс — море простых конструкций, одновременно с мощной библиотекой.

Поэтому «для веба» я бы сразу взял Ди и критерием была бы быстрота написания и понятность кода. Веб — это не место для экономии микросекунд или, ещё смешнее, экономия килобайт в ГИГАБАЙТОВЫХ серверах. Есть нагрузка — почти всегда дешевле «оптимизировать вширь железом», чем насиловать программиста «ну ещё пару мегабайт!». Особенно зная, что есть не так много разных способов написания алгоритма или использования библиотеки (т.е. не всегда есть возможность что-то вообще выжать).
Веб — это не место для экономии микросекунд

Вы хоть одно нагруженное приложение в жизни писали?
А давайте вы перейдёте от подростковых переходов на личности сразу к аргументам? Расскажите мне о нагрузках типичного форума (а-ля RSDN) и удивите какой-нибудь 50-блэйдовой фермой на ксеонах!
Неспособность ответить на прямо поставленный короткий вопрос как раз и выдает подростковое мышление.

Я не могу рассказывать о нагрузках типичного форума а-ля rsdn, потому что не имею отношения к разработке типичных форумов а-ля rdsn. Зато имею отношение к разработке нескольких продуктов с нагрузками в тысячи и десятки тысяч запросов в секунду. И не по наслышке знаю, как сэкономленные где-нибудь в дальнем углу кода 10-20 миллисекунд могут сэкономить десяток тысяч долларов в месяц на железе.

Поскольку мне было интересно, откуда взялось ваше утверждение, я задал простой вопрос — «Вы хоть одно нагруженное приложение в жизни писали?». Он короткий и не несёт в себе никаких эмоций.

Как я могу предположить теперь — нет, не писали. А если я прав (если я прав) — получается, в предмете вы ни черта не понимаете, о чём говорите — не знаете, но Веское Мнение имеете.

П — Профессионализм.
Ну я писал приложения где нужно экономить каждый такт.
И должен вам сказать — это такая страшная редкость.
И если уж тестировать Go на возможность написания именно таких приложений, то тестировать грамотно — используя fasthttp.
Посмотрите лучше на Ж — пиЖонство. Каким-то чудом вы попали в один-на-миллион высоконагруженный проект и уже готовы лопнуть от тщеславия, тыкая всем какие они «непросвещённые». Ну хорошо, оставайтесь при своём высокомерии, экономьте микросекунды и упивайтесь ассемблером — говорить с вами как с человеком нет никакого желания.
Жаль, ведь вы были прекрасным собеседником. Умудряетесь в буквах видеть эмоции — подростковые выпады, высокомерие, пижонство, — я в восторге.

Я иной раз думаю всякое. Вот как так получается, что Microsoft Word, который в 1999 году работал на 486м процессоре, влезая в 16 мегабайт памяти, сейчас отжирает половину ресурсов и еле ворочается на восьмиядерном ксеоне? Что за индус мог написать калькулятор для убунты, который для своей работы тянет сотню пакетов ради красивой отрисовки кнопочек? Какая такая волшебная сила превращает танчики, которые работали на денди, в многомегабайтного монстра, за полчаса высасывающего батарейку на топовом смартфоне? Что за мировой заговор новостных сайтов, которые состоят из текста и картинок и при этом отжирают по гигабайту в браузере?

И периодически убеждаюсь, что нет ни чудес, ни волшебства, ни индусов, ни масонского заговора. Есть лишь Правильные программисты, которые презирают всяких пижонов, заботящихся о производительности своих продуктов. Правильным программистам не нужны бенчмарки. Им не надо знать, что быстрее в конкретной задаче — D, Go, плюсы или вообще пхп. Это всё вторично.

Скорость работы везде и особенно в вебе — для пижонов. Ведь если вы пишете не один-на-миллион поисковик/соцсеть/биллинг, а сайт «Сады и парки Норильска», то можно это делать спустя рукава и как-нибудь. А когда всё начинает тупить — так это не кодер неподходящий инструмент выбрал, это хостер кривой. Голову включать не надо, надо масштабироваться железом.

Аминь.
Этот глупый вопрос я задаю в каждом посте про любые бенчмарки:

Вы убедились, что частота процессора не менялась на протяжении всех тестов?
непонятно почему
t, _ := template.ParseFiles("index.html")
пересоздается на каждый запрос. Разве вы так будете писать в реальном проекте? А если нет, то зачем такое мерять?
В Go на FastHTTP я получал около 170к запросов в секунду на Xeon E5620 при практически 100% загрузке всех ядер. А данный бенчмарк считаю некорректным по многим причинам, часть которых озвучена выше — абсолютно неинформативно.
По поводу памяти… не знаю как vibe-d ею управляет(вполне возможно что там полностью своё упроавление) но стандартный GC может быть ограничен в своих аппетитах. Детали тут:
https://dlang.org/spec/garbage.html
«планировщик заданий в Go устроен лучше — сразу распределяет нагрузку на ядра поровну»

Это неверное утверждение. Вопрос раскидывания файберов по ядрам очень сложный и на сегодняшний день я скорее считаю, что правильнее, когда планировщик загружает ядра ближе к 85%, оставляя свободные ядра.

Это дает возможность линуксу запустить что-то ещё на сервере.
Sign up to leave a comment.

Articles