Олексій Найденов, CEO
Олексій Найденов (далі – АН): - Всім привіт! Мене звуть Олексій Найденов. Я директор компанії ITooLabs. Насамперед я хотів би відповісти, що тут роблю і яким чином тут опинився.
Якщо ви подивіться Bitrix24 Marketplace (розділ «Телефонія»), то 14 додатків та 36, які там є (40%) – це ми:
Точніше сказати, це наші партнери-оператори, але за цим стоїть наша платформа (Platform as a Service) - те, що ми їм продаємо за невелику копійчину. Власне, про розвиток цієї платформи та про те, як ми прийшли до Go, я б і хотів розповісти.
Цифри нашої платформи зараз:
44 партнери-оператори, включаючи «Мегафон». Ми, взагалі кажучи, дуже любимо пускатися в різні авантюри, і ми маємо фактичний доступ до 100 мільйонів абонентів 44 операторів тут, в Росії. Тому, якщо в когось з'являтимуться якісь бізнес-ідеї, ми завжди їх з радістю вислухаємо.
- 5000 компаній-користувачів.
- 20 000 абонентів у сумі. Це все b2b – ми працюємо лише з компаніями.
- 300 дзвінків за хвилину вдень.
- 100 мільйонів хвилин викликів за минулий рік (ми це відсвяткували). Це без урахування внутрішніх переговорів, які є на нашій платформі.
Як це починалося?
Як взагалі правильні чуваки починають робити свою платформу? Треба ще врахувати, що у нас в анамнезі була «хардкор-інтерпрайз» розробка, та ще й у найточнішу для enterprise пору року! Це був той щасливий час, коли приходиш до замовника і кажеш: «Нам потрібна ще пара серверів». А замовник: «Та не питання! У нас десятка у стійці стоїть».
Тому ми займалися Oracle, Java, WebSphere, Db2 і таке інше. Тому ми взяли, звичайно, найкращі вендорські рішення, інтегрували їх та спробували з цим злетіти. Гуляли на свої. Це б такий внутрішній стартап.
Все це взагалі розпочалося у 2009 році. З 2006-го ми щільно займаємося операторськими рішеннями так чи інакше. Зробили кілька замовних віртуальних АТС (на зразок того, що у нас зараз є на замовлення): подивилися, вирішили, що це добре, і вирішили зробити внутрішній стартап.
Взяли VMWare. Оскільки гуляли на свої, то довелося одразу відмовитись від крутого вендорського Storage. Ми все про них знаємо: що обіцянки потрібно ділити на 3, а вартість множити на 10. Тому робили DirDB і таке інше.
Потім воно почало зростати. До цього додався сервіс білінгу, тому що платформа перестала справлятися. Потім серер білінгу з MySQL пішов на Mongo. У результаті вийшло працююче рішення, яке переробляє всі виклики, які туди йдуть:
Але десь там, усередині, крутиться цей вендорський продукт – головний, ядерний, який ми колись взяли. Приблизно до кінця 2011 року ми для себе зрозуміли, що головним пляшковим шийкою для нас, звичайно, буде саме цей продукт - ми в нього впораємося. Ми бачили перед собою стіну, в яку бігли повним скаком, оскільки клієнти йшли, додавалися.
Відповідно нам потрібно було щось робити. Звичайно, ми провели досить довгі дослідження щодо різних продуктів – і open source, і вендорських. Я не буду зараз на цьому зупинятись – не про те йдеться. Останній запасний варіант, про який ми думали - це робити свою власну платформу.
Зрештою, ми прийшли саме до цього варіанту. Чому? Тому що всі вендорські та open source продукти робилися для вирішення проблем 10-річної давності. Добре, якщо 10-річної, а дехто і більше! Для нас став очевидним вибір: або ми прощаємося з нашою прекрасною ідеєю про ідеальну послугу (для партнерів, операторів і себе), або ми робимо щось своє.
Ми вирішили робити щось своє!
Вимоги до платформи
Якщо довго чимось займаєшся (експлуатуєш чужий продукт), то в голові потихеньку складаються думка: а як би я це зробив сам? Оскільки ми у компанії всі програмісти (крім продавців, не програмістів немає), то вимоги у нас склалися давно, і вони були зрозумілі:
- Висока швидкість розробки. Вендорський продукт, який нас мучив, не влаштовував насамперед тим, що все виходило довго та повільно. Ми хотіли швидко – ми мали багато ідей! У нас і зараз багато ідей, але тоді список ідей був такий, що здавалося, ніби вперед на десять років. Нині лише на рік.
- Максимальна утилізація багатоядерного заліза. Це теж для нас було важливо, оскільки ми бачили, що ядер ставатиме лише більше і більше.
- Висока надійність. Те, із чим ми теж наплакалися.
- Висока стійкість до збоїв.
- Ми хотіли прийти зрештою до процесу з щоденними релізами. Для цього нам потрібний був вибір мови.
Відповідно, з вимог до продукту, які ми собі пред'явили, виростають явно логічним чином вимоги до мови.
- Якщо ми хочемо підтримки мультиядерних систем, нам потрібна підтримка паралельного виконання.
- Якщо нам потрібна швидкість розробки – нам потрібна мова за допомогою конкурентної розробки, конкурентного програмування. Якщо хтось не стикався з різницею, то вона дуже проста:
- паралельне програмування – це про те, як два різні потоки виконуються на різних ядрах;
- Конкурентне виконання, точніше підтримка конкурентності - це про те, як мова (або runtime, неважливо) допомагає приховати всю складність, яка випливає з паралельного виконання.
- Висока стійкість. Очевидно, що нам потрібен був кластер, причому краще, ніж у нас на вендорському продукті.
Варіантів у нас було не так багато насправді, якщо згадати. По-перше, "Ерланг" - ми його любимо і знаємо, це був мій особистий, персональний фаворит. По-друге, Java – навіть Java, саме Scala. По-третє, мова, яку на той час ми взагалі не знали – Go. Він тоді тільки-но з'явився, точніше, приблизно два роки вже існував, але ще не вийшов у реліз.
Переміг Go!
Історія Go
Ми зробили платформу на ньому. Спробую пояснити чому.
Коротка історія Go. Стартував 2007-го, відкритий 2009-го, перша версія вийшла 2012-го (тобто ми почали працювати ще до першого релізу). Ініціатором виступав Google, який хотів замінити у себе, як я підозрюю, Java.
Автори - дуже імениті:
- Кен Томсон, який стояв за Unix'ом, вигадав UTF-8, працював над системою Plan 9;
- Роб Пайк, який разом із Кеном вигадував UTF-8, теж працював над Plan 9, над Inferno, Limbo у Bell Labs;
- Роберт Гізмер, якого ми знаємо і любимо за те, що він придумав Java HotSpot Compiler, і за те, що він працював над генератором у V8 (інтерпретатор Javascript'а від Google);
- І понад 700 учасників, включаючи деякі наші патчі.
Go: перший погляд
Ми бачимо, що мова більш-менш проста, зрозуміла. У нас є очевидні типи: у деяких випадках їх потрібно оголошувати, у деяких – не потрібно (це означає, що типи виводяться так чи інакше).
Видно, що модно описувати структури. Видно, що ми маємо поняття покажчика (там, де зірочка). Видно, що є спеціальна підтримка для оголошення ініціалізації масивів та асоціативних масивів.
Приблизно зрозуміло – жити можна. Пробуємо написати 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: методи та інтерфейси
Go має методи. Ви можете оголосити метод для будь-якого типу користувача. Причому це необов'язково структура, а може бути або якогось типу. Ви можете оголосити або для N32 і писати для нього методи, щоб робити щось корисне.
І ось тут ми вперше впадаємо в ступор ... З'ясовується, що Go немає класів як таких. Ті, хто знає Go, можуть сказати, що там є включення типів, але це зовсім інше. Чим раніше розробник перестане думати про це як про наслідування, тим краще. У Go класів немає, і спадкування теж немає.
Запитання! Що ж компанія авторів під керівництвом Google дала нам, щоб відображати всю складність світу? Нам дали інтерфейси!
Інтерфейс – такий спеціальний тип, який дозволяє написати просто методи, сигнатури методів. Далі будь-який тип, для якого ці методи існують (виконуються), відповідатиме цьому інтерфейсу. Це означає, що ви можете просто описати відповідну функцію для одного типу, іншого (що відповідає тому типу інтерфейсу). Далі – оголосити змінну типу цього інтерфейсу та присвоїти їй будь-який з цих об'єктів.
Для любителів хардкору можу сказати, що в цій змінній буде насправді два покажчики: один – на дані, інший – на спеціальну таблицю дескрипторів, яка характерна саме для цього конкретного типу для інтерфейсу цього типу. Тобто компілятор такі таблиці дескрипторів робить на момент лінкування.
І є у Go, звичайно, покажчики на void. Слово interface {} (з двома фігурними дужками) – це змінна, яка дозволяє вказувати взагалі будь-який об'єкт у принципі.
Поки що все гаразд, все звичне. Нічого дивного.
Go: goroutines
Тепер наближаємося до того, що зацікавило: легковажні процеси – goroutines (горутини) у термінології Go.
- По-перше, вони дійсно легкі (менше 2 Кб).
- По-друге, витрати на створення такої горутини нікчемні: їх можна створювати тисячу за секунду – нічого не буде.
- Обслуговуються вони своїм власним планувальником, який просто передає управління від однієї горутини до іншої.
- При цьому управління передається у таких випадках:
- якщо зустрічається вираз go (якщо горутина запускає наступну горутину);
- якщо вмикається блокуючий виклик Input/Out;
- якщо запускається складання сміття;
- якщо запускається операція з каналами.
Тобто щоразу, коли програма на Go запускається на комп'ютері, вона визначає кількість ядер у системі, запускає стільки потоків, скільки потрібно (скільки ядер у системі чи скільки ви їй сказали). Відповідно, планувальник запускатиме ці легковагові потоки виконання у всіх цих потоках операційної системи в кожному ядрі.
Слід зазначити, що це максимально ефективний спосіб утилізації заліза. Крім показаного, ми робимо ще багато чого. Ми робимо, наприклад, системи DPI, які дозволяють в один unit обслуговувати 40 гігабіт (дивлячись, що відбувається в цих рядках).
Там ми ще до Go використовували ту саму схему саме з цієї причини: тому що це дозволяє зберігати локальність кешу процесора, значно знизити кількість перемикань контексту ОС (що теж займає дуже багато часу). Повторюся: це максимально ефективний спосіб утилізувати заліза.
Цей простий приклад 21 рядок – приклад, який робить просто echo-server. При цьому зверніть увагу, що функція serve – дуже проста, вона лінійна. Там немає жодних колбеків, жодної потреби морочитися і думати… Ви просто читаєте та пишете!
При цьому, якщо ви читаєте і пишете, воно насправді має заблокуватися - це горутина просто кладеться в чергу і дістається планувальником тоді, коли знову можливе виконання. Тобто цей простий код може працювати луною на стільки з'єднань, скільки дозволить ОС на цій машині.
Продовження буде зовсім скоро.
Небагато реклами 🙂
Дякую, що залишаєтеся з нами. Вам подобаються наші статті? Бажаєте бачити більше цікавих матеріалів? Підтримайте нас, оформивши замовлення або порекомендувавши знайомим,
Dell R730xd вдвічі дешевше в дата-центрі Equinix Tier IV в Амстердамі? Тільки в нас
Джерело: habr.com