Go: Два года в продакшне

в 4:58, , рубрики: golang, performance

Я хотел бы поделиться нашим опытом использования Go в течение двух лет в продакшне Iron.io. Мы одна из первых компаний, ставших использовать Go (golang) в высоконагруженных сервисах. Когда в Iron.io было принято решение об использовании этого языка, мы не знали, чего ожидать в долгосрочной перспективе, но до сих пор все идет отлично.

Я уже немного писал об этом в предыдущем посте о переходе на Go с Ruby. Но сейчас мне хотелось бы поговорить о конкретных вещах, за которые мы любим этот язык, о которых узнали во время его использования. Вот они в произвольном порядке:

  • Производительность
  • Память
  • Параллельные вычисления
  • Надежность
  • Развертывание
  • Талантливые специалисты

Производительность

Когда мы в Iron.io впервые принимали решение о том, какой язык будем использовать, то сперва провели некоторое исследование и написали тесты для нашего продукта — очереди сообщений. Я написал частичный клон beanstalkd на Go, который использовал протокол beanstalkd так, что можно было использовать существующие клиенты для его проверки. Тесты показали высокую производительность, почти такую же, как у официальной версии на С. А как приятное дополнение — на Go было удивительно легко писать.

Вы можете найти критерии сравнения Go с другими языками на сайте Computer Language Benchmarks Game. Приведенный ниже график сравнивает его с Java (который, вероятно, был бы языком, коим бы мы пользовались, если бы не было Go):

Go: Два года в продакшне

Это график показывает, что Go немного быстрее в некоторых случаях, но в общем проигрывает Java. Тем не менее, это не так уж плохо для языка, которому всего несколько лет. Я не сомневаюсь, что он догонит конкурентов через некоторое время. Вы также можете видеть, что объем используемой памяти значительно меньший.

Просто интереса ради сравните различия между Go и Ruby ниже. Go превосходит Ruby по производительности и использованию памяти.
Go: Два года в продакшне

За два года Go никогда не был узким местом в наших продуктах, это всегда была база данных.

Память

Так как в Go нет виртуальной машины или интерпретатора, он запускается быстро и использует малый объем памяти. IronMQ начинает работать примерно с 6,5 кб резидентной памяти, включая загрузку конфигурации, создание соединений и т.д. После того как он проработает некоторое время, потребление памяти увеличивается, в основном за счет кэширования. Прямо сейчас наши продакшн-серверы работают используя около 400 МБ (я понимаю, что данное сравнение может быть неуместно в контексте вашего приложения).

За два года у нас никогда не было утечки памяти или проблем, связанных с памятью.

Параллельные вычисления

Параллелизм является чрезвычайно важной частью Go, а разнообразные высокоуровневые абстракции позволяют его легко использовать. Я использовал Java в течение многих лет и чуствовал себя очень комфортно с пакетом java.util.concurrency, который предоставляет довольно неплохой набор инструментов для параллелизации, но это совсем не то же самое, что есть в Go, по своей простоте базовой реализации. Go имеет goroutines для параллельных операций и каналы связи между ними. Goroutines особенно интересны:

“Goroutines являются частью того, что упрощает использование параллелизации. Существовавшая в течении долгого времени идея — это множество независимо выполняемых функций-сопрограмм на множестве потоков. Когда сопрограмма блокируется, например, через вызов блокирующего системного вызова, среда выполнения автоматически перемещает другие сопрограммы в том же потоке операционной системы на другой выполняемый поток, чтобы они не были заблокированы. Программист не видит ничего из этого, что является явным преимуществом. В результате мы получаем goroutines. Они легковесные, и при отсутствии больших временых затрат на длительные системные вызовы будут стоить немногим больше памяти для стека, который помещается всего в несколько килобайт. Для того, чтобы стеки были небольшими, Go во время выполнения использует сегментированные стеки. Новоиспеченной goroutine дается несколько килобайт, которых почти всегда бывает достаточно. В противном случае во время выполнения автоматически осуществляется расширение сегментов. Накладные расходы в среднем около трех простых инструкций за вызов функции. Целесообразно создать сотни тысяч goroutines в том же адресном пространстве. Если бы goroutines были просто потоками, системные ресурсы заканчивались бы гораздо быстрее. " Источник

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

Надежность

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

Я также склоняюсь к мысли, что наш код имеет более высокое качество только в связи с тем, что он написан на Go. Я не могу точно сказать почему, но при взгляде на код IronMQ он мне кажется “теплым и ламповым”. Быть может, дело в очень строгом компиляторе, который заставляет нас удалять импорты и неиспользуемые переменные. Быть может, это связано с тем, что порой достаточно написать небольшой кусочек кода для решения большой задачи. Вероятно, я в скором времени пойму в чем тут суть и поделюсь подробностями с аудиторией.

Развертывание

Go компилируется в один статический бинарный файл. Развертывание — это просто загрузка файл на сервер и его запуск. Не требуется установка дополнительных зависимостей. Нет среды выполнения программы (вам не нужно устанавливать Go на сервере). Исполняемый файл небольшой — размер IronMQ составляет ~ 6 Мб.

Откат

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

Талантливые специалисты

Два года назад мы взяли на себя большой риск, выбирая Go — тогда было мало людей, которые знали язык. Мы были первой компанией, которая опубликовала вакансию в рассылке golang, и мы были озадачены квалификацией откликнувшихся людей. Нами были получены заявки от разработчиков с огромным опытом из лучших технологических компаний, другие имели степени кандидатов наук, третьи работали над действительно хардкорными проектами. Большинство из них не были full-time Go разработчиками, но проработали с ним достаточно, чтобы получить опыт и желание поделиться своими знаниями. Я не уверен, имело ли значение то, что мы пытаемся создать, или они просто хотели работать с Go.

Наш первый Go программист Evan Shaw, который работает с нами до сих пор, является одним из разработчиков Golang.

Заключение

После двух лет работы с Go могу я с уверенностью сказать, что мы сделали правильный выбор. Если бы мы начали Iron.io сегодня, все равно Go был бы лучшим вариантом. Многие другие компании используют его сейчас, в том числе Google и Heroku. Схожее мнение высказывает и + Rob Pike, один из создателей Go:

«Мы поняли, что программное обеспечение, которое мы строим в Google, не всегда хорошо обслуживается имеющимися в наличии языками. Robert Griesemer, Ken Thompson и я решили сделать язык, максимально подходящий для написания программ, которые мы разрабатываем в Google».

Derek Collison, основатель Apcera, заявил недавно в статье для Wired:

«Какие управляющие слои и слои инфраструктуры новейших технологий будут использоваться для обеспечения функционирования облачных сервисов? В течение двух лет большинство из них будет написано на Go».

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

Автор: rkononov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js