Как стать автором
Поиск
Написать публикацию
Обновить

Go for IT. Часть первая

Время на прочтение5 мин
Количество просмотров12K

Неуловимый Go.


Помните анекдот про неуловимого Джо? Именно восклицанием «Да кому он нужен!», прозвучавшим в форме вопроса "ЗАЧЕМ?", был встречен на Хабре релиз первой стабильной версии GO 1.

Именно на этот вопрос я хочу ответить циклом статей, оформленных в необычном для Хабра формате — в виде пошаговой совместной разработки действующего веб-проекта — с живым обсуждением и добавлением функционала. А чтобы вдвойне оправдать внесение цикла ещё и в хаб «Высокая производительность», мы поставим перед собой задачу создать не просто «хомяка», а проект, который наглядно продемонстрирует habri et orbi способность выдерживать значительные естественные нагрузки.

Вместо аперитива: реализация простейшего динамического веб-приложения на языке Go работает в 5-20 раз быстрее аналогичной Python-реализации. И всего в два раза уступает скорости отдачи статики Nginx-ом.

В рамках этого проекта, помимо самого языка Go, мы косвенно затронем и другие (относительно новые) технологии веб-разработки — HTML5, CSS3, Redis, MongoDB. Также я постараюсь вытащить из закутков долговременной памяти некоторые из трюков в области безопасности и экономии на спичках, коих накопилось много за полтора десятка лет работы в этой области. Устраивайтесь поудобнее, запасайтесь терпением и кофе — под катом «много букв», а ведь это только вводная часть :)

Прежде всего, хочу поблагодарить администрацию Хабра за быстрый отклик и создание хаба, посвящённому языку Go. Признание любимого предмета всегда приятно, так что именно появление такого хаба и возникший интерес аудитории побудил меня впервые за два года присутствия на Хабре «взять в руки шашки».

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

Goрдость и предубеждение

О вкусах, как известно, не спорят. Поэтому я вынужден оставить за кадром свои восклицания о прекрасном синтаксисе, простоте и изяществе языка Go. Меньше всего мне бы хотелось увидеть в комментариях очередную битву тупоконечников и остроконечников. Исходя из этого, предлагаю говорить исключительно о материях, подлежащих простому и понятному измерению. Но даже сравнивая цифры, мне придётся сравнивать с другими языками, что также может быть воспринято как casus belli. Долго думал как бы выкрутиться из этой щекотливой ситуации, и решение мне кажется вполне соломоновым. Сравнивать я буду с другим своим любимым языком, с Python. Такой подход, как мне кажется, избавит меня от обвинений в необъективности. Так и запишем, чёрным по белому и жирными буквами: я тоже люблю Python!

Не хочу я повторять и банальные абзацы из документации, описывая сам язык, его философию и возможности. Буду исходить из того, что вы уже заинтересовались и при этом способны самостоятельно прочесть документацию.

К барьеру, Goспода! К барьеру!

Начнём со сравнения, которым я запугивал вас в предыдущем параграфе. Напишем два примитивнейших динамических приложения, которые:

  1. запускают вебсервер
  2. имеют роутинг и обработчик
  3. берут из контекста переменную
  4. подставляют её в обработчике и выдают персонализированное приветствие Hello, %s.


Ничего сложного, но это уже не статичный контент, пусть и с некоторым лукавством. Я предвижу множество возражений на тему того, что главными тормозами всё равно останутся дисковые операции и работа с БД. И с этим я не спорю. Но давайте вспомним про анонсированное содержание статьи. До оптимизации i/o и db мы ещё доберёмся, а пока посмотрим на цифры чистой скорости ответов.

1. Код приложения для Webapp2.py — весьма простого и быстрого минифреймворка на базе Paste:

import webapp2
class Hello(webapp2.RequestHandler):
    def get(self, name):
        self.response.write('Hello, %s!' % name)
app = webapp2.WSGIApplication([
    ('/(\w+)', Hello),
], debug=False)
def main():
    from paste import httpserver
    httpserver.serve(app, host='127.0.0.1', port='8080')
if __name__ == '__main__':
    main()

Код запуска: python habr.py

2. Код на языке Go:
package main
import (
    "fmt"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}
func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

Код запуска:go run habr.go

