What is the difference between Swoole efficiency and traditional web development?

First, the operation mode of swoole

What is the difference between Swoole efficiency and traditional web development? Except the traditional LAMP / LNMP synchronous development mode, what is the asynchronous development mode of swoole?

1.1, traditional web development model

PHP web development adopts the LAMP / LNMP architecture, namely Linux, Nginx, Mysql, and PHP. Here is an example of nginx, the general structure is:

When the request comes in, the web server forwards the request to PHP-FPM. PHP-FPM is a FastCGI service with a process pool architecture and a built-in PHP interpreter. FPM is responsible for interpreting and executing the PHP file to generate a response, which is finally returned to the web server and displayed to the front end. Many business logics are implemented in the PHP file, including access to Mysql and Nosql, calling third-party applications, and so on.

This structure works well with php-fpm and nginx, but because php-fpm itself is a synchronous blocking process model, all resources (including a series of objects created by the framework initialization) are released after the request ends, resulting in the PHP process "Idle" (create <-> destroy <-> create) consumes a lot of CPU resources, resulting in limited throughput of a single machine.

Each request processing process means a PHP file parsing, environment setting and other unnecessary time-consuming operations. The PHP process is destroyed immediately after processing. It is not possible to use the connection pool and other technologies in the PHP program to optimize performance.

1.2, Swoole operation mode

Aiming at the problems of traditional architecture, swoole started from the PHP extension to solve the above problems. We have just learned about the swoole process model.

Compared with the traditional architecture, the biggest feature of the Swoole process model is that its multi-threaded Reactor mode processes network requests, making it easy to handle a large number of connections.

Other advantages include:

Fully asynchronous and non-blocking, with low resource consumption and high program execution efficiency

The program runs and parses and loads the PHP file only once, avoiding repeated loading for each request

1.3, the disadvantages of using swoole and traditional php development

1. It's harder to get started. This requires developers to have a clearer understanding of the multi-process operating mode
2. Easier memory leaks. When dealing with global variables and static variables, you must be careful. Such variables that will not be cleaned up by the GC will exist throughout the life cycle. If they are not processed properly, it is easy to consume all the memory. Under php-fpm, the memory of PHP code is completely released after execution.

Annotation mechanism

In general, annotations are a concept parallel to annotations in programming sessions. Before explaining annotations, we need to define the differences between annotations and annotations:

Notes: Show it to programmers, help to understand the code, and play a role in explaining and explaining the code.

Annotations: For applications, annotations often act as a declaration and configuration of the code, providing additional information available to the machine for the executable code, which will affect the execution of the program under specific circumstances.

The framework can provide various additional functions for the code based on these meta-informations. Essentially, annotations are to understand that annotations are just another way to show configuration:

For example, the control of permissions through annotations is more convenient than configuration in the configuration file.

For example, use annotations to configure routing and configure scheduled tasks.

Many existing swoole-based frameworks are developed based on annotations, so we need to understand the annotation mechanism, and then use the code to implement the annotations


3.1 What is a container?

A container is a huge factory that is used to store and manage the life cycle of objects, and can resolve program dependencies and achieve decoupling.

3.2 Simple understanding of dependency injection through code

  /* * 1 / * * 
  * 耦合严重的写法  3 * */ 2 * severely coupled 3 * * /
 class  db { 4 class db { 
  public static  function get_db() { 5 public static function get_db () { 
  return new mysqli( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 ); 6 return new mysqli ( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 ); 
   } 7 } 
  } 8 } 
  class  post { 9 class post { 
  private  $db; 10 private $ db; 
  public  function __construct($db){ 11 public function __construct ($ db) { 
  // 假设数据库驱动发生了变化呢？ 12 // What if the database driver changes?  If you write, you can only change the code directly
 $ this ->db = new mysqli( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 ); } 13 $ this- > db = new mysqli ( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 );} 
  public  function get_post($id){ 14 public function get_post ($ id) { 
  return $ this ->db->query( ' SELECT * FROM post WHERE id = ' .$id); 15 return $ this- > db-> query ( ' SELECT * FROM post WHERE id = ' . $ Id); 
   } 16 } 
  } 17 } 
  $post = new  post(); 18 $ post = new post (); 
  $post->get_post( 12 ); 19 $ post-> get_post ( 12 ); 
 /* 21 / *
 *依赖注入的方式 23 */ 22 * Dependency injection 23 * /
 <? php 24 <? Php 
  class  db { 25 class db { 
  public static  function get_db() { 26 public static function get_db () { 
  return new mysqli( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 ); 27 return new mysqli ( ' ' , ' user ' , ' pass ' , ' dbname ' , 3306 ); 
   } 28 } 
  } 29 } 
  class  post { 30 class post { 
  private  $db; 31 private $ db; 
  public  function set_db(db $db){ 32 public function set_db (db $ db) { 
  $ this ->db =  $db; 33 $ this- > db = $ db; 
   } 34 } 
  public  function get_post($id){ 35 public function get_post ($ id) { 
  return $ this ->db->query( select xx from  xxx); 36 return $ this- > db-> query ( select xx from xxx); 
   } 37 } 
  } 38 } 
  $post = new  post(); 39 $ post = new post (); 
  $post->set_db( db::get_db() ); // 注入post类依赖的数据库连接对象,通过类名直接调用静态方法get_db 40 $ post-> set_db (db :: get_db ()); // Inject the database connection object that the post class depends on, and call the static method get_db directly through the class name
 $post->get_post( 11 ); 41 $ post-> get_post ( 11 ); 

