📜 ⬆️ ⬇️

Go language, microservices and DevOps - the good company?

Hi, Habr!

We remind you that everyone can still purchase Sam's Newman's excellent book, Creating Microservices . Since our expectations this topic has more than met, we continue to look for literature related to it, and not so long ago we paid attention to the book on microservice programming in the Go language.


')
We found an interesting article on the rationale for this approach on the Agile Maverick blog, and its translation is placed under the cut.

Enjoy reading!



Now everyone is talking about microservices and DevOps. Put these words in your profile - and you will immediately begin to besiege recruiters. I visited Munich at several interesting meetings on microservices, and I was most surprised that this topic is of the most interest in the Java and Scala communities. I was surprised because Java and Scala are very rich languages ​​in which there is something to choose from.

When talking about microservices, it is often said that services should be small for the sake of reducing complexity and dependencies in implementation. But the richer the programming language, the more varied the dependencies there are. This is especially true in Java, where a lot of code is inherited.

I understand microservice architecture in a more holistic manner. I would say that the whole ecosystem should be simpler and more compact. Implementation - only one side of the coin. The other side is the execution time and the associated frameworks. Here we come to the topic of DevOps, a philosophy that seeks to link these two sides together.

Java virtual machine is optimized for working with long-playing applications, it has one of the most verified and intricate garbage collection systems. Used in combat conditions for over 10 years. However, when I see modern highly accessible architectures, the question immediately arises: do we need long-playing applications to implement the absolute majority of existing services?

I will give an example. I participated in the development of an application for video encoding, and this application unfortunately had to work around the clock with minimal delays. We thought about staying on a stable programming language like Java or writing an application on Go, where existing C libraries would be used for encoding and decoding, but such a project could result in memory leaks. Finally, we decided to split the application into different processes; The static backend almost did not change, since it transmitted information over a practically unchanged protocol, and we also had a functionally rich client part, where there was a risk of leaks. Both parts used shared memory. It turned out that the option is good. Since Go starts quickly, we restarted the client part every ten seconds. It turned out that the problem is not in memory leaks, but in operational updates.

For many years, Java has developed many non-trivial solutions - for example, the log4j framework for logging. Using the example of container solutions like OpenShift, we can make sure that it is now accepted to work with stdout and stderr again. There is no need to implement sophisticated logging solutions at the language level. This example allows you to judge how DevOps and new runtime environments change the rules of the game.

A typical docker image on a Go docker is about 15 MB in size; Compare it with the Java JVM image, which is about 300 MB. The difference is 1 to 10. Java JVM is optimized for economical memory consumption, but still requires about 10 times more memory than Go.

In Go, there are not so many inherited frameworks, so there are usually few dependencies, and the dependency code is included in the binary file. Therefore, there is no need for such complex tools as Maven. In a container environment, the release of a new image is needed whenever one of the dependencies in the chain changes. So, in Java, Java, we must update such containers quite often. Worse, the dependencies are usually hidden somewhere deep.

Java and Scala are languages ​​for object-oriented programming. But when working in relatively simple subject areas, such solutions seem rather costly to me. The “flexible” aspect of Go philosophy allows you to organize the development not only no worse, but also much more understandable.

Java is known for its huge pipeline and a variety of tools for continuous integration such as Jenkins, which have evolved around this pipeline. In Go, pipelines are much shorter, simpler and faster - after all, we get binary files that are already ready for execution.

In the 1990s, there was a real boom in Java application servers — they were thought to provide development independence from the operating system and hardware. While reading the JEE specification, we also counted on the ease of remote interactions and component-oriented development. When I see a docker container that runs Java applications, I always remember the new version of the EJB. In principle, the Java stack has not been simplified, but now it is packaged in a container. Such packaging is not given for nothing, because another level of complexity is added; You will get to know him as soon as you try to debug the network of such a docker container.

Go docker is an option for scaling services, but it does not save a complicated execution time environment. If you have only one simple service, then simple Go binaries can be executed directly on the host. If we are talking about a more complex application, then services can be put, for example, in a container and run them in a PaaS environment like OpenShift. To test the service on a developer's laptop, the container is not needed, and all the magic associated with it is also not needed.

Go is simple, and you learn it quickly enough. The basic concepts of Go are assimilated in just a week or two. Therefore, new colleagues can successfully explore the implementation of services, and developers or operators can fix bugs faster without being distracted from the main work, even if they did not implement these services. Autonomous teams are a good thing, but if you have only three colleagues, then it becomes really difficult to ensure around-the-clock accessibility.

Go, where there are not so many options, helps the developers who did not write it themselves to quickly get used to the solution. No need to delve into the development philosophy. Of course, you can always implement services in a simpler style in more saturated languages, for example, in Java or Scala, but in this case you need to learn self-restraint, discuss all the details with the team - respectively, the microservice architecture is overgrown with huge documentation.

It seems to me that Go is perfect for implementing microservices. Why is this language so slowly assimilated in the developer community?

I think just no one likes drastic changes. We tried to change just one dimension in the multidimensional programming world. This measurement is the size of the service. In my experience, changing one dimension is not enough to go evolution. Since all measurements are interrelated, they affect each other. Having decided to simplify the application, remaking it in the form of microservices, we must also simplify both the runtime environment and the programming language with which we work. Otherwise, we will get only a new headache - for example, we will have to manage multiple JVMs at once, which take up a lot of memory space and start up rather slowly. Or we get a lot of small object-oriented solutions that will be distributed, and therefore more complex. Finally, we’ll just get confused with the many services that make up the huge dependency tree.

In my opinion, without changing all the dimensions at once, we seem to be transplanting from a horse to a car, but we take with us the saddle and the spurs.

Let's not just write microservices, but also adapt the whole architecture for them. Go is great for this. If the service domain expands, you can always use additionally Java or Scala.

Source: https://habr.com/ru/post/304040/


All Articles