Good projects need good solutions; this is why developers are always looking for better ways to do their jobs. There is no best solution for all projects because every single project has different needs and the architect (or the developer) has to find the best solution for that specific project.
Microservices are maybe a good approach to solve problems; in the last few years, companies such as Netflix, PayPal, eBay, Amazon, and Spotify have chosen to use microservices in their own development teams because they believed them to be the best solution for their projects. To understand why they chose microservices and understand the kinds of projects you should use them in, it is necessary to know what a microservice is.
Firstly, it is essential to understand what a monolithic application is, but basically, we can define a microservice as an extended Service Oriented Architecture. In other words, it is a way to develop an application by following the required steps to turn it into various little services. Each service will execute itself and communicate with others through requests, usually using APIs on HTTP.
To further understand what microservices are, we first need to understand what a monolithic application is. It is the typical application that we have been developing for the last few years, for example in PHP, using a framework like Symfony; in other words, all the applications we have been developing are divided into different parts, such as frontend, backend, and database, and also use the Model-View-Controller (MVC) pattern. It is important to differentiate between MVC and microservices. MVC is a design pattern and microservices are a way to develop an application; therefore, applications developed using MVC could still be monolithic applications. People may think that if we split our application into different machines and divide the business logic from the model and the view, the application is then based on microservices, but this is not correct.
However, using a monolithic architecture still has its advantages. There are also various huge web applications, such as Facebook, that use it; we just need to know when we need to use a monolithic architecture and when we need to use microservices.
Now, we will discuss the advantages and disadvantages of using monolithic applications and how microservices improve a specific project by giving a basic example.
Imagine a taxi platform like Uber; the platform in this example will be a small one with only the basic things in order to understand the definitions. There are customers, drivers, cities, and a system to track the location of the taxi in real time:
In a monolithic system, we have all this together---we have a common database with the customers and drivers linked to cities and all these are linked to the system to track taxis using foreign keys.
All this can also be hosted on different machines using master-slave databases; the backend can be in different instances using a load balancer or a reverse proxy and the frontend can use a different technology using Node.js or even plain HTML. Even so, the platform will be a monolithic application.
Lets see an example of possible problems faced in a monolithic application:
Two developers, Joe and John, are working on the basic taxi example project; Joe needs to change some code on drivers and John has to change some code on customers. The first problem is that both the developers are working on the same base code; this is not an exclusive monolithic problem but if Joe needs to add a new field on drivers, he may need to change the customer's model too, so Joe's work does not finish on the driver's side; in other words, his work is not delimited. This is what happens when we use monolithic applications.
Joe and John have realized that the system to track taxis has to communicate with third parties calling external APIs. The application does not have a very big load but the system to track taxis has a lot of requests from customers and drivers, so there is a bottleneck on that side. Joe and John have to scale it to solve the problem on the tracking system: they can get faster machines, more memory, and a load balancer, but the problem is that they have to scale the entire application.
Joe and John are happy; they just finished fixing the problem on the system to track taxis. Now they will put the changes on the production server. They will have to work tonight when the traffic on the web application is lower; the risk is high because they have to deploy the entire application and not just the system to track taxis that they fixed.
In a couple of hours, an error 500 appears within the application. Joe and John know that the problem is related to the tracking system, but the entire application will be down only because there is a problem with a part of the application.
A microservice is a simple, isolated entity with a concrete proposal. It is independent and works with the rest of the microservices by communicating through an agreed channel as you can see in the next picture:
For developers who are used to working on object-oriented programming, the idea of a microservice would be something like an encapsulated object working on a different machine and isolated from the other ones working on different machines too.
Following the same example as before, if we have a problem on the system to track taxis, it would be necessary to isolate all the code related to this part of the application. This is a little complex and will be explained in detail in Chapter 9, From Monolithic to Microservices, but in general terms, it is a database used exclusively by the system to track taxis, so we need to extract the part for this purpose and the code needs to be modified to work with the extracted database. Once the goal is achieved, we will have a microservice with an API (or any other channel) that can be called by the rest of the monolithic application.
This will avoid the problems mentioned before---Joe and John can work on their own issue because once the application is divided into microservices, they will work on the customer or driver microservice. If Joe has to change code or include a new field, he will only need to change it in his own entity and John will consume the drivers API to communicate with it from the customer's part.
The scalability can be done just for this microservice, so it is not necessary to scale the entire application by spending money and resources and if the system to track taxis is down, the rest of the application will work without any problems.
Another advantage of using microservices is that they are agnostic to the language; in other words, it is possible to use different languages for each microservice. A microservice written in PHP can talk to others written in Python or Ruby because they only give the API to the rest of the microservices, so they just have to share the same interface to communicate with each other.
When a developer encounters microservices and they know the Service Oriented Architecture (SOA) style of software design, the first question they ask themselves is whether SOA and microservices are the same thing or whether they are related, and the answer is a little bit controversial; depending on who you ask, the answer will be different.
According to Martin Fowler, SOA focuses on integrating monolithic applications between themselves, and it uses an Enterprise Service Bus (ESB) to achieve this.
When the SOA architectures began to appear, these ones tried to connect different components between themselves, and this is one of the characteristics of microservices, but the problem with SOA was that it needed many things surrounding the architecture to work properly, such as ESB, Business process management (BPM), service repositories, register, and more things, so it made it more difficult to develop. Also, in order to change some parts of a code, it was necessary to agree with the other development teams before doing it.
All these things made the maintenance and code evolution difficult, and the time to market long; in other words, this architecture was not the best for applications that often needed to make changes live.
There are other opinions regarding SOA. Some say that SOA and microservices are the same, but SOA is the theory and microservices is a good implementation. The need to use an ESB or communicate using WSDL or WADL was not a must, but it was defined as the SOA standard. As you can see on the next picture, your architecture using SOA and ESB will look like this:
The requests arrive via different ways; this is the same way microservices work, but all the requests reach the ESB and it knows where it should call to get the data.
Next, we will look at the key elements of a microservice architecture:
Ready to fail: Microservices are designed to fail. In a web application, microservices communicate with each other and if one of them fails, the rest should work to avoid a cascading failure. Basically, microservices attempt to avoid communicating synchronously using async calls, queues, systems based on actors, and streams instead. This topic will be discussed in the subsequent chapters.
Unix philosophy: Microservices should follow the Unix philosophy. Each microservice must be designed to do one thing only, and should only be small and independent. This allows us as developers to adjust and deploy each microservice independently. The Unix philosophy emphasizes building simple, short, clear, modular, and extensible code that can be easily maintained and repurposed by developers as well, in addition to its creators.
Communication layer: Each microservice communicates with the others through HTTP requests and messages, executing the business logic, querying the database, exchanging messages with the required systems and, at the end, returning a JSON (or HTML/XML) response.
Scalability: The main reason to choose a microservice architecture is that it is possible to scale the application easily. The bigger an application is and the more traffic the application has, the more sense the proper selection of choosing microservices makes. A microservice can scale the required part without any impact on the rest of the application.
The best way to understand how important microservices are in real life is knowing some platforms that decided to evolve and use microservices thinking about the future and making the maintenance and scalability easier, faster, and more effective:
Netflix: The number one application for online video streaming turned its architecture into microservices a few years ago. There is a story about the reason they decided to use microservices. Making changes on a review module, a developer forgot to put the
;at the end of the line and Netflix was down for many hours. The platform gets around 30% of the total traffic from the USA every day, so Netflix has to offer a stable service to its customers who pay every month. To get this, Netflix makes five requests to its different servers for each request that we make and it can get requests from 800 different devices using its streaming video API.
eBay: In 2007, eBay decided to change its architecture to microservices; it used a monolithic application on C++ and Perl, later they moved to services built on Java, and finally they implemented their architecture using microservices. Its main application has many services and each one executes its own logic to be used by the customers in each area.
Uber: Microservices allowed this company to grow quickly because it allowed it to use different languages (Node.js, Go, Scala, Java, or Python) for each microservice and the process of hiring engineers was easier because they were not limited by the language code.
Amazon: Maybe Amazon is not the king of Internet traffic, but it moved to microservices a few years ago, being one of the first ones to use live microservices. The engineers said that it was not possible to provide all the services they offer, such as the web service, using the old monolithic application.
Spotify: The need to be faster than its opponent was a must for Spotify. The main engineer, Niklas Gustavsson, said that being fast, automating everything, and having smaller teams of development is really important for the application. This is the reason Spotify uses microservices.
Next, we will look at the disadvantages of the microservices architecture. When asking developers about this, they agree that the major problem with microservices is the debugging on the production server.
Debugging an application based on microservices can be a little tedious when you have hundreds of microservices in your application and you have to find where a problem is; you need to spend time looking for the microservice that is giving you the error. Each microservice works like an individual machine, so to look at a specific log you have to go to the specific microservice. Fortunately, there are some tools to help us out with this subject by getting the logs from all the different microservices in your application and putting them together into a single location. In the subsequent chapters, we will look at these kinds of tools.
Another disadvantage is that it is necessary to maintain every single microservice as an entire server; in other words, every single microservice can have one or more databases, logs, different services, or library versions, and even the code can be in a different language, so if it is difficult to maintain a single server and doing it with hundreds will waste money and time.
Also, the communication between microservices is very important---they have to work like clocks, so communication is essential for the application. To do this, the communication between the development teams will be necessary to tell each other what they need and also to write good documentation for each microservice.
A good practice to work with microservices is having everything automatized or at least everything possible. Maybe the most important part is the deployment. If it is necessary to deploy hundreds of microservices, it can be difficult. So, the best way is to automatize these kinds of tasks. We will look at how to do this in the subsequent chapters.
Developing microservices is a new way of thinking. Therefore, it can be difficult when you encounter how the application will be designed and built for the first time. However, if you always remember that the most important idea behind microservices is the need to decompose your application into smaller logical pieces, you are already halfway there.
Once you understand this, the following core ideas will help you with the design and build process of your application.
As a developer, you always start with the big picture of what you will build. Try to decompose the big picture into small logical blocks that only do one thing. Once the multiple small pieces are ready, you can start building complex systems, ensuring that the foundations of your application are solid.
Each of your microservices is like a black box with a public interface, which is the only way to interact with your software. The main recommendation you need to have always in mind is to build a very stable API. You can change the implementation of an API call without many problems, but if you change the way of calling or even the response of this call, you will be in big trouble. In the case of deep changes to your API, ensure that you use some kind of versioning so that you can support the old and new versions.
The communication between services is made through API calls using the network as a connection pipe. This message exchange takes some time and it will not always be the same due to multiple factors. Imagine that you have service_a on one machine and a service_b on a different machine. Do you think that the network latency will always be the same? What happens if, for example, one of the servers is under a high load and takes some time to process requests? To reduce time, always keep an eye on your infrastructure, monitor everything, and use compression if it is available.
One of the main advantages of a microservice application is that each service can be scaled up or down. This flexibility can be achieved by reducing the number of stateful services to the minimum. A stateful service relies on data persistence, making it difficult to move or share the data without having data consistency problems.
Using autodiscovery and autoregistry techniques, you can build a system that knows which one will deal with each request at all times.
Nobody likes to wait, not even your microservices. Don't try to reinvent the wheel or use an obscure but cool communication protocol, use HTTP and REST. They are known by all web developers, they are fast, reliable, easy to implement, and very easy to debug. If you need to increase the security, implement SSL/TSL.
As a developer, you want to make your system as fast as possible. Therefore, it makes no sense to increase the execution time of an API call just because it is waiting for some action that can be done in the background. In these cases, the best approach is the use of queues and job runners in charge of this background processing.
Imagine that you have a notification system that sends an e-mail to a customer when placing an order on your microservice e-commerce. Do you think that the customer wants to wait to see the payment successful page only because the system is trying to send an e-mail? In this case, a better approach is to enqueue the message so that the customer will have a pretty instant thank you page. Later, a job runner will pick up the queued notification and the e-mail will be sent to the customer.
You have a nice, new, good-looking site built on top of microservices. Are you ready for the moment when everything goes wrong? If you are suffering a network partition, do you know if your application will recover from that situation? Now, imagine that you have a recommendation system and it is down, are you going to give the customers a default recommendation while you try to recover the dead service? Welcome to the world of distributed systems where when something goes wrong, it can get worse. Always keep this in mind and try to be ready for any scenario.
We are decomposing an application into small parts which we want to scale and deploy independently, so it makes sense to keep the source in different repositories. Having different build environments and repositories means that each microservice has its own lifecycle and can be deployed without affecting the rest of your application.
In the subsequent chapters, we will take a deeper look at all these ideas and how to implement them using different driven developments.
To understand why PHP is a suitable programming language for building microservices, we need to take a small peek into its history, where it comes from, which problems it was trying to solve, and the evolution of the language.
In 1994, Rasmus Lerdorf created what we can say was the first version of PHP. He built a small suite of Common Gateway Interfaces (CGIs) in the C programming language to maintain his personal web page. This suite of scripts was called Personal Home Page Tools, but it was more commonly referenced as PHP Tools.
Time passed and Rasmus rewrote and extended the suite so that it could work with web forms and have the ability to communicate with databases. This new implementation was called Personal Home Page/Forms Interpreter or PHP/FI and served as a framework upon which other developers could build dynamic web applications. In June 1995, the source code was opened to the public under the name of Personal Home Page Tools (PHP Tools) version 1.0, allowing developers from all over the world to use it, fix bugs and improve the suite.
The first idea around PHP/FI was not to create a new programming language, and Lerdorf let it grow organically, leading to some problems like the inconsistency of function names or their parameters. Sometimes the function names were the same as the low-level libraries that PHP was using.
In October 1995, Rasmus released a new rewrite of the code; this was the first release that was considered as an advanced scripting interface and PHP started to become the programming language that it is today.
As a language, PHP was designed to be very similar to C in structure so that it would be easier to be adopted by developers who were familiar with C, Perl, or similar languages. Along with the growth of the features of the language, the number of early adopters also began to grow. A Netcraft survey of May, 1998 indicated that nearly 60,000 domains had headers containing PHP (around 1% of the domains on the Internet at the time), which indicated that the hosting server had it installed.
One important point in PHP history was when Andi Gutmans and Zeev Suraski of Tel Aviv, Israel, joined the project in 1997. At this time, they did another complete rewrite of the parser and started the development of a new and independent programming language. This new language was named PHP, with the meaning becoming a recursive acronym---PHP (Hypertext Preprocessor).
The official release of PHP 3 was in June 1998, including a great number of features that made the language suitable for all kinds of projects. Some of the features included were a mature interface for multiple databases, support for multiple protocols and APIs, and the ease of extending the language itself. Among all the features, the most important ones were the inclusion of object-oriented programming and a more powerful and consistent language syntax.
Andi Gutmans and Zeev Suraski founded Zend Technologies and started the rewrite of PHP's core, creating the Zend Engine in 1999. Zend Technologies became the most important PHP company and the main contributor to the source code.
This was only the beginning and as years passed, PHP grew in features, language stability, maturity, and developer adoption.
Now that we have some historical background, we can focus on the main milestones achieved by PHP throughout the years. Each release increased the language stability and added more and more features.
PHP 4 was the first release, which included the Zend Engine. This engine increased the average performance of PHP. Along with the Zend Engine, PHP 4 included support for more web servers, HTTP sessions, output buffering, and increased security.
PHP 5 was released on July 13, 2004 using the Zend Engine II, which increased the language performance once again. This release included important improvements for object-oriented (OO) programming, making the language more flexible and robust. Now, users were able to choose between developing applications in a procedural or a stable OO way; they could have the best of both worlds. In this release, one of the most important extensions used to connect to data stores was also included---the PHP Data Objects (PDO) extension.
With PHP 5 becoming the most stable version in 2008, many open source projects started ending their support for PHP 4 in their new code.
This release was one of the most famous failures for PHP. The development of this major release started in 2005 but, in 2010, it was abandoned due to difficulties with the Unicode implementation. Not all the work was thrown away and most of the features, one of them being namespaces, were added to the previous releases. As a side note, version 6 is generally associated with a failure in the tech world: PHP 6, Perl 6, and even MySQL 6 were never released.
This was a long awaited release---one release to rule them all and a release with performance levels seen never before.
On December 3, 2015, version 7.0.0 was released with the last Zend Engine available. The performance increase obtained only by changing the running version on your machine reached up to 70%, with a very small memory footprint.
The language also evolved, and PHP now had a better 64-bit support and a secure random number generator. Now you could create anonymous classes or define return types among other major changes.
This release became serious competition to the other so-called enterprise languages.
PHP is one of the most used programming languages you can use to build your web projects. In case you are not yet sure if PHP is the appropriate language for your next application, let us now to tell you the main advantages of using PHP:
Big community: It's very easy to engage in conferences, events, and meetups all over the world with ZendCon, PHP[world], or International PHP Conference. Not only can you talk to other PHP developers at events and conferences, but you can join IRC/Slack channels or mailing lists to ask questions and keep yourself updated. One of the many locations where you can find events near your area is on the official site at http://php.net/cal.php.
Great documentation: The main point of information about the language is available on the PHP website (http://php.net/docs.php). This reference guide covers every aspect of PHP, from basic control flows to advanced topics. Do you want to read a book? No problem, it will be easy to find a suitable book among more than 15,000 Amazon references. Even if you need more information, a quick search on Google will give you more than 9,300,000,000 results.
Stable: The PHP project makes frequent releases and maintains several major releases at the same time until their scheduled End Of Life (EOL). Usually, the time between a release and its EOL is enough to move to the next mainstream version.
Easy to deploy: PHP is the most popular server-side programming language with an 81.8% usage in August 2016, so the market moves in the same direction. It is very easy to find a hosting provider with PHP preinstalled and ready to use, so you only need to deal with the deploy.
There are a number of ways of deploying your code into production. For instance, you can track your code in a Git repository and do a Git pull on your server later. You could also push your files through FTP to the public location.You can even build a Continuous Integration/Continuous Delivery (CI/CD) system with Jenkins, Docker, Terraform, Packer, Ansible, or other tools. The complexity of the deploy will always match the project complexity.
Easy to install: PHP has prebuilt packages for the major operating systems: it can be installed on Linux, Mac, Windows, or Unix. Sometimes the packages are available inside the package system (for instance, apt). In other cases, you need external tools to install it, such as Homebrew. In the worst case scenario, you can download the source code and compile it on your machine.
Open Source: All the PHP source code is available at GitHub, so it is really simple for any developer to take a deep look at how everything works. This openness allows a programmer to participate in the project, extending the language or fixing the bugs. The license used in PHP is a Berkeley Software Distribution (BSD) style license without the copyleft restrictions associated with GPL.
High running speed (PHP 7): In the past, PHP was not fast enough, but this situation changed completely with PHP 7. This major release is based on the PHP Next-Gen (PHPNG) project with Zend Technologies as the leader. The idea behind PHPNG was to speed up PHP applications and they did this very well. The performance gains can vary between 25% and 70% only by changing the PHP version.
High number of frameworks and libraries available: The PHP ecosystem is very rich in libraries and frameworks. The common way to find a suitable library for your project is using PEAR and PECL.
Regarding the available frameworks, you can use one of the best, for example Zend Framework, Symfony, Laravel, Phalcon, CodeIgniter, or you can build one from scratch if you can't find one that meets your requirements. The best part about this is that all of these are open source, so you can always extend them.
High development speed: PHP has a relatively small learning curve, which can help you start coding from the beginning. Also, the similarities in syntax with C, Perl, and other languages can make you understand how everything works in no time. PHP avoids wasting time waiting for the compiler to generate our build.
Easy to debug: As you probably know, PHP is an interpreted language. Therefore, when trying to solve an issue, you have multiple options to succeed. The easy way is dropping a few
print_rcalls to view what the code is doing. For a deeper view of the execution, you can link your IDE to Xdebug or Zend Debug and start tracing your application.
Easy to test: No modern programming language will survive in the wild without an appropriate test suite, so you have to ensure that your application will continue running as expected. Don't worry, the PHP community has your back as you have available multiple tools to do any kind of tests. For instance, you can use PHPUnit for your Test Driven Development (TDD), or Behat if you are following a Behavior Driven Development (BDD).
You can do anything: PHP is a modern programming language with multiple applications in the real world. Therefore, only sky is the limit! You can build a GUI application using the GTK extension, or you can create a terminal command with all the required files in a phar archive. The language has no limitations, so anything can be built.
Like any programming language, PHP also has some disadvantages. Some of the most common mentioned disadvantages flagged are: security issues, unsuitable for large applications, and weak types. PHP started as a collection of CGIs and has become more modern and robust throughout the years, so it is pretty robust and flexible for a young programming language (in comparison with other languages).
In any case, an experienced developer will have no problem overcoming these disadvantages when building their application if they use the best practices.
As you can already see, the evolution of PHP was enormous. It has one of the most vibrant communities, was made for the web, and has all the power you need to create any kind of project. Without a doubt, PHP will be the right language for you to express your best ideas.
In this chapter, we looked at how microservices stand against monolithic architecture and SOA. We learned about the essential components of microservices architecture along with its advantages and disadvantages. Further along the chapter, we looked at how to implement the microservices architecture and the prerequisites to take into consideration before switching to microservices. Later, we covered the history of PHP versions along with their advantages and disadvantages.