When there is no Ioc / DI container

When the IoC / DI container is available, the post class no longer actively creates the db class, as shown in the following figure:

Dependency injection: When an instance of class B is used in class A, the construction of the B object is not initialized in a method of class A, but is passed in as an object of class B after external initialization of class A. This process is called dependency injection. The required class passes in the form of parameters as dependency injection.


IoC (Inversion of Control) refers to the transfer of control over the creation of an object. Previously, the initiative to create an object and the timing of its creation were controlled by itself, but now this power is transferred to a third party, such as the transfer to IOC container, it is a factory specifically used to create objects, what object you want, it will give you what object, with IOC container, the dependency relationship changes, the original dependency is gone, they all depend on the IOC container Now, through the IOC container to establish the relationship between them, the inversion of control means that the control of the dependent class is handed out and changed from active to passive.

3.3. Why is it more meaningful to use containers in swoole?

The traditional PHP framework does not have resident memory, so you need to instantiate the class you use every time a request comes in, you need to apply for memory for each instantiation, and you need to release it after the request is processed. For details, see the first point. , So we can put the class instantiation into memory in advance when the server starts, and reduce the creation time of the object.

A simple bean container

 class BeanFactory{ 2 private static $container= []; 3 4 public static function set ( string $name,callable $func){ 5 self::$container[$name]= $func; 6 } 7 8 9 public static function get ( string $name){ 10 if (isset(self::$container[$name])){ 11 return (self::$container[$name])(); 12 } 13 return null ; 14 } 15 } 1 class BeanFactory { 2 private static $ container = []; 3 4 public static function set ( string $ name, callable $ func) { 5 self :: $ container [$ name] = $ func; 6 } 7 8 9 public static function get ( string $ name) { 10 if (isset (self :: $ container [$ name])) { 11 return (self :: $ container [$ name]) (); 12 } 13 return null ; 14 } 15 } 

3.4 Swoole Process Structure

Swoole's efficiency is not only written in C at the bottom. His process structure model also enables it to efficiently handle business. We want to learn in depth and use it in actual scenarios. We must first understand the structure diagram.

First of all, what are the different processes of swoole?

From the names of these levels, let's first outline what the following levels do, and give a detailed explanation.

1.Master process: master process

2. Manger process: management process

3. Worker process: worker process

4, Task process: asynchronous task worker process

1.Master process

The first layer is the Master process. This is the main process of swoole. This process is driven by the core event handling of swoole. Then you can see that it has a MainReactor [thread] and several Reactor [threads]. All swoole event monitoring will be implemented in these threads, such as connection from the client, signal processing, etc.

Each thread has its own purpose, each thread has an understanding

1.1, MainReactor (main thread)

The main thread will be responsible for listening to the server socket. If there is a new connection accept, the main thread will evaluate the number of connections for each Reactor thread. This connection is allocated to the reactor thread with the least number of connections for load balancing.

1.2 Reactor thread group

The Reactor thread is responsible for maintaining the TCP connection of the client machine, processing network IO, and sending and receiving data in a completely asynchronous and non-blocking mode.

After accepting a new connection, the main thread of swoole will assign this connection to a fixed Reactor thread, read the data when the socket is readable, and analyze the protocol to deliver the request to the Worker process. Send data to the TCP client when the socket is writable.

1.3 Heartbeat Check Thread (HeartbeatCheck)

After Swoole is configured with heartbeat detection, the heartbeat packet thread will connect to all previous online connections within a fixed time.

Send detection packet

1.4, UDP packet receiving thread (UdpRecv)