Ничего сложного, верно? Обратите внимание, насколько прост и понятен код на Go, по крайней мере для столь простой задачи. Оба листинга показывают один и тот же алгоритм. Слушаем порт, направляем все GET /(*) обработчику, который превращает (*) в выводимое имя после Hello. Полагаю, код должен быть понятен всем, кто работал с такой схемой.

3. Для сравнения добавим ещё и nginx, отдающий статическую страницу с текстом «Hello, habr». Внимание! Nginx запущен с настройками «из коробки», идущими в пакете nginx-light. Запас для разгона остаётся огромным, но об этом поговорим позже.

4. Тестовый стенд (не поворачивается язык назвать это сервером) следующей конфигурации:
Lenovo B460E / RAM:2G / CPU: Celeron Dual-Core T3500 @2.10Ghz
OS: Lubuntu 12.04 x86, kernel: 3.2.0-20-generic

5. Замеры будем производить примитивнейшим образом, утилитой ab из apache2-utils. Если хотите, можете сами проверить с помощью siege или другого привычного инструмента.

6. Результаты забегов

Py @ ab -c10 -n1000 http://localhost:8080/habr
(при большем значении "-n" Python версия уже не справляется)
Time taken for tests: 0.987 seconds
Requests per second: 1012.67 [#/sec] (mean)

Go @ ab -c10 -n1000 http://localhost:8080/habr

Time taken for tests: 0.197 seconds
Requests per second: 5080.24 [#/sec] (mean)

Nginx @ ab -c10 -n1000 http://localhost/

Time taken for tests: 0.101 seconds
Requests per second: 9895.50 [#/sec] (mean)

Усложним задачу.

Py @ ab -c100 -n1000  http://localhost:8080/habr  

Time taken for tests: 1.045 seconds
Requests per second: 956.57 [#/sec] (mean)

Go @ ab -c100 -n1000: http://localhost:8080/habr

Time taken for tests: 0.199 seconds
Requests per second: 5021.14 [#/sec] (mean)

Nginx @ ab -c100 -n1000 http://localhost/

Time taken for tests: 0.110 seconds
Requests per second: 9054.77 [#/sec] (mean)

При "-c" >1000, python версия тест не проходит, Nginx держится огурцом, а вот Go «радует» совершенно непредсказуемыми результатами, показывая от 50 до 4000 requests per second. Объяснить этот феномен я не могу, поскольку столкнулся с ним впервые именно сегодня, на Ubuntu 12.04 и в версии Go 1. На ранних версиях (r60.3) Go держался стабильно. А может дело в ноутбуке, всё же комплектация явно не для HighLoad сервера :)

Подозреваю, что кого-то не устроит методика тестирования, настройки по умолчанию или отсутствие реализации на других языках. С удовольствием выслушаю ваши предложения и повторю тесты. Я прогнал много различных тестов и с разными настройками за два года существования (разработки) Go. И все тесты убедили меня в том, что Go является оптимальным инструментом для моего круга задач. Проводить и приводить их все — занятие неблагодарное, ведь всё равно опять окажутся недовольные.

Запрашивая веру на слово, приведу коротенькую выдержу по результатам из памяти.

Java иногда оказывается быстрее на 10-30%, но за счёт значительно большего потребления памяти (как самой VM, так и процессами). Опять же, приведённый пример (без использования фреймворков, только стандартные библиотеки) вполне наглядно демонстрируют минимум кода реализации. А чем меньше кода, тем меньше ошибок.

То же самое могу сказать о Net/Mono C# реализации.

C/C++ вне всяких сомнений позволяют создавать фантастически быстрые web-приложения с минимальными требованиями к ресурсам. Но сильно страдает скорость разработки.

Python и Ruby реализации проигрывают в скорости и создаваемой нагрузке приблизительно одинаково, PHP терпит сокрушительное поражение.

Анонс следующей части:
  • Разбираем по косточкам код из примера Hello, Habr!
  • Усложняем несколькими обработчиками
  • Компилируем и запихиваем несколько Go-серверов под Nginx.


Благодарю за внимание. Надеюсь, что хоть кто-нибудь осилил введение и нашёл для себя что-нибудь интересное.
С нетерпением жду дискуссии, желательно цивилизованной.
Теги:
Хабы:
Всего голосов 95: ↑86 и ↓9+77
Комментарии179

Публикации

Ближайшие события