Си или Go для приложения по обработке сетевого трафика до 1.5М пакетов/с?
Планируется проект по обработке сетевого трафика. Основная суть - взять сырой поток пакетов сетевой карты и извлечь из него различную статистику и метаинформацию. Далее это статистику надо сжать и отправить на сервер. Поток пакетов на входе до 1.5 миллионов пакетов/с.
Дополнительные требования - утилита должна поставляться в виде одного бинарного файла, поддержка x86 и ARM.
Первая мысль, которая меня посетила - это реализация на C/C++, основная причина - добиться высокой производительности даже на слабом/среднем железе.
Несколько знакомых посоветовали приглядеться к Go, мол всем твоим требованиям отвечает, но разработка на Go должна получиться лучше/проще.
Поизучал материалы по Go и не смог сформировать однозначного ответа по Go. Особенно смущает вопрос, не будет ли проигрыша в скорости работы.
Что можно почитать толкового относительно скорости С/C++ vs Go?
Роман Мирр: что по вашему надо написать то ?
топик стартеру надо одну простую прогу, а тут надо целых две , то есть в два раза больше, чтобы сравнить скорость, каких то супер запросов у него нет, простой парсинг пакетов тут можно вообще сделать как делает кнокд и получить дичайшую производительность, ну а спарсить заголовки дело плевое и все равно писать.
К сожалению, как правильно подметил Роман Мирр , ничего общего с реальностью не получится. Дело не только в IO, но сбор статистики тоже не самый простой получается и ресурсов кушает.
И сделали уже пару прототипов - но никакого очевидного результата не получилось. Прототип же не учитывает множества моментов, из которых какой-нибуть вполне вероятно можем стать узким местом.
разумный компромис между надёжностью и производительностью. Касательно доводов против из-за производительности по сравнению с Си: всё зависит от структур данных, алгоритмов и их оптимизации для железа.
простота разработки и отладки
хорошая поддержка, наличие большого количества проектов и документация
с интеграцией проблем быть не должно - записать файл-бинарник не проблема
в долгосрочном плане может быть выигрыш при поддержке кода
Из недостатков выбора Go:
Нужно время на знакомство и эксперименты
Сразу хорошо написать не получится из-за пункта 1. Возможно, понадобится переписывать некоторые части или всю архитектуру программы пока не получится нужный результат.
Языки программирования: скорость
По качеству сгенерированного нативного кода можно ожидать, что Go будет раз до 2-х (всего!) медленнее, но в плюсах получите а). скорость проектирования + б). возможность очень эффективного распараллеливания работы.
См. также Go конспект.
abcyu:
Это как с компилятором Clang в сравнении с GCC: авторы Clang уверяют, что в этой реализации есть невиданные перспективы для оптимизации кода, из-за общих подходов проекта LLVM.
А экспериментальная проверка показывает, что тот же код, откомпилированный Clang до несколько раз медленнее, чем после GCC.
Василий:
ну и что, что "отвечал на пост"?
там сложно судить, потому что всё зависит от реализации, но Go уступает C в несколько раз по скорости (хотя совершенно непонятно, почему у них C++ должен уступать C ? это у них ... "артефакт реализации"? ... то, что называют "через жопу"? ;-) )
Олег Цилюрик: в коментариях исходников С программы сказано что основано на программе С++ конечно можно посмотреть исходники и поискать разницу в реализации, но сдаётся что тут и компилятор не последнюю роль играет
ЗЫ лично у меня был случай как парочка нопов воткнутых перед условным переходном поднимала скорость программы с тех пор я понял что ничего не понимаю.
Для обработки сетевого трафика больше подойдёт модуль ядра Linux написанный на Си. Если кто-то умеет такое делать на Golang - дайте знать, с удовольствием послушаю, почитаю на эту тему... Агрегированные же данные (прилетающие от такого модуля) вполне хорошо обрабатывать на Golang (в этом случае можно не заморачиваться одной железкой, а поставить сразу несколько распределив по ним трафик).
P.S. Возможно речь идёт не о linux, но в топике это как-то отдельно не оговаривалось.
Согласен с вами. Но вот в ядро влезать совсем не хочется, неблагодарное это дело. По ссылке от 31415 есть список готовых и работающих решений для реализации задачи через юзерспэйс.
insekt: юзерспейс по определению медленней для таких операций, потому что происходит как минимум 1 или даже два (не помню точно) обязательных копирований из пространства ядра и обратно.
Можно ведь сделать модуль который подгружается динамически, без перекомпиляции ядра - вполне себе решение. Агрегировать данные и отправлять их уже дальше в юзерспейс для последующей бизнес-обработки.
В общем удачи с решением, расскажите что и как делали:)
Посмотрите на проекты pf_ring, snabb switch, netmap - они предназначены для работы с сетевой картой напрямую, пакеты захватываются напрямую из сетевой карты, ядро вообще исключается из процесса и не имеет доступа к сетевой карте.
insekt: интересное замечание, спасибо. Обязательно посмотрю когда буду работать с сетевым стеком поближе. На самом деле иногда про FPGA читаю, но на практике пока нет подходящих проектов.
конечно, Си. Потому что придется всю обработку держать в kernel space, возможно, использовать DPDK. Переключения контекста kernel - user сожрут весь CPU на потоке 1.5 Мппс.
А на других языках кернел-модули писать, вроде, не получается.
На гоу быстрее напишите программу. очевидно что читать ничего не надо чтобы понимать что тормознее работать будет, значительно больше исполняемый файл весить будет.
Go достаточно шустрый язык а в рамках этой задачи мы упираемся в работу с I/O. В Go с его горутинами можно легко и просто распаралелить это дело. На Си же файберы и прочее это сложно, а с потоками мы можем потерять чутка производительности за счет переключения контекста.
insekt: мм, не могу ответить на этот вопрос пожалуй. 1.5 миллионов пакетов в секунду это довольно много. Я бы на шавем месте исходил из простого, можно быстро написать на Go прототип (в минимальные сроки) и замерять производительность. Если все ок - оставаться с этим. Если нет - смотреть на более низкоуровневые решения.
1.5 миллионов пакетов ... это еще и от размера пакета зависит. Если взять по максимальному MTU (1500) это уже будет порядка 2Gb/s
Я к тому что 2 гигабита в секунду это много но не очень. Чисто теоритически решения вроде netmap удобны когда у вас надо обрабатывать потоки в 10+ гигабит в секунду. На таких объемах я бы сразу смотрел на Си и на netmap.
Очевидно, что Вы ВООБЩЕ НИЧЕГО НЕ ЗНАЕТЕ о Go.
Большой размер файла - это то, на что спотыкаются НОВИЧКИ даже еще не прочитавшие FAQ.
Размер файла Go - это банальная полная статическая компоновка, возможная и с С/С++, это упрощение deploy, минимум зависимостей от системных библиотек. Это осознанное решение разработчиков языка.
При этом ничто не мешает откомпилировать программу, написанную на Go, с использованием динамической компоновки. Она станет примерно такой же мелкой как и обычная программа на С/С++. И получит те же проблемы с "адом зависимостей", что и типичная программа на С/С++.
insekt: Ответ был иным. Если JIT способен выдать 35Mpps, то уж у нативно компилируемых языков вообще не должно быть проблем на уровне самого языка.
Проблема может быть только на уровне реализации конкретного софта.