How to use PHP to build microservice?

 

Simon Tony

In this article, we mainly introduce how to use PHP to build a microservices architecture. Knowing that PHP is also advancing with the times, it is also capable of supporting microservice architectures for large systems.

Php uses traditional framework (laravel,yii, symfony) to implement microservice, the effect is very poor.

Why?

In the development mode of fpm, because the resident memory cannot be provided, every request must begin from zero by starting to load a process to exit the process, adding a lot of useless overhead.

Also, the database connection can not be reused and can not be protected because fpm is the process-based and the number of fpm process also determines the number of concurrent. These are the problems given to us by the simple of the fpm development.

It is not friendly enough with microservice tools such as docker and must rely on nginx to provide services.

So, these are the reasons why Java is more popular now in the Internet platform comparing to PHP. Apart from PHP non-memory resident, there are many other issues are need to be addressed.

Let’s see how Swoft implements microservice.

Swoft is a PHP microservices coroutine framework based on the Swoole extension. Like Go, Swoft has a built-in coroutine web server and a common coroutine client and is resident in memory, independent of traditional PHP-FPM.

There are similar Go language operations, similar to the Spring Cloud framework flexible annotations, powerful global dependency injection container, comprehensive service governance, flexible and powerful AOP, standard PSR specification implementation and so on.

  • High Performance Application Framework
  • Service Registration and Discovery
  • Service Circuit Breaker
  • Service Restriction
  • Configuration Center

Oh, Everything is ready in swoft

You can imagine the benefits that resident memory brings to us.

  • Only start framework initialization once we can concentrate on processing requests as framework can be only initialized in memory on startup in once for resident memory
  • Connection multiplexing, some engineers can not understand if not using connections pool, what is the consequence of making connections for every request? It causes too much backend resource in connections. For some basic services, such as Redis, databases, connections are an expensive drain.

So, is there a good solution? The answer is yes, and many people are using the framework called Swoft. Swoft is a RPC framework with the Service Governance feature. Swoft is the first PHP resident memory coroutine full-stack framework, based on the core concept of the Spring Boot, convention is greater than the configuration.

Swoft provides a more elegant way to use RPC services like Dubbo and Swoft has great performance similar to Golang performance. Here is the stress test result of Swoft performance happening in my PC.

Processing speed is very amazing in the ab stress test. With the i7 generation 8 CPU and 16GB memory, 100000requests only use 5s. The time is basically impossible to be achieved in the fpm development mode.

The test is also sufficient to demonstrate the high performance and stability of Swoft.

In the microservice governance process, registration of services initiated to third-party clusters, such as consul/etcd, is often involved. This chapter uses the swoft-consul component in the Swoft framework to implement service registration and discovery.

Implementation logic

In the basic circuit breaker mode, to ensure supplier is not called when the circuit breaker is in the open state, but we also need additional method to reset the circuit breaker after the supplier resumes service.

One possible solution is that the circuit breaker periodically detects whether the service of the supplier is resumed. Once resumed, the status is set to close. The state is a half-open state when the circuit breaker retries.

The use of the fuse is simple and powerful. It can be annotated with a @Breaker. The fuse of the Swoft can be used in any scenario, such as a service is called. It can be downgraded or not called when requesting a third party service.

Flow Restriction, Circuit Breaker, Service Downgrade These can be emphasized repeatedly because they are really important. When the service is not working, it must be broken. Flow restriction is a tool to protect itself. If there is no self-protection mechanism and connections are received no matter how many they are, the front-end will definitely hang when traffic is very large while the back-end can not handle all connections.

The flow restriction is to limit the number of concurrent and number of requests when accessing scarce resources, such as flash sale goods, so as to effectively cut the peak and smooth the flow curve.

The purpose of flow restriction is to limit the rate of concurrent access and concurrent requests, or to limit the speed of request within a window of time to protect the system. Once the rate limit is reached or exceeded, the requests can be denied, or queued.

The bottom layer of the flow restriction of Swoft uses the token bucket algorithm, and the underlying layer relies on Redis to implement distributed flow restriction.

The Swoft flow restriction not only limits controllers, it also limits the methods in any bean and controls the access rate of the methods. The following example is the explanation in detail.

<?php declare(strict_types=1);namespace AppModelLogic;use SwoftBeanAnnotationMappingBean;
use SwoftLimiterAnnotationMappingRateLimiter;/**
* Class LimiterLogic
*
* @since 2.0
*
* @Bean()
*/
class LimiterLogic
{
/**
* @RequestMapping()
* @RateLimiter(rate=20, fallback="limiterFallback")
*
* @param Request $request
*
* @return array
*/
public function requestLimiter2(Request $request): array
{
$uri = $request->getUriPath();
return ['requestLimiter2', $uri];
}

/**
* @param Request $request
*
* @return array
*/
public function limiterFallback(Request $request): array
{
$uri = $request->getUriPath();
return [‘limiterFallback’, $uri];
}
}

 

This supports the symfony/expression-language expression. If the speed is limited, the limiterFallback method defined in fallback will be called.

Before we talk about the configuration center, let’s talk about the configuration file. We are no stranger to it. It provides us with the ability to dynamically modify the program. A quote from someone is:

Dynamic adjustment of the flight attitude of the system runtime!

For the stand-alone version, we call it the configuration (file); for the distributed cluster system, we call it the configuration center (system);

This chapter uses Apollo as an example to pull configuration and secure restart services from the remote configuration center. If you are unfamiliar with Apollo, you can first look at the Swoft extension Apollo component and read Apollo Official documentation.

This chapter uses Apollo in Swoft as an example. When the Apollo configuration changes, restart the service (http-server / rpc-server/ ws-server). The following is an example of an agent:

<?php declare(strict_types=1);
namespace AppModelLogic;use SwoftApolloConfig;
use SwoftApolloExceptionApolloException;
use SwoftBeanAnnotationMappingBean;
use SwoftBeanAnnotationMappingInject;/**
* Class ApolloLogic
*
* @since 2.0
*
* @Bean()
*/
class ApolloLogic
{
/**
* @Inject()
*
* @var Config
*/
private $config;    /**
* @throws ApolloException
*/
public function pull(): void
{
$data = $this->config->pull('application');

// Print data
var_dump($data);
}
}

 

The above is a simple Apollo configuration pull, in addition to this method, Swoft-Apollo provides more ways to use.

At this point, our simple microservices framework has been built. If you use the traditional PHP framework, it is very difficult to achieve. But using Swoft is very easy.