Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Aleksiej Naidenow, dyrektor generalny ITooLabs, opowiada o rozwoju platformy telekomunikacyjnej dla operatorów telekomunikacyjnych w języku programowania Go (Golang). Alexey dzieli się także swoim doświadczeniem z wdrażania i obsługi platformy u jednego z największych azjatyckich operatorów telekomunikacyjnych, który wykorzystywał platformę do świadczenia usług poczty głosowej (VoiceMail) i wirtualnej centrali PBX (Cloud PBX).

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Alexey Naydenov (dalej - AN): - Cześć wszystkim! Nazywam się Aleksiej Naidenow. Jestem dyrektorem ITooLabs. Na początek chciałbym odpowiedzieć na pytanie, co tu robię i jak tu trafiłem.

Jeśli spojrzysz na rynek Bitrix24 (sekcja „Telefonia”), to 14 aplikacji i 36, które tam są (40%), to my:

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Dokładniej, są to nasi operatorzy partnerscy, ale za tym wszystkim stoi nasza platforma (Platform as a Service) – to, co im sprzedajemy za niewielki grosz. Właściwie chciałbym porozmawiać o rozwoju tej platformy i tym, jak doszliśmy do Go.

Numery naszej platformy to obecnie:

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

44 operatorów partnerskich, w tym MegaFon. Ogólnie rzecz biorąc, uwielbiamy przeżywać przygody i faktycznie mamy dostęp do 100 milionów abonentów 44 operatorów tutaj w Rosji. Dlatego jeśli ktoś ma jakiś pomysł na biznes, zawsze chętnie go wysłuchamy.

  • 5000 firm użytkowników.
  • Łącznie 20 000 abonentów. To wszystko b2b - współpracujemy tylko z firmami.
  • 300 połączeń na minutę w ciągu dnia.
  • W ubiegłym roku 100 milionów minut rozmów (świętowaliśmy). Dzieje się tak bez uwzględnienia wewnętrznych negocjacji prowadzonych na naszej platformie.

Jak to się zaczęło?

Jak właściwi kolesie zaczynają tworzyć własną platformę? Musimy także wziąć pod uwagę, że mieliśmy historię rozwoju „hardkorowego przedsiębiorstwa” i to nawet w najdokładniejszym momencie roku dla przedsiębiorstwa! To był ten szczęśliwy czas, kiedy przychodzisz do klienta i mówisz: „Potrzebujemy jeszcze kilku serwerów”. A klient: „Tak, bez dwóch zdań! Mamy dziesiątkę w szafie.

Zrobiliśmy więc Oracle, Java, WebSphere, Db2 i tak dalej. Dlatego wzięliśmy oczywiście rozwiązania najlepszych dostawców, zintegrowaliśmy je i próbowaliśmy z tym wystartować. Grali sami. Byłby to taki wewnętrzny startup.

Wszystko zaczęło się w 2009 roku. Od 2006 roku jesteśmy w ten czy inny sposób ściśle zaangażowani w decyzje operatorów. Zrobiliśmy kilka niestandardowych wirtualnych central PBX (takich jak te, które mamy teraz na zamówienie): sprawdziliśmy, uznaliśmy, że są dobre i postanowiliśmy rozkręcić wewnętrzny startup.

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Weź VMware. Ponieważ szliśmy sami, musieliśmy od razu porzucić fajnego sprzedawcę Storage. Wiemy o nich wszystko: że obietnice należy podzielić przez 3, a koszt pomnożyć przez 10. Dlatego zrobiliśmy DirDB i tak dalej.

Potem zaczęło rosnąć. Dodano do tego usługę billingową, bo platforma już nie dawała sobie rady. Następnie serwer rozliczeniowy z MySQL został przeniesiony do Mongo. W rezultacie otrzymaliśmy działające rozwiązanie, które przetwarza wszystkie kierowane tam połączenia:

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Ale gdzieś w środku kręci się produkt tego samego dostawcy - główny, nuklearny, który kiedyś wzięliśmy. Mniej więcej pod koniec 2011 roku zdaliśmy sobie sprawę, że głównym wąskim gardłem dla nas będzie oczywiście ten konkretny produkt - na niego natrafimy. Zobaczyliśmy przed sobą ścianę, na którą wbiegliśmy w pełnym galopie, gdy klienci szli.
W związku z tym musieliśmy coś zrobić. Oczywiście przeprowadziliśmy sporo badań na temat różnych produktów – zarówno open source, jak i dostawców. Nie będę się teraz nad tym rozwodzić – nie o to chodzi. Ostatnim rozwiązaniem, o którym myśleliśmy, było stworzenie własnej platformy.

