Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

Alexey Naidenov, CEO ITooLabs, talks about the development of a telecommunications platform for telecom operators in the programming language Go (Golang). Alexey also shares his experience of deploying and operating the platform in one of the largest Asian telecom operators, which used the platform to provide voice mail (VoiceMail) and Virtual PBX (Cloud PBX) services.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

Alexey Naydenov (hereinafter - AN): - Hi all! My name is Alexey Naidenov. I am the director of ITooLabs. First of all, I would like to answer what I am doing here and how I ended up here.

If you look at the Bitrix24 Marketplace (section "Telephony"), then 14 applications and 36 that are there (40%) are us:

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

More precisely, these are our partner operators, but behind all this is our platform (Platform as a Service) - what we sell to them for a small penny. Actually, I would like to talk about the development of this platform and how we came to Go.

The numbers for our platform now are:

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

44 partner operators, including MegaFon. Generally speaking, we love to go on adventures, and we actually have access to 100 million subscribers of 44 operators here in Russia. Therefore, if someone has some business ideas, we are always happy to listen to them.

  • 5000 user companies.
  • 20 subscribers in total. It's all b000b - we only work with companies.
  • 300 calls per minute during the day.
  • 100 million call minutes last year (we celebrated). This is without taking into account the internal negotiations that are on our platform.

How did it start?

How do the right dudes start making their own platform? We must also take into account that we had a history of "hardcore enterprise" development, and even at the most accurate time of the year for an enterprise! It was that happy time when you come to the customer and say: "We need a couple more servers." And the customer: β€œYes, no question! We have a ten in the rack.

So we did Oracle, Java, WebSphere, Db2 and all that. Therefore, we took, of course, the best vendor solutions, integrated them and tried to take off with it. They played on their own. It would be such an internal startup.

It all started in 2009. Since 2006, we have been closely involved in operator decisions, one way or another. We made several custom virtual PBXs (like what we currently have on order): we looked, decided that it was good, and decided to stir up an internal startup.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

Take VMWare. Since we were walking on our own, we had to immediately abandon the cool vendor Storage. We know all about them: that promises should be divided by 3, and the cost should be multiplied by 10. Therefore, we did DirDB and so on.

Then it started to grow. The billing service was added to this, because the platform could no longer cope. Then the billing server from MySQL moved to Mongo. As a result, we got a working solution that processes all the calls that go there:

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

But somewhere inside, the same vendor product is spinning - the main, nuclear one, which we once took. Approximately by the end of 2011, we realized for ourselves that the main bottleneck for us, of course, will be this particular product - we will run into it. We saw a wall in front of us, into which we ran at full gallop, as customers walked, were added.
Accordingly, we had to do something. Of course, we did quite a lot of research on various products - both open source and vendor ones. I will not dwell on this now - that is not the point. The very last fallback we thought about was making our own platform.

Ultimately, we came to this option. Why? Because all vendor and open source products were made to solve problems 10 years ago. Well, if a 10-year-old, and some more! The choice has become obvious for us: either we say goodbye to our great idea of ​​​​an ideal service (for partners, operators and ourselves), or we do something of our own.

We decided to do something different!

Platform Requirements

