пятница, 23 ноября 2012 г.

Go(golang) vs PHP по взрослому

      Я давно хотел устроить сравнение скорости Go и PHP на какой-нибудь реальной задаче  и в условиях близких к боевым. Интернеты кишат синтетическими тестами - например  вычисление квадратных корней в милион потоков  - причем эти тесты чаще всего выполняются на ноутбуке. 
    Итак, есть реальная задача - backend для автосаджеста городов. На вход передается набранная строка - возвращается список возможных городов в JSON. Сами города находятся в sphinx, в количестве 30 тысяч. 
Что с чем сравниваем:
    Текущая реализация написана на PHP c использованием фреймворка Yii. Состоит буквально из 10 строчек, 5 из которых комментарии. Естественно используется opcode cacher.  
   Go реализация занимает чуть побольше - 35 строчек кода. Тестировалось 2 варианта FastCGI и HTTP. Различаются они фактически только подключаемой библиотекой - "net/http" или "net/http/fcgi".  Забегая вперед сразу скажу - разница между этими реализациями лежит в пределах погрешности - менее 1 сотой секунды.
    На чем собственно проводилось тестирование: PHP реализация была разложена на 2-х фронтах(Intel Xeon 8CPU/32GB RAM/Ubuntu 12.xx).  Go реализация была разложена только на одном фронте - потому как деплойный скрипт написан именно под PHP, а раскидывать ручками больше чем на один сервер было лень.
       Как тестировалось: был сгенерирован список URL для siege, состоящий примерно из 250 тысяч различных запросов к автосаджестеру. siege запускался с одного из фронтов - чтобы не учитывать сетевые задержки. Тестировалось с 30, 40 и 50 одновременных соединений.
        Итак результаты:
При 30 одновременных соединениях
Среднее время ответа: PHP - 0.36 секунд, Go - 0.01 секунда.
Самая длинная транзакция: PHP 12.04 секунды, Go - 5.02 секунд.
Самая короткая транзакция: PHP 0.02 секунды, Go - 0.00 секунд.

При 40 одновременных соединениях
Среднее время ответа: PHP - 0.65 секунд, Go - 0.09 секунд.

При 50 одновременных соединениях
Среднее время ответа: PHP - 0.96 секунд, Go - 0.22 секунд.

Выводы:
1. Переписывание на Go данной задачи выглядит более чем оправдано.  
2. При увеличении числа одновременных подключений разница между GO и PHP сильно сокращается. Объяснение этому одно - начинает засасывать sphinx - который запущен только на одном сервере. Также на это повлияло то что siege был запущен на одном из фронтов. 

Также я сравнивал варианты когда обращение идет к Go серверу напрямую и через Nginx: результат порадовал - среднее время ответа различается буквально на 0.01-0.02 секунды. Что в общем еще раз доказывает что проксирование через Nginx работает очень быстро.

Еще я проводил сравнение при разных GOMAXPROCS: результат фактически не изменился. Чего собственно и следовало ожидать в данных условиях.