Ostatecznie doszliśmy do tej opcji. Dlaczego? Ponieważ wszystkie produkty dostawców i produkty typu open source zostały stworzone, aby rozwiązywać problemy 10 lat temu. Cóż, jeśli 10-latek i trochę więcej! Wybór stał się dla nas oczywisty: albo żegnamy się ze świetnym pomysłem na idealną usługę (dla partnerów, operatorów i nas samych), albo robimy coś własnego.

Postanowiliśmy zrobić coś innego!

Wymagania platformy

Jeśli robisz coś przez dłuższy czas (wyzyskujesz produkt kogoś innego), to w Twojej głowie powoli pojawia się myśl: jak sam bym to zrobił? Ponieważ w firmie wszyscy jesteśmy programistami (oprócz sprzedawców, nie ma nieprogramistów), nasze wymagania kształtowały się od dawna i były jasne:

  1. Wysoka prędkość rozwoju. Produkt sprzedawcy, który nas dręczył, przede wszystkim nam nie odpowiadał, bo wszystko działało długo i powoli. Chcieliśmy szybko – mieliśmy mnóstwo pomysłów! Wciąż mamy mnóstwo pomysłów, ale lista pomysłów była taka, że ​​wydawało się, że do przodu zajmie nam dziesięć lat. Teraz tylko przez rok.
  2. Maksymalne wykorzystanie żelaza wielordzeniowego. To też było dla nas ważne, bo widzieliśmy, że rdzeni będzie coraz więcej.
  3. Wysoka niezawodność. Ten, nad którym też płakaliśmy.
  4. Wysoka tolerancja na błędy.
  5. Chcieliśmy zakończyć codziennym procesem wydawania wersji. Aby to zrobić, potrzebowaliśmy wyboru języka.

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

W związku z tym z wymagań dotyczących produktu, które sami sobie przedstawiliśmy, wymagania dotyczące języka rosną w wyraźnie logiczny sposób.

  1. Jeśli chcemy obsługi systemów wielordzeniowych, potrzebujemy wsparcia dla wykonywania równoległego.
  2. Jeśli potrzebujemy szybkości rozwoju, potrzebujemy języka, który wspiera konkurencyjny rozwój, konkurencyjne programowanie. Jeżeli ktoś nie spotkał się z różnicą to sprawa jest bardzo prosta:
    • programowanie równoległe polega na tym, że dwa różne wątki działają na różnych rdzeniach;
    • Wykonywanie współbieżne, a dokładniej obsługa współbieżności, dotyczy tego, w jaki sposób język (lub środowisko wykonawcze, cokolwiek innego) pomaga ukryć całą złożoność wynikającą z wykonywania równoległego.
  3. Wysoka stabilność. Oczywiście potrzebowaliśmy klastra i był on lepszy niż to, co mieliśmy w przypadku produktu dostawcy.

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Jeśli pamiętasz, nie mieliśmy zbyt wielu opcji. Po pierwsze Erlang – uwielbiamy go i wiemy, to był mój osobisty, osobisty ulubieniec. Po drugie, Java to nawet nie Java, ale konkretnie Scala. Po trzecie, język, którego wówczas w ogóle nie znaliśmy – Go. Pojawiła się dopiero wtedy, a dokładniej istniała już jakieś dwa lata, ale nie została jeszcze wypuszczona.

Pokonano Go!

Historia Go

Zrobiliśmy na nim platformę. Spróbuję wyjaśnić dlaczego.

Krótka historia Go. Rozpoczęty w 2007 r., otwarty w 2009 r., pierwsza wersja została wydana w 2012 r. (czyli pracowaliśmy jeszcze przed pierwszym wydaniem). Inicjatorem był Google, który chciał, jak podejrzewam, zastąpić Javę.

Autorzy są bardzo znani:

  • Ken Thomson, który stał za Uniksem, wynalazł UTF-8, pracował nad systemem Plan 9;
  • Rob Pike, który wraz z Kenem zaprojektował UTF-8, pracował także nad Plan 9, Inferno i Limbo w Bell Labs;
  • Robert Gizmer, którego znamy i kochamy za wynalezienie kompilatora Java HotSpot i pracę nad generatorem w V8 (interpretator Javascript firmy Google);
  • I ponad 700 autorów, w tym niektórzy z naszych poprawek.

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Przejdź w skrócie

Widzimy, że język jest mniej więcej prosty i zrozumiały. Mamy oczywiste typy: w niektórych przypadkach należy je zadeklarować, w innych nie (co oznacza, że ​​typy i tak są wywnioskowane).

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Widać, że modne jest opisywanie struktur. Można zauważyć, że mamy pojęcie wskaźnika (w miejscu, w którym znajduje się gwiazdka). Można zauważyć, że istnieje specjalne wsparcie dla deklarowania inicjalizacji tablic i tablic asocjacyjnych.