If you do something for a long time (you exploit someone else's product), then the thought slowly forms in your head: how would I do it myself? Since we are all programmers in the company (except for sellers, there are no non-programmers), our requirements have been formed for a long time, and they were clear:

  1. High development speed. The vendor's product, which tormented us, did not suit us in the first place because everything worked out for a long time and slowly. We wanted fast – we had a lot of ideas! We still have a lot of ideas, but then the list of ideas was such that it seemed like ten years ahead. Now only for a year.
  2. Maximum utilization of multi-core iron. This was also important for us, because we saw that there would only be more and more cores.
  3. High reliability. The one we cried too.
  4. High fault tolerance.
  5. We wanted to end up with a daily release process. To do this, we needed a choice of language.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

Accordingly, from the requirements for the product that we have presented for ourselves, the requirements for the language grow in a clearly logical way.

  1. If we want support for multi-core systems, then we need support for parallel execution.
  2. If we need development speed, we need a language that supports competitive development, competitive programming. If anyone has not encountered the difference, then it is very simple:
    • parallel programming is about how two different threads run on different cores;
    • concurrent execution, more specifically concurrency support, is about how the language (or runtime, whatever) helps hide all the complexity that comes from parallel execution.
  3. High stability. Obviously, we needed a cluster, and it was better than what we had on the vendor product.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

We didn't really have many options, if you remember. Firstly, Erlang - we love it and know it, it was my personal, personal favorite. Secondly, Java is not even Java, but specifically Scala. Thirdly, the language that at that time we did not know at all - Go. It had just appeared then, more precisely, it had already existed for about two years, but had not yet been released.

Defeated Go!

History of Go

We made a platform on it. I'll try to explain why.

A Brief History of Go. Started in 2007, opened in 2009, the first version was released in 2012 (that is, we started working even before the first release). The initiator was Google, which wanted to replace, as I suspect, Java.

The authors are very famous:

  • Ken Thomson, who was behind Unix, invented UTF-8, worked on the Plan 9 system;
  • Rob Pike, who designed UTF-8 with Ken, also worked on Plan 9, Inferno, Limbo at Bell Labs;
  • Robert Gizmer, whom we know and love for inventing the Java HotSpot Compiler and for working on the generator in V8 (Google's Javascript interpreter);
  • And over 700 contributors, including some of our patches.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

Go at a glance

We see that the language is more or less simple and understandable. We have obvious types: in some cases they need to be declared, in others they don't (meaning the types are inferred anyway).

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

It can be seen that it is fashionable to describe structures. It can be seen that we have the concept of a pointer (where the asterisk is). It can be seen that there is special support for declaring initialization of arrays and associative arrays.

Roughly understandable - you can live. Trying to write Hello, world:

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

What do we see? This is C-like syntax, the semicolon is optional. It can be a separator for two lines, but only if these are two constructs that are exactly on the same line.

We see that the brackets in the control structures (on the 14th line) are optional, but curly ones are always required. We see that the typing is static. Tim in most cases is displayed. This example is slightly more complicated than the usual Hello, world - just to show that there is a library.

What else do we see important? The code is organized into packages. And in order to use the package in your own code, you need to import it using the import directive - this is also important. We start - it works. Great!

Let's try something more complicated: Hello, world, but now it's an http server. What do we see interesting here?

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

First, the function acts as a parameter. This means that the function we have is a β€œfirst-class citizen” and you can do a lot of interesting things with it in a functional style. We see the unexpected next: the import directive refers directly to the GitHub repository. That's right, that's how it is - moreover, that's how it should be done.

In Go, a package's universal identifier is the url of its repository. There is a special Goget utility that goes for all the dependencies, downloads them, installs them, compiles them, and prepares them for use if necessary. At the same time, Goget knows about html-meta. Accordingly, you can keep an http directory, which will contain links to your specific repository (as we, for example, do).

What else do we see? Http and Json in the regular library. There is, obviously, introspection - reflection, which should be used in encoding / json, because we simply substitute some arbitrary object for it.

We run it and see that we have 20 lines of useful code that compiles, runs and gives the current average load of the machine (on the machine on which it is running).
What else is important from what we can immediately see here? It compiles into one static binary (buinary). This binary has no dependencies at all, no libraries! It can be copied to any system, run immediately, and it will work.

Moving on.

Go: methods and interfaces

Go has methods. You can declare a method for any custom type. Moreover, this is not necessarily a structure, but may be an alias of some type. You can declare an alias for N32 and write methods for it to do something useful.

And this is where we fall into a stupor for the first time ... It turns out that Go does not have classes as such. Those who know Go may say that there is type inclusion, but this is completely different. The sooner the developer stops thinking of it as inheritance, the better. There are no classes in Go, and there is no inheritance either.

Question! What did the company of authors led by Google give us in order to display the complexity of the world? We've been given interfaces!

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

An interface is a special type that allows you to write simple methods, method signatures. Further, any type for which these methods exist (are executed) will correspond to this interface. This means that you can simply write the corresponding function for one type, for another (which corresponds to that interface type). Next, declare a variable of the type of this interface and assign any of these objects to it.

For hardcore fans, I can say that this variable will actually contain two pointers: one to data, the other to a special descriptor table that is specific to this particular type, to the interface of this type. That is, the compiler makes such tables of descriptors at the time of linking.

And there are, of course, pointers to void in Go. The word interface {} (with two curly braces) is a variable that allows you to point to any object at all in principle.
So far, everything is in order, everything is familiar. Nothing surprising.

Go: goroutines

Now we come to what we are interested in: lightweight processes - goroutines (goroutines) in Go terminology.

Alexey Naidenov. ITooLabs. Development case on Go (Golang) phone platform. Part 1

  1. First, they are really lightweight (less than 2 Kb).
  2. Secondly, the cost of creating such a goroutine is negligible: you can create a thousand of them per second - nothing will happen.
  3. They are served by their own scheduler, which simply transfers control from one goroutine to another.
  4. In this case, control is transferred in the following cases:
    • if a go statement is encountered (if the goroutine starts the next goroutine);
    • if a blocking Input/Out call is enabled;
    • if garbage collection is triggered;
    • if some operation with channels is started.

That is, whenever a Go program is run on a computer, it detects the number of cores in the system, starts as many threads as needed (how many cores are in the system, or how many you told it to). Accordingly, the scheduler will run these lightweight threads of execution on all of these operating system threads in each core.

It should be noted that this is the most efficient way to utilize iron. In addition to what we have shown, we do a lot more. We make, for example, DPI systems that allow serving 40 gigabits in one unit (depending on what happens in these lines).

There, even before Go, we used exactly the same scheme for this very reason: because it allows you to save the locality of the processor cache, significantly reduce the number of OS context switches (which also takes a very long time). I repeat: this is the most effective way to utilize iron.

This simple 21-line example is an example that simply does echo-server. At the same time, note that the serve function is extremely simple, it is linear. There are no callbacks, no need to bother and think... You just read and write!

At the same time, if you read and write, it should actually block - this goroutine is simply queued and taken by the scheduler when execution becomes possible again. That is, this simple code can act as an echo server for as many connections as the OS on this machine will allow.

To be continued very soon...

Some ads πŸ™‚

Thank you for staying with us. Do you like our articles? Want to see more interesting content? Support us by placing an order or recommending to friends, cloud VPS for developers from $4.99, a unique analogue of entry-level servers, which was invented by us for you: The whole truth about VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps from $19 or how to share a server? (available with RAID1 and RAID10, up to 24 cores and up to 40GB DDR4).

Dell R730xd 2 times cheaper in Equinix Tier IV data center in Amsterdam? Only here 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV from $199 in the Netherlands! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - from $99! Read about How to build infrastructure corp. class with the use of Dell R730xd E5-2650 v4 servers worth 9000 euros for a penny?

Source: habr.com

Add a comment