Receive and process client udp packets

2. Management Process

To achieve the best performance, Swoole must create multiple worker processes to help process tasks, but the Worker process must fork, but the fork operation is not safe. If there is no management, there will be a lot of zombie processes, which will affect server performance. At the same time, the worker process is killed by mistake or exits abnormally due to program reasons. In order to ensure the stability of the service, the worker process needs to be re-created.

Swoole will create a separate management process during operation, and all worker processes and task processes are forked from the management process. The management process monitors the exit events of all child processes. When a fatal error occurs in the worker process or the end of the operating life cycle, the management process recycles this process and creates a new process. In other words, for the creation and recycling of worker and task processes, there is a full-service "nanny" Manager process for management.

Let's take another picture to sort out the relationship between the Manager process and the Worker / Task process.

3. Worker process

The worker process belongs to the main logical process of the swoole. The user processes a series of client requests, accepts request data packets delivered by the Reactor thread, and executes a PHP callback function to process the data to generate response data and send it to the Reactor thread. The Reactor thread sends it to the TCP client. Can be asynchronous non-blocking mode or synchronous blocking mode

4.Task process

The taskWorker process is an asynchronous worker process provided by swoole. These processes are mainly used to process some synchronous tasks that take a long time and are delivered in the worker process.

5, client and server interaction:

1. The client request reaches the Main Reactor, and the Client is actually connected to a Reactor thread in the Master process.

2. The Main Reactor registers the request to the corresponding Reactor according to the situation of the Reactor.

3.When the client changes, Reactor passes the data to the worker for processing

4. After the worker has finished processing, it sends it to the corresponding reactor through inter-process communication (such as pipes, shared memory, and message queues).

5, reactor sends the response result to the corresponding connection request processing is completed

schematic diagram:

A more popular analogy, assuming Server is a factory, then Reactor is sales and accept customer orders. Workers are workers. When sales receive orders, Workers go to work to produce what customers want. And Task_Worker can be understood as an administrative staff, which can help Workers do some chores and let Workers concentrate on their work.

6, the process of binding events

Callback function in the master process

  onStart Server starts in the main thread of the main process callback this function onShutdown This event occurs when the server ends normally 

Callback function in Manager process

  /task_worker进程发生异常后会在Manager进程内回调此函数 onManagerStart is called when the management process starts onManagerStop is called when the management process ends onWorkerError When the worker / task_worker process exception occurs, this function will be called back in the Manager process 

Callback function in Worker process

  onWorkerStart This event occurs when the Worker process / Task process starts. onWorkerStop This event occurs when the worker process terminates. 
  onConnect Call back onClose in the worker process when a new connection comes in. Call back this function in the worker process after the TCP client connection is closed. OnReceive Call back this function when data is received. Occurs when a new connection comes in onRequest in the worker process. Callback in the worker process onPacket This function is called back when a UDP packet is received, which occurs in the worker process onFinish When the task delivered by the worker process is completed in task_worker, the task process will send the result of the task processing to the worker through the finish () method process. 
  onWorkerExit is only valid when the reload_async feature is enabled.  Asynchronous restart feature onPipeMessage will trigger an event when a worker process receives a pipe message sent by sendMessage 

  Callback function in Task process 
  onTask is called inside the task_worker process.  / Task进程启动时发生onPipeMessage 当工作进程收到由sendMessage 发送的管道消息时会触发事件 The worker process can use the swoole_server_task function to deliver a new task to the task_worker process onWorkerStart This event occurs when the Worker process / Task process starts onPipeMessage This event is triggered when the worker process receives a pipe message sent by sendMessage 

3.5 Swoole operation mode and hot restart

Swoole excels because Swoole reduces the overhead of loading PHP files and initializing every request. However, this advantage also prevents developers from modifying PHP files and re-requesting, as they did in the past, to obtain the results of running new code. If new code needs to be executed, the server needs to be shut down and then restarted, so that the new file can be loaded into memory and run, which obviously cannot meet the needs of developers. Fortunately, Swoole provides such a feature.

In swoole, we can send various signals to the main process, and the main process does different processing according to the type of signal received. For example, the following

1. kill -SIGTERM master_pid terminates the Swoole program, an elegant termination signal, which will be interrupted after the process finishes executing the current program, rather than killing the process directly

2.kill -USR1 master_pid restarts all worker processes

3. kill -USR2 | -12 master_pid restarts all Task Worker processes

When the USR1 signal is sent to the Master process, the Master process will forward the same signal to the Worker process through the Manager process. After receiving this signal, the Worker process will release the process memory and close itself after processing the logic being executed. The Manager process restarts a new Worker process. The new Worker process will take up new memory space and reload the file.

