Алексей Найденов, генеральный директор ITooLabs , рассказывает о разработке телекоммуникационной платформы для операторов связи на языке программирования Go (Golang).
Также Алексей делится опытом развертывания и эксплуатации платформы в одном из крупнейших азиатских операторов связи, который использовал платформу для предоставления услуг голосовой почты (VoiceMail) и Виртуальной АТС (Cloud PBX).
Алексей Найденов.
ITooLabs. Кейс разработки на телефонной платформе Go (Golang).
Часть 1
Перейти: каналы
Понятно, что при параллельном выполнении необходимы средства синхронизации.Go предоставляет все необходимые инструменты синхронизации: мьютексы, разделяемую память.
Но его стандартный механизм — каналы.
Канал можно рассматривать как однонаправленную типизированную очередь из n элементов (по умолчанию — 1).
Сам канал может быть параметром, членом структуры.
Причем канал можно передавать по каналу — и этот канал будет иметь тип «канал каналов такого-то типа».
Что делает этот пример из 20 строк? Это счетчик http-вызовов.
Он просто подсчитывает, где запускается http-сервер, и показывает, сколько раз к этому серверу обращались.
Как это обычно делается? Обычно вы создаете переменную, помещаете ее в мьютекс и увеличиваете ее.
Или вы создаете атомарную переменную и увеличиваете ее атомарно.
В Го все по-другому.
Разработчик, попробовав это на Go, очень быстро начинает писать именно так.
В Go вы запускаете горутинную функцию count (8-я строка) и go count (17-я строка); сделать переменную; а потом просто увеличиваешь локальную переменную — в канал начинает отправляться следующее число.
Те из вас, кто помнил генераторы скриптов Atmos, конечно, будут правы, но в Go каналы допускают гораздо более широкое использование.
Перейти: выбрать
Наконец, есть оператор Select, который позволяет выбирать сразу из нескольких каналов.
Это типичный шаблон в Go для прекращения выполнения горутины:
Вы передаете два канала.
В один канал идут запросы, а в другой – сигналы о том, что пора заканчивать.
Перейти: C API (CGO)
Для нас, как разработчиков платформы телефонии, было важно, чтобы у Go был C API, который позволяет писать некоторые кусочки на C прямо в коде Go, который потом нормально компилируется, нормально компонуется и потом нормально работает.То есть вы можете получить доступ ко всем библиотекам C, которые есть в вашей операционной системе.
В то же время они также будут связаны статически.
Перейти: инструменты
Инструментарий Go — еще одна причина, по которой людям он нравится.Все делается с помощью одной команды — (идти).
Существует команда go build, которая выполняет сборку, и команда go test, которая запускает специальные функции тестирования, описанные в конкретном пакете.
Существует команда go run, которая запускается и строит немедленно.
Есть команда, которая обновляет зависимости (go get).
Есть такие, которые форматируют исходники: go fmt - у нас это, например, на пушах.
Больше нет споров о том, где, как и какой стиль форматирования мы используем — табуляция или пробел: есть команда go fmt, есть определенный стиль, который она форматирует, и споров нет. Не нравится что-то? Запустите go fmt - все будет как надо.
Команда go doc позволяет читать документацию и отображать ее в формате html. Существует инструмент go pprof для профилирования, генератор синтаксического анализа (gotool yacc) и многое другое.
Короче говоря, инструменты Go очень продвинуты для такого молодого языка.
Многие идеи в нем были не то чтобы новаторскими, но очень интересными, которые позже были перенесены в другие системы — например, тот же Goget и возможность указывать в качестве имени пакета прямой репозиторий.
Перейти: IDE
В целом я предпочитаю Emacs. Если здесь есть любители, мы можем подраться позже.
Но для разработки я предпочитаю «взрослую» IDE:
Я перепробовал их все, включая VIM. Могу сказать, что на данный момент самая крутая IDE — это обычная, какая-нибудь IDEA Edition с плагином для Go. Лучшее! Я рекомендую.
Если кто-то собирается его использовать, он должен начать сразу и не мучиться.
Перейти: библиотеки
Библиотеки – это был еще один очень и очень приятный сюрприз, потому что буквально каждый раз, когда мы чихали, мы сразу что-то находили.Даже когда нам понадобился интерпретатор Javascript, мы думали, что придется писать его самим — мы его только нашли, он уже существовал.
На данный момент в Git зарегистрировано более 35 тысяч различных репозиториев, имеющих хотя бы одну звезду.
Могу повторить свою мысль: есть наши библиотеки и другие, и есть множество компаний, которые открывают какие-то свои внутренние библиотеки.
В общем, я не могу вспомнить момент, когда мне что-то понадобилось и я не сразу нашел это на GitHub (в случае с Go).
Перейти: эксплуатация
«Эксплуатация — это мечта, особенно для тех, кто, например, работал с Java.- Статическая сборка.
Никаких зависимостей во время выполнения!
- Единственный двоичный файл.
Вплоть до того, что у нас в платформе есть еще один компонент: медиапроцессор, который мы написали на C++ просто потому, что там не так важна скорость разработки, как скорость выполнения.
Никаких сборщиков мусора! Но в итоге мы тоже стали собирать его со статикой, потому что убедились, насколько это удобно.
- Никаких зависимостей – вам просто не нужно об этом думать.
В остальном опыт эксплуатации какой-либо крупной системы вам здесь очень поможет.
- При падении остаются следы стека.
Но они нужны довольно редко.
Перейти: сообщество
Сообщество также победило в этом.Сообщество Go удивительное и восходящая звезда.
К сожалению, информации на слайде мало и ее не видно: слева — репозиторий на GitHub, справа — теги Stack Overflow:
Если вы посмотрите на Go, то увидите, что он находится в компании языков, которые в пять раз старше его!
Go против Node.js
Боевой! Давайте сравним, например, с Node.js. На самом деле вы можете сравнить это с чем угодно.Но почему с Node? Я предполагаю, что Google планировал, что Go вытеснит Java и составит конкуренцию Java. Не совсем.
Основным конкурентом Go оказались Node.js, Python и интерпретируемые языки.
Почему? Потому что в Go за счет вывода типов, за счет множества мелких деталей (типа команды go run) возникает ощущение интерпретируемого языка, то есть легкого языка, на котором можно делать макеты, быстро строить и прототипировать что-то.
.
Но при этом он действительно работает: действительно быстро компилируется, запускается и работает.
Здесь у нас есть два простых сервера — и http, и http:
Разница.
- Он компилируется на Go, интерпретируется в Node.js. Запустил и он сразу работает (ну и там тоже).
- В Go много потоков (столько, сколько процессоров в машине).
В Node.js, как вы знаете, есть один поток (если вам нужно много потоков, запустите кластер).
- Теперь начинаем усложнять логику — усложняем ее в Handler. В Go ничего не усложняешь, просто берешь и делаешь так, как написал линейную программу, которая блокирует (отправляет запрос в базу данных — рассчитывает — отправляет ответ клиенту).
- А в Node.js сразу возникают вопросы.
Что вы теперь будете использовать — коллбэки, промисы, Q, async.js или новомодный доходность?
Идите: недостатки?
Да, вполне!- Нет параметризованного полиморфизма, шаблонов, дженериков.
Есть только специальные операции для работы с массивом, массивами и ассоциативными массивами.
Все остальное отсутствует.
- Отладчика до сих пор нет. Не то чтобы оно не нужно, но его там нет.
- Провоцирует стиль вырезания и вставки.
Если вы пишете на Go достаточно долго, вы обнаружите, что просто берете куски кода и вставляете их — это нормально.
Вы раздражены тем, что это нормально.
- Строго диктует правила, в том числе форматирование.
Я, например, очень люблю Haskell, пишу на нем много домашних проектов для себя, есть простор для фантазии.
В Го — нет! У вас всегда есть только один, простой и понятный способ что-то сделать.
- Отступление в сторону начинает выглядеть таким извращением, что вы просто не можете заставить себя это сделать.
Поэтому нет воображения – надо сосредоточиться на задаче.
- Никаких исключений.
Паника/восстановление есть, но их нельзя использовать для контроля.
- Очень простой синтаксис, который иногда начинает бесить (потом привыкаешь).
- Здесь нет места фантазии – слишком просто!
Зачем вообще идти?
Может из-за быстрой сборки или из-за развертывания одним бинарником? За счет конкуренции или эффективного использования железа? Может быть, потому, что он быстро растёт, или из-за классного сообщества? Я долго пытался ответить для себя на этот вопрос.
В конце концов я понял: нет, ни одна из этих причин! Все гораздо проще: Go работает.
Go — чрезвычайно практичный язык для инженеров.
Для инженеров, которые занимаются разработкой веб-сервисов и распределенных систем, на нем можно писать интерфейсы, много чего.
Можно ли на нем написать «Битрикс»? Я не знаю.
Скорее всего нет, потому что интерфейсов слишком много.
Но написать на нем платформу, на которой Битрикс будет работать быстрее (например, шину сообщений) — это то, что нужно, я уверен.
Кто использует Го?
Кто уже успел запрыгнуть в этот вагон?- Google понятен: у него много проектов, которые используют Go и давно на него перешли.
- Докер.
- ИнфлюксДанные.
Если кто не пробовал, рекомендую.
Тоже восходящая звезда.
- Твиттер.
- Дропбокс.
- Коддинг.
- Даже Байду.
Го, кстати, очень популярен в Китае.
- Многие другие.
Что мы сделали в Go? ITooLabs Centrex
Что мы написали в этом году?- Динамический кластер, позволяющий равномерно распределять нагрузку между всеми его узлами (согласно хеш-кольцу).
- Использует Protobuffer для внутренней связи.
- Использует SIP/HTTP/WebSocket для внешней связи.
- Есть медиапроцессор (оставим его в стороне, он на C++).
- Он имеет встроенный интерпретатор JavaScript и не является узлом (не нужно возиться с обратными вызовами).
Он работает так же, как Go: вы пишете в прямом и простом блочном стиле.
Изначально у нас там был Lua, но, немного помучавшись, мы от него отказались — нашли интерпретатор JavaScript в Go и теперь смело им пользуемся (разработчики довольны).
- Что еще мы сделали для себя? Понятно, что когда вы делаете систему, которая, по вашему мнению, должна работать при очень больших нагрузках, первое, что вам нужно сделать, — это нагрузочное тестирование.
И мы сделали генератор нагрузки/тестер звонков, который может генерировать до 2 тысяч звонков в секунду на двух машинах.
- Наша система чрезвычайно дружелюбна к DevOps. Например, чтобы развернуть в производство новое приложение сигнализации, нужно запустить всего одну команду, которая моментально скачает из репозитория конкретную версию этого самого приложения сигнализации, раздаст ее по всем узлам кластера, заменит, и потом в любой момент можно откатиться.
Для одних клиентов можно будет оставить одну версию, для других — другую.
- От решения до первого развертывания у нас прошел 1 год.
О развертывании
Как я уже сказал, примерно в 2012 году мы поняли, что перед нами стена.Это было довольно страшно.
Мы не сильно ошиблись в своих прогнозах (что пройдет еще два года и это будет крах), потому что в начале 2014 года дела у нас были действительно очень плохи.
И мы быстро перенесли на нашу новую платформу значительную часть генерирующего функционала, в частности записи, всякие внешние транки — то, что генерирует большую нагрузку на ЦП, и с чем старая платформа вендора совершенно не справлялась.
Случай.
Голосовая почта для 70 миллионов абонентов Сейчас все это уже успешно работает и почти вся запись, которая идет на платформу, проходит через нашу систему Go. Если долго работать на репутацию, в какой-то момент репутация начинает работать на меня.
И уже давно к нам приходят разные люди из операторов с предложениями что-то сделать.
- В конце прошлого года «что-то» оказалось системой голосовой почты индонезийского оператора Indosat с 70 миллионами абонентов.
Мы подумали об этом и сделали его на базе нашей платформы.
С момента принятия решения (точнее, с момента установки оборудования, потому что это заняло много времени) до момента его развертывания прошло около трёх недель.
- Система находится на 16 серверах, из которых, обратите внимание, только 7 серверов — это сам Application Service и сервис SIB в Go. Все остальное — медиашлюзы в C++.
Эти 16 серверов держат 1800 вызовов в секунду и 50 000 одновременных диалогов.
Это 6,5 млн звонков в час (любимый критерий оператора – BHCA).
- 280 звонков в секунду — это текущая ежедневная нагрузка, которая есть сейчас.
Это 1 миллион BHCA на 36 миллионов подписчиков, плюс каждую неделю добавляется 2 миллиона подписчиков.
Или сейчас, на данный момент, это 100 миллионов звонков в секунду.
- После того как все это будет запущено в итоге целевая нагрузка составит около 600 звонков в секунду.
В качестве хранилища записи мы используем Ceph с тройной репликацией.
- Мы проверили и протестировали: система полностью выдерживает отказ системы до двух серверов.
То есть их можно просто отключить.
Именно это и произошло здесь, потому что индонезийцы, прокладывающие кабели, допустили небольшую ошибку.
- Наконец, мы обычно делаем скользящие обновления.
Не знаю, но думаю, мы могли бы сделать это на орланге.
Возможно, они могли бы сделать это на Java. Поскольку помимо основной работы я еще читаю лекции по системам реального времени и параллельному программированию в Тульском университете, то для меня одним из окончательных результатов, причин, по которым мы решили использовать Go, стал очень простой эксперимент. Я провел лабораторные работы для студентов и обнаружил, что кривая обучения Go была более крутой, чем у любого другого языка, с которым я когда-либо сталкивался (в этой области).
Студенты стали писать более-менее приличный код, потому что неприличный Go просто не позволял им писать.
Go создает скучный код, и только скучный код! Но это не получается неприлично – это очень сложно.
Могу похвастаться тем, что 31 декабря 2015 года, всего через месяц после развертывания, в системе за один день было зафиксировано 160 тысяч сообщений, которые абоненты передают друг другу.
Вопросы
Вопрос из зала (далее Б): – Большое спасибо за репортаж! Очень интересные случаи.Скажите, пожалуйста, как сейчас выглядит обработка ошибок в Go? Например, когда я пишу на Node и мне нужно выполнить 5 асинхронных операций подряд, мой код выглядит как 5 строк: подожди, подожди, подожди, подожди, подожди.
АН: – Как я уже сказал, исключений нет. По крайней мере, в том смысле, в котором их можно использовать для контроля и управления.
В: – Как вы справляетесь с ошибками?
АН: - если'ами! Повторюсь, Golang позволяет писать довольно скучный код и провоцирует вырезание и вставку.
В: — А сколько таких «если» будет для 5 асинхронных операций, каждая из которых может взорваться? АН: — С моей точки зрения, они будут синхронными (с точки зрения этой горутины).
5 если.
В: – Код увеличивается практически вдвое.
АН: — Наверное, если бы я заплатил разработчикам кода, я бы расстроился.
Но поскольку я плачу за то, чтобы они создавали хороший, работающий код, я в принципе доволен этим.
В: – Возможно ли вообще динамически подключить какую-нибудь библиотеку C? АН: - Да.
В: – То есть этот функционал сохраняется? АН: — Про CGO я показал и рассказал, что он линкуется со статической библиотекой, если она есть, а если нет — подключает динамическую.
Более того, в Go 1.5 в принципе появилось динамическое связывание, и теперь оно позволяет даже создавать динамические библиотеки.
Но мы настолько к этому привыкли, настолько испытали на себе такой механизм, что уже не ощущаем в этом необходимости.
Конечно, вы можете подключить динамические библиотеки C, но не C++.
В: – И двоичный файл в итоге не окажется слишком гигантским? АН: — Нет. Бинарник всей нашей системы, которая обрабатывает все эти вызовы (вместе с интерпретатором JavaScript внутри), занимает всего 6 мегабайт. Это бинарник, который в принципе укладывается во второй кэш.
В: — Я сам часто слышал сравнения: Go часто сравнивают с интерпретируемыми языками, а задача написать полноценную коммуникационную платформу мало у кого стоит. Какие более простые практические случаи существуют?
АН: – Простой случай – это здорово.
Для компании Мегафон мы написали пребиллинг - что-то вроде автобуса, который собирает платформы из разных компонентов (биллинг, Мультифон - у крупного оператора их всегда много), интегрирует все это внутри, заносит в базу данных, рассчитывает что нужно и отправляет события в разные места.
В той же Индонезии есть простой шлюз (пусть и простой, но распределенный), который принимает события от нашей системы и передает их дальше в систему, которая отправляет их на SSD. Вот типа задач - конечно , все это написано очень и очень быстро, что и привлекает.
Немного рекламы :)
Спасибо, что остаетесь с нами.Вам нравятся наши статьи? Хотите увидеть больше интересных материалов? Поддержите нас, разместив заказ или порекомендовав друзьям, облачный VPS для разработчиков от $4,99 , уникальный аналог серверов начального уровня, который мы придумали для вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от 19$ или как правильно раздать сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40 ГБ DDR4).
Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только здесь 2 x Intel TetraDeca-Core Xeon, 2 x E5-2697v3, 2,6 ГГц, 14C, 64 ГБ DDR4, 4 твердотельных накопителя по 960 ГБ, 1 Гбит/с, 100 ТВ от 199 долларов США в Нидерландах! Dell R420 — 2x E5-2430, 2,2 ГГц, 6C, 128 ГБ DDR3, 2 твердотельных накопителя по 960 ГБ, 1 Гбит/с, 100 ТБ — от 99 долларов США! Прочтите об этом Как построить корпоративную инфраструктуру класса, используя серверы Dell R730xd E5-2650 v4 стоимостью 9000 евро за копейки? Теги: #программирование #ИТ-инфраструктура #Конференции #Go
-
Сложные Методы Авторизации
19 Oct, 24 -
Стать Потребителем Лицензионной Продукции
19 Oct, 24 -
Машина, Которая Делает Дырки!
19 Oct, 24 -
Советы По Защите Диссертации. Часть 1
19 Oct, 24