How to use PHP to build microservice?
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.
The challenge of servitization
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.
What is Swoft?
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.
Swoft Github
What do we need to build a microservice?
- High Performance Application Framework
- Service Registration and Discovery
- Service Circuit Breaker
- Service Restriction
- Configuration Center
Oh, Everything is ready in swoft
Swoft’s high performance
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, 100000
requests 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
.
Service Registration and Discovery
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
Service Circuit Breaker
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.
Service Restriction
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 App\Model\Logic;use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Limiter\Annotation\Mapping\RateLimiter;/**
* 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.
Configuration Center
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 App\Model\Logic;use Swoft\Apollo\Config;
use Swoft\Apollo\Exception\ApolloException;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\Annotation\Mapping\Inject;/**
* 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.
Conclusion
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.