Z grubsza zrozumiałe - możesz żyć. Próbuję napisać Witaj, świecie:

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Co widzimy? To jest składnia podobna do języka C, średnik jest opcjonalny. Może być separatorem dwóch linii, ale tylko wtedy, gdy są to dwie konstrukcje znajdujące się dokładnie w tej samej linii.

Widzimy, że nawiasy w strukturach kontrolnych (w 14. linii) są opcjonalne, ale zawsze wymagane są nawiasy kręcone. Widzimy, że pisanie jest statyczne. Tim w większości przypadków jest wyświetlany. Ten przykład jest nieco bardziej skomplikowany niż zwykły Hello, world - tylko po to, aby pokazać, że istnieje biblioteka.

Co jeszcze uważamy za ważne? Kod jest podzielony na pakiety. A żeby wykorzystać pakiet we własnym kodzie trzeba go zaimportować za pomocą dyrektywy import - to też jest ważne. Zaczynamy – to działa. Świetnie!

Spróbujmy czegoś bardziej skomplikowanego: Witaj, świecie, ale teraz jest to serwer http. Co tu widzimy ciekawego?

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Po pierwsze, funkcja działa jako parametr. Oznacza to, że funkcja, którą posiadamy, jest „obywatelem pierwszej klasy” i można z nią zrobić wiele ciekawych rzeczy w funkcjonalnym stylu. Dalej widzimy nieoczekiwane: dyrektywa importowa odnosi się bezpośrednio do repozytorium GitHub. Zgadza się, tak właśnie jest – co więcej, tak należy to robić.

W Go uniwersalnym identyfikatorem pakietu jest adres URL jego repozytorium. Istnieje specjalne narzędzie Goget, które sprawdza wszystkie zależności, pobiera je, instaluje, kompiluje i przygotowuje do użycia, jeśli to konieczne. Jednocześnie Goget wie o html-meta. W związku z tym możesz prowadzić katalog http, który będzie zawierał linki do Twojego konkretnego repozytorium (tak jak na przykład my to robimy).

Co jeszcze widzimy? Http i Json w zwykłej bibliotece. Istnieje oczywiście introspekcja - refleksja, którą należy zastosować w kodowaniu/json, ponieważ po prostu podstawiamy za nią jakiś dowolny obiekt.

Uruchamiamy go i widzimy, że mamy 20 linii przydatnego kodu, który kompiluje, uruchamia i podaje aktualne średnie obciążenie maszyny (na maszynie, na której jest uruchomiona).
Co jeszcze jest istotne z tego, co od razu tu widzimy? Kompiluje się do jednego statycznego pliku binarnego (buinarnego). Ten plik binarny nie ma żadnych zależności ani bibliotek! Można go skopiować do dowolnego systemu, uruchomić natychmiast i zadziała.

Przechodząc.

Idź: metody i interfejsy

Go ma metody. Możesz zadeklarować metodę dla dowolnego typu niestandardowego. Co więcej, niekoniecznie jest to struktura, ale może to być pewnego rodzaju alias. Możesz zadeklarować alias dla N32 i napisać dla niego metody, aby zrobił coś pożytecznego.

I tu po raz pierwszy wpadamy w odrętwienie... Okazuje się, że w Go nie ma zajęć jako takich. Ci, którzy znają Go, mogą powiedzieć, że istnieje inkluzja typów, ale to jest zupełnie coś innego. Im szybciej deweloper przestanie myśleć o tym jako o dziedziczeniu, tym lepiej. W Go nie ma klas, nie ma też dziedziczenia.

Pytanie! Co dała nam grupa autorów pod przewodnictwem Google, aby ukazać złożoność świata? Dostaliśmy interfejsy!

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

Interfejs to specjalny typ, który umożliwia pisanie prostych metod, sygnatur metod. Co więcej, każdy typ, dla którego istnieją (są wykonywane) te metody, będzie odpowiadał temu interfejsowi. Oznacza to, że możesz po prostu napisać odpowiednią funkcję dla jednego typu, dla innego (co odpowiada temu typowi interfejsu). Następnie zadeklaruj zmienną typu tego interfejsu i przypisz do niej dowolny z tych obiektów.

Zagorzałym fanom mogę powiedzieć, że ta zmienna będzie właściwie zawierać dwa wskaźniki: jeden do danych, drugi do specjalnej tabeli deskryptorów, specyficznej dla tego konkretnego typu, do interfejsu tego typu. Oznacza to, że kompilator tworzy takie tablice deskryptorów w momencie łączenia.