Specific scenarios:

If it is an online project, a busy back-end server is processing the request at any time. If the administrator terminates / restarts the server program through the kill process, it may result in just half of the code execution.

In this case, the data will be inconsistent. For example, in the transaction system, the next paragraph of payment logic is shipping, assuming that the process is terminated after the payment logic. Will cause the user to pay the currency, but did not ship, the consequences are very serious.

How to solve?

At this time we need to consider how to smoothly restart the server. The so-called smooth restart, also called "hot restart", is to restart the service without affecting the user and update the PHP program code that has been loaded in memory to achieve the update of business logic.

Swoole provides us with a smooth restart mechanism. We only need to send a specific signal to the main process of swoole_server to complete the restart of the server.


1. The update is only for the worker process, that is, the update code written in the master process and the manger process does not take effect, that is to say, the restart only makes sense if the file is loaded after the onWorkerStart callback. A file that has been loaded into memory before the Worker process starts. If you want it to take effect again, you can only shut down the server and restart it.

2. The logic written directly in the worker code will not take effect. Even if a signal is sent, it will not take effect until the relevant business logic code is introduced through the include method.

Why do you need distributed services

4.1 Problems with Early Monolithic Architecture

The monolithic architecture works well when the scale is relatively small, but with the expansion of the system scale, it exposes more and more problems, mainly the following points:

1. Complexity is gradually increasing

For example, some projects have hundreds of thousands of lines of code, and the differences between the various modules are fuzzy and the logic is chaotic. The more code the more complex the code, the more difficult it is to solve the problems encountered.

2. Technical debt is rising

It is normal for the company's personnel flow. Before leaving, some employees were neglected by the code quality self-restraint, which led to a lot of pits. Due to the huge amount of code in individual projects, it was difficult to detect the pits left. This brings great annoyance to new employees. The larger the flow of people, the more pits are left, which is the so-called technical debt.

3. Obstructing technological innovation

For example, a previous project was written using tp3.2. Due to the inextricable connections between the various modules, the amount of code is large, and the logic is not clear enough. If you want to use tp5 to reconstruct this project now, it will be very difficult. The cost will be very large, so more often companies have to stick to their heads and continue to use the old monolithic architecture, which hinders technological innovation.

4. Can't scale on demand

For example, the recommended module is a CPU-intensive module, and the order module is an IO-intensive module. If we want to improve the performance of the order module, such as increasing the memory and adding hard disks, but all the modules are under one architecture, so We have to consider the factors of other modules when expanding the performance of the order module, because we cannot damage the performance of other modules by expanding the performance of one module, so we cannot scale as needed.

5. Poor system high availability

Because all functional development is ultimately deployed in the same framework and runs in the same process, once there is a problem with the code or resources involved in a function, it will affect the deployed functions in the entire framework.

5. What is RPC?

RPC (Remote Procedure Call) —Remote procedure call. It is a protocol that requests services from remote computer programs through the network without needing to understand the underlying network technology.

For example, two servers A and B, an application is deployed on server A. If you want to call the functions / methods provided by the application on server B, because they are not in a memory space and cannot be called directly, you need to express the semantics and Convey the data of the call, and this way is rpc

5.1. Why do we need RPC?

The main functional goal of RPC is to make it easier to build distributed computing (applications) without sacrificing the semantic simplicity of local calls while providing powerful remote call capabilities. To achieve this goal, the RPC framework needs to provide a transparent call mechanism so that users do not have to explicitly distinguish between local calls and remote calls.

Call ("listServices")-> info ();

RPC hides the details of communication. Calling a remote service is like calling local code. The calling protocol usually includes a transmission protocol and an encoding protocol.
Transmission protocol: can be custom tcp protocol, can be http, websockect
Encoding protocol: such as xml and json based on text encoding, and protobuf and binpack with binary encoding.

5.2. What protocol is used?

RPC is a software structure concept and the theoretical basis for building distributed applications. It's like why your family can use the electricity from the power plant?
Because electricity can be transmitted. As for whether to use copper wire or iron wire or other types of wires, that is, whether to use http or other protocols. This depends on what scenarios and performance requirements.

5.3 Is rpc just an interface call?

A complete rpc actually contains another piece of content. In addition to the communication protocol, there are "service registration discovery", error retry, service throttling, service call load balancing, and so on. Service governance.

5.4 Practical operation

Transmission protocol: TCP protocol

Encoding protocol: json encoding

I know the column