- PVSM.RU - https://www.pvsm.ru -
Алексей Найдёнов, CEO ITooLabs [1], рассказывает про разработку телекоммуникационной платформы для операторов связи на языке программирования Go (Golang). Алексей также делится опытом развертывания и эксплуатации платформы в одном из крупнейших азиатских операторов связи, который использовал платформу для оказания услуг голосовой почты (VoiceMail) и Виртуальной АТС (Cloud PBX).
Алексей Найдёнов (далее – АН): – Всем привет! Меня зовут Алексей Найдёнов. Я – директор компании ITooLabs. Перво-наперво я хотел бы ответить, что здесь делаю и каким образом здесь оказался.
Если вы посмотрите Bitrix24 Marketplace (раздел «Телефония»), то 14 приложений и 36, которые там есть (40%) – это мы:
Точнее сказать, это наши партнёры-операторы, но за всем этим стоит наша платформа (Platform as a Service) – то, что мы им продаём за небольшую копеечку. Собственно, о развитии этой платформы и о том, как мы пришли в Go, я бы и хотел рассказать.
Цифры по нашей платформе сейчас:
44 партнёра-оператора, включая «Мегафон». Мы, вообще говоря, очень любим пускаться в разные авантюры, и у нас есть фактический доступ к 100 миллионам абонентов 44 операторов здесь, в России. Поэтому, если у кого-то будут появляться какие-то бизнес-идеи, мы всегда их с радостью выслушаем.
Как вообще правильные чуваки начинают делать свою платформу? Надо ещё учесть, что у нас в анамнезе была «хардкор-интерпрайз» разработка, да ещё и в самое точное для enterprise время года! Это было то счастливое время, когда приходишь к заказчику и говоришь: «Нам нужно ещё пару серверов». А заказчик: «Да не вопрос! У нас десятка в стойке стоит».
Поэтому мы занимались Oracle, Java, WebSphere, Db2 и всё такое. Поэтому мы взяли, конечно, лучшие вендорские решения, интегрировали их и попробовали с этим взлететь. Гуляли на свои. Это бы такой внутренний стартап.
Всё это вообще началось в 2009 году. С 2006-го мы плотно занимаемся операторскими решениями, так или иначе. Сделали несколько заказных виртуальных АТС (вроде того, что у нас сейчас имеется на заказ): посмотрели, решили, что это хорошо, и решили замутить внутренний стартап.
Взяли VMWare. Поскольку гуляли на свои, то пришлось сразу отказаться от крутого вендорского Storage. Мы всё про них знаем: что обещания нужно делить на 3, а стоимость умножать на 10. Поэтому делали DirDB и так далее.
Потом оно начало расти. К этому добавился сервис биллинга, потому что платформа перестала справляться. Затем серер биллинга с MySQL ушёл на Mongo. В итоге получилось работающее решение, которые перерабатывает все вызовы, которые туда идут:
Но где-то там, внутри, крутится тот самый вендорский продукт – главный, ядерный, который мы когда-то взяли. Примерно к концу 2011 года мы для себя поняли, что главным бутылочным горлышком для нас, конечно, будет являться именно этот продукт – мы в него упрёмся. Мы видели перед собой стену, в которую бежали на полном скаку, поскольку клиенты шли, добавлялись.
Соответственно, нам нужно было что-то делать. Конечно, мы провели довольно долгие исследования по поводу разных продуктов – и open source, и вендорских. Я не буду сейчас на этом останавливаться – не о том речь. Самый последний запасной вариант, о котором мы думали – это делать свою собственную платформу.
В конечном итоге мы пришли именно к этому варианту. Почему? Потому что все вендорские и open source продукты делались для решения проблем 10-летней давности. Хорошо, если 10-летней, а некоторые и больше! Для нас стал очевиден выбор: либо мы прощаемся с нашей прекрасной идеей об идеальной услуге (для партнёров, операторов и себя), либо мы делаем что-то своё.
Мы решили делать что-то своё!
Если долго чем-то занимаешься (эксплуатируешь чужой продукт), то в голове потихоньку складываются мысль: а как бы я это сделал сам? Поскольку мы в компании все программисты (кроме продавцов, не программистов нет), то требования у нас сложились давно, и они были понятны:
Соответственно, из требований к продукту, которые мы для себя предъявили, вырастают явно логичным образом требования к языку.
Вариантов у нас было не так много на самом деле, если вспомнить. Во-первых, «Эрланг» – мы его любим и знаем, это был мой личный, персональный фаворит. Во-вторых, Java – даже не Java, а конкретно Scala. В-третьих, язык, который на тот момент времени мы вообще не знали – Go. Он тогда только-только появился, точнее, примерно два года уже существовал, но ещё не вышел в релиз.
Победил Go!
Мы сделали платформу на нём. Попробую объяснить, почему.
Краткая история Go. Стартовал в 2007-м, открыт в 2009-м, первая версия вышла в 2012-м (то есть мы начали работать ещё до первого релиза). Инициатором выступал Google, который хотел заменить у себя, как я подозреваю, Java.
Авторы – весьма имениты:
Мы видим, что язык более-менее простой, понятный. У нас есть очевидные типы: в некоторых случаях их нужно объявлять, в некоторых – не нужно (это значит, что типы выводятся, так или иначе).
Видно, что модно описывать структуры. Видно, что у нас есть понятие указателя (там, где звёздочка). Видно, что есть специальная поддержка для объявления инициализации массивов и ассоциативных массивов.
Примерно понятно – жить можно. Пробуем написать Hello, world:
Что видим? Это Си-подобный синтаксис, точка с запятой необязательна. Она может быть разделителем для двух строк, но только в том случае, если это две конструкции, которые именно на одной строке.
Видим, что скобки в управляющих структурах (в 14-й строке) необязательны, а вот фигурные обязательны всегда. Видим, что типизация статическая. Тим в большинстве случаев выводится. Этот пример чуть сложнее обычного Hello, world – просто для того, чтобы показать, что есть библиотека.
Что ещё видим важного? Код организован в пакеты. И для того чтобы пакет использовать в своём собственном коде, необходимо его импортировать при помощи директивы import – это тоже важно. Запускаем – работает. Отлично!
Пробуем дальше что-нибудь посложнее: Hello, world, но только теперь это http-сервер. Что видим интересного здесь?
Во-первых, функция выступает параметром. Это означает, что функция у нас – «первоклассный гражданин» и с ним можно делать много всего интересного в функциональном стиле. Видим далее неожиданное: директива import ссылается непосредственно на репозиторий GitHub. Всё верно, так и есть – более того, так и нужно делать.
В Go универсальным идентификатором пакета является url его репозитория. Есть специальная утилита Goget, которая сходит за всеми зависимостями, скачает их, установит, скомпилирует и подготовит к использованию, если это необходимо. При этом Goget знает про html-meta. Соответственно, можно держать http-каталог, в котором будут ссылки на конкретный свой репозиторий (как мы, например, делаем).
Что мы ещё видим? Http и Json в штатной библиотеке. Есть, очевидно, интроспекция – reflection, которая должна использоваться в encoding/json, потому что мы ему подставляем просто какой-то произвольный объект.
Запускаем и видим, что у нас в 20 строк уложился полезный код, который компилируется, запускается и отдаёт текущую среднюю загрузку машины (на машине, на которой он запущен).
Что ещё важно из того, что мы можем здесь сразу увидеть? Оно компилируется в один статический бинарник (buinary). У этого бинарника вообще нет никаких зависимостей, никаких библиотек! Его можно скопировать на любую систему, сразу запустить, и оно будет работать.
Двигаемся дальше.
У Go есть методы. Вы можете объявить метод для любого пользовательского типа. Притом это необязательно структура, а может быть alias какого-то типа. Вы можете объявить alias для N32 и писать для него методы, чтобы делать что-нибудь полезное.
И вот здесь мы в первый раз впадаем в ступор… Выясняется, что у Go нет классов как таковых. Те, кто знает Go, может сказать, что там есть включение типов, но это совсем другое. Чем раньше разработчик перестанет думать об этом как о наследовании, тем лучше. В Go классов нет, и наследования тоже нет.
Вопрос! Что же компания авторов под руководством Google дала нам для того, чтобы отображать всю сложность мира? Нам дали интерфейсы!
Интерфейс – это такой специальный тип, который позволяет написать просто методы, сигнатуры методов. Дальше любой тип, для которого эти методы существуют (выполняются), будет соответствовать этому интерфейсу. Это значит, что вы можете просто описать соответствующую функцию для одного типа, для другого (который соответствует тому типу интерфейса). Дальше – объявить переменную типа этого интерфейса и присвоить ей любой из этих объектов.
Для любителей хардкора могу сказать, что в этой переменной будет на самом деле два указателя: один – на данные, другой – на специальную таблицу дескрипторов, которая характерна именно для этого, конкретного типа, для интерфейса этого типа. То есть компилятор такие таблицы дескрипторов делает на момент линковки.
И есть в Go, конечно, указатели на void. Слово interface {} (с двумя фигурными скобками) – это переменная, которая позволяет указывать вообще на любой объект в принципе.
Пока что всё в порядке, всё привычно. Ничего удивительного.
Теперь подходим к тому, что заинтересовало: легковесные процессы – goroutines (горутины) в терминологии Go.
То есть всякий раз, когда программа на Go запускается на компьютере, она определяет количество ядер в системе, запускает столько потоков, сколько нужно (сколько ядер в системе или сколько вы ей сказали). Соответственно, планировщик будет запускать эти легковесные потоки выполнения во всех этих потоках операционной системы в каждом ядре.
Надо отметить, что это максимально эффективный способ утилизации железа. Кроме показанного мы делаем ещё много чего. Мы делаем, например, системы DPI, которые позволяют в один unit обслуживать 40 гигабит (смотря что происходит в этих строках).
Там мы ещё до Go использовали ровно ту же схему именно по этой причине: потому что это позволяет сохранять локальность кэша процессора, значительно снизить количество переключений контекста ОС (что тоже занимает очень много времени). Повторюсь: это – максимально эффективный способ утилизировать железа.
Этот простой пример в 21 строку – пример, который делает просто echo-server. При этом обратите внимание, что функция serve – предельно простая, она линейная. Там нет никаких колбэков, никакой нужды заморачиваться и думать… Вы просто читаете и пишете!
При этом, если вы читаете и пишете, оно на самом деле должно заблокироваться – это горутина просто кладётся в очередь и достаётся планировщиком тогда, когда снова станет возможно выполнение. То есть этот простой код может работать эхо-сервером на столько соединений, сколько позволит ОС на этой машине.
Продолжение будет совсем скоро…
Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас, оформив заказ или порекомендовав знакомым, облачные VPS для разработчиков от $4.99 [2], уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер? [3] (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).
Dell R730xd в 2 раза дешевле в дата-центре Equinix Tier IV в Амстердаме? Только у нас 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199 [4] в Нидерландах! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — от $99! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки? [5]
Автор: ua-hosting.company
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/349042
Ссылки в тексте:
[1] ITooLabs: http://itoolabs.com/
[2] облачные VPS для разработчиков от $4.99: https://ua-hosting.company/cloudvps/nl
[3] Вся правда о VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps от $19 или как правильно делить сервер?: https://habr.com/company/ua-hosting/blog/347386/
[4] 2 х Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 ТВ от $199: https://ua-hosting.company/serversnl
[5] Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5-2650 v4 стоимостью 9000 евро за копейки?: https://habr.com/company/ua-hosting/blog/329618/
[6] Источник: https://habr.com/ru/post/491652/?utm_source=habrahabr&utm_medium=rss&utm_campaign=491652
Нажмите здесь для печати.