Istnieją oczywiście wskazówki dotyczące unieważnienia w Go. Słowo interfejs {} (z dwoma nawiasami klamrowymi) jest zmienną, która w zasadzie pozwala wskazać dowolny obiekt.
Jak dotąd wszystko jest w porządku, wszystko jest znajome. Nic zaskakującego.

Idź: goroutines

Teraz dochodzimy do tego, co nas interesuje: procesy lekkie – goroutines (goroutines) w terminologii Go.

Aleksiej Naidenow. ITooLabs. Sprawa deweloperska na platformie telefonicznej Go (Golang). Część 1

  1. Po pierwsze, są naprawdę lekkie (mniej niż 2 Kb).
  2. Po drugie, koszt stworzenia takiej goroutine jest znikomy: możesz stworzyć ich tysiąc na sekundę - nic się nie stanie.
  3. Obsługiwane są przez własny program planujący, który po prostu przenosi kontrolę z jednej procedury goroutine na drugą.
  4. W takim przypadku kontrola zostaje przekazana w następujących przypadkach:
    • jeśli napotkana zostanie instrukcja go (jeśli goroutine rozpoczyna następną goroutine);
    • jeśli włączona jest funkcja blokująca wywołanie wejścia/wyjścia;
    • jeśli zostanie uruchomione zbieranie śmieci;
    • jeśli rozpocznie się jakaś operacja na kanałach.

Oznacza to, że za każdym razem, gdy na komputerze uruchamiany jest program Go, wykrywa on liczbę rdzeni w systemie i uruchamia tyle wątków, ile potrzeba (ile rdzeni jest w systemie lub ile mu każesz). W związku z tym program planujący uruchomi te lekkie wątki wykonawcze we wszystkich wątkach systemu operacyjnego w każdym rdzeniu.

Warto zaznaczyć, że jest to najskuteczniejszy sposób wykorzystania żelaza. Oprócz tego, co pokazaliśmy, robimy o wiele więcej. Wykonujemy np. układy DPI, które pozwalają obsłużyć 40 gigabitów w jednej jednostce (w zależności od tego, co dzieje się w tych liniach).

Tam, jeszcze przed Go, używaliśmy dokładnie tego samego schematu z tego właśnie powodu: ponieważ pozwala to na zapisanie lokalizacji pamięci podręcznej procesora, znacznie zmniejsza liczbę przełączeń kontekstu systemu operacyjnego (co również zajmuje bardzo dużo czasu). Powtarzam: to najskuteczniejszy sposób wykorzystania żelaza.

Ten prosty 21-liniowy przykład jest przykładem, który po prostu wykonuje echo-server. Jednocześnie należy pamiętać, że funkcja serwowania jest niezwykle prosta, ma charakter liniowy. Nie ma żadnych oddzwonień, nie musisz się martwić i myśleć... Po prostu czytasz i piszesz!

Jednocześnie, jeśli czytasz i piszesz, powinno to faktycznie blokować - ta goroutine jest po prostu umieszczana w kolejce i pobierana przez program planujący, gdy wykonanie stanie się ponownie możliwe. Oznacza to, że ten prosty kod może działać jako serwer echa dla tylu połączeń, na ile pozwala system operacyjny na tym komputerze.

Ciąg dalszy już wkrótce...

Kilka reklam 🙂

Dziękujemy za pobyt z nami. Podobają Ci się nasze artykuły? Chcesz zobaczyć więcej ciekawych treści? Wesprzyj nas składając zamówienie lub polecając znajomym, VPS w chmurze dla programistów od 4.99 USD, unikalny odpowiednik serwerów klasy podstawowej, który został przez nas wymyślony dla Ciebie: Cała prawda o VPS (KVM) E5-2697 v3 (6 rdzeni) 10GB DDR4 480GB SSD 1Gbps od 19$ czyli jak udostępnić serwer? (dostępne z RAID1 i RAID10, do 24 rdzeni i do 40 GB DDR4).

Dell R730xd 2 razy taniej w centrum danych Equinix Tier IV w Amsterdamie? Tylko tutaj 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6 GHz 14C 64 GB DDR4 4x960 GB SSD 1 Gb/s 100 Telewizor od 199 USD w Holandii! Dell R420 — 2x E5-2430 2.2 GHz 6C 128 GB DDR3 2x960 GB SSD 1 Gb/s 100 TB — od 99 USD! Czytać o Jak zbudować firmę infrastrukturalną klasy z wykorzystaniem serwerów Dell R730xd E5-2650 v4 o wartości 9000 euro za grosz?

Źródło: www.habr.com

Dodaj komentarz