当前位置:网站首页>Implementation of message queue system and underlying source code based on redis

Implementation of message queue system and underlying source code based on redis

2022-06-09 00:12:00 weixin_ two billion forty-seven million six hundred and seventy

Introduction to message queuing

A complete queue system consists of three components :

  • queue (Queue)
  • news (Message)
  • Process (Worker)

The corresponding basic workflow is the producer ( Business code ) First push the message data to the queue , And then consume the message data in the queue through other processing processes , So as to realize the decoupling between producers and consumers . therefore , Message queuing is ideal for time-consuming operations that require asynchronous execution ( E.g. email sending 、 Upload files ), Or temporary high concurrency operations ( For example, seckill 、 Message push ), It is very effective for improving system performance and load , In especial PHP This language does not support concurrent programming by itself , It is the best choice for asynchronous programming .

Before demonstrating how to implement message queuing , Let's briefly introduce the above three components .

queue

Queues are actually linear data structures , This is what you are Data structure Has been described in detail in , This data structure has first in first out (FIFO) Characteristics , Therefore, it is very suitable for decoupling between producers and consumers , At the same time, it does not affect the execution sequence of business logic .

stay PHP in , You can use native array functions or  SplQueue  Class can easily implement data structures like queues , But here we introduce Redis, So you can also use Redis Self contained List the type To achieve .

We can improve the system performance through queue asynchronous implementation of the browse number update operation in the previous tutorial . To simplify the process , We go through  post-views-increment  To identify the queue name , The message data pushed to the queue passes through the article ID Are identified :

/  Article views  +1
public function addViews(Post $post)
{
    //  Push message data to the queue , Handle database updates through asynchronous processes 
    Redis::rpush('post-views-increment', $post->id);
    return ++$post->views;
}

news

The so-called news , That is, the data pushed to the queue , It's usually a string , If it is a non string type , It can be converted to a string by serialization , After the processing process at the consumer gets the message data from the queue , It can be parsed , Complete the closed loop of business logic .

The producer or the message itself does not have to care about how the consumer processing process handles the message data , The processing process on the consumer side does not have to care who sent the message , The three are completely decoupled , But it also builds a bridge between producers and consumers through message data .

Message data can be passed inside the application , It can also be passed across applications , Cross application delivery usually requires the help of third-party Message Queuing Middleware , For example, based on Redis Implementation of the queue system 、RabbitMQ、Kafka、RocketMQ etc. .

In the example code above , We will be writing ID As message data .

Process

The consumer process is usually one or more memory resident processes , They either subscribe to or poll message queues , If the message queue is not empty , Then take out the message data and process it .

In order to simplify the process , We create a Artisan Command to simulate a memory resident polling process as a message processor :

php artisan make:command MockQueueWorker

And write its implementation code as follows :

<?php

namespace App\Console\Commands;

use App\Models\Post;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class MockQueueWorker extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'mock:queue-worker';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Mock Queue Worker';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info(' Listen message queue  post-views-increment...');
        while (true) {
            //  Get the message data from the queue 
            $postId = Redis::lpop('post-views-increment');
            //  Number of views of the current article  +1, And stored in the corresponding  Sorted Set  Of  score  Field 
            if ($postId && Post::newQuery()->where('id', $postId)->increment('views')) {
                Redis::zincrby('popular_posts', 1, $postId);
                $this->info(" Update article  #{$postId}  Browse number ");
            }
        }
    }
}

Focus on  handle  Method , We go through  while (true)  Analog resident memory , Then keep polling  post-views-increment  queue , If there is an article ID data , Then take out and update the number of article views .

thus , We have implemented a simple message queue , Start the message handler :

Then visit any article  http://redis.test/posts/1, You can see the task processing record of the queue in the queue processor window :

At the same time, you can see the updated number of views in the database , Prove that the queue message is processed successfully .

The above process is also Laravel The basic principle of the underlying implementation of the queue system , With this knowledge reserve , Let's look at Laravel The underlying implementation of message queuing will be much easier .

Laravel Implementation and use of queue system

Basic configuration

however ,Laravel Provides a more elegant Queue system Realization , We don't need to write queues manually 、 Implementation code of message and processing process , And support different queue system drivers , Include database 、Beanstalkd、Amazon SQS、Redis etc. , Here, of course, we take Redis For example .

To be in Laravel Project use Redis Implement the queue system , Just configure it Redis After connecting the information, the environment configuration file  .env  Medium  QUEUE_CONNECTION  The configuration value is adjusted to  redis  that will do :

QUEUE_CONNECTION=redis

thus ,Laravel It can be based on  config/queue.php  Medium  redis  Configure and initialize the queue system :

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => env('REDIS_QUEUE', 'default'),
    'retry_after' => 90,
    'block_for' => null,
],

Queue system service provider

stay Laravel When app starts , Will pass  QueueServiceProvider  To register the queue system related services to the service container :

public function register()
{
    $this->registerManager();
    $this->registerConnection();
    $this->registerWorker();
    $this->registerListener();
    $this->registerFailedJobServices();
}

...

//  Queue manager 
protected function registerManager()
{
    $this->app->singleton('queue', function ($app) {
        return tap(new QueueManager($app), function ($manager) {
            $this->registerConnectors($manager);
        });
    });
}

//  Default queue connection , Here, it will be initialized to... According to the configuration value  redis  Connect 
protected function registerConnection()
{
    $this->app->singleton('queue.connection', function ($app) {
        return $app['queue']->connection();
    });
}

//  Queue processor 
protected function registerWorker()
{
    $this->app->singleton('queue.worker', function ($app) {
        $isDownForMaintenance = function () {
            return $this->app->isDownForMaintenance();
        };

        return new Worker(
            $app['queue'],
            $app['events'],
            $app[ExceptionHandler::class],
            $isDownForMaintenance
        );
    });
}

//  Queue listeners , Listen for queue events 
protected function registerListener()
{
    $this->app->singleton('queue.listener', function ($app) {
        return new Listener($app->basePath());
    });
}

//  Failed task handling ( The default is based on the database )
protected function registerFailedJobServices()
{
    $this->app->singleton('queue.failer', function ($app) {
        $config = $app['config']['queue.failed'];

        if (isset($config['driver']) && $config['driver'] === 'dynamodb') {
            return $this->dynamoFailedJobProvider($config);
        } elseif (isset($config['driver']) && $config['driver'] === 'database-uuids') {
            return $this->databaseUuidFailedJobProvider($config);
        } elseif (isset($config['table'])) {
            return $this->databaseFailedJobProvider($config);
        } else {
            return new NullFailedJobProvider;
        }
    });
}

RedisQueue Queue implementation

The underlying code design is similar to caching —— be based on  QueueManager  Manage queue system connections for different drivers , The final message push and receive are distributed to the corresponding queue system for processing according to the currently used queue driver , The configuration here uses Redis As a message system driver , So it will eventually pass  RedisConnector  Connect to  RedisQueue  To deal with :

/**
 *  Establish a queue connection 
 *
 * @param  array  $config
 * @return \Illuminate\Contracts\Queue\Queue
 */
public function connect(array $config)
{
    return new RedisQueue(
        $this->redis, $config['queue'],
        $config['connection'] ?? $this->connection,
        $config['retry_after'] ?? 60,
        $config['block_for'] ?? null
    );
}

You can  RedisQueue  See the implementation method of pushing message data to the queue in  push

public function push($job, $data = '', $queue = null)
{
    return $this->enqueueUsing(
        $job,
        $this->createPayload($job, $this->getQueue($queue), $data),
        $queue,
        null,
        function ($payload, $queue) {
            return $this->pushRaw($payload, $queue);
        }
    );
}

public function pushRaw($payload, $queue = null, array $options = [])
{
    $this->getConnection()->eval(
        LuaScripts::push(), 2, $this->getQueue($queue),
        $this->getQueue($queue).':notify', $payload
    );

    return json_decode($payload, true)['id'] ?? null;
}

Laravel Use The task class As the default format for message data , Because it is an object type , Therefore, serialization processing will be performed , The final push operation uses Lua The script by Reis RPUSH  Command complete :

public static function push()
{
    return <<<'LUA'
-- Push the job onto the queue...
redis.call('rpush', KEYS[1], ARGV[1])
-- Push a notification onto the "notify" queue...
redis.call('rpush', KEYS[2], 1)
LUA;
}

The queue connection here is Redis, The default queue is  default. Reading data from the message queue uses  pop  Method realization :

public function pop($queue = null)
{
    $this->migrate($prefixed = $this->getQueue($queue));

    if (empty($nextJob = $this->retrieveNextJob($prefixed))) {
        return;
    }

    [$job, $reserved] = $nextJob;

    if ($reserved) {
        return new RedisJob(
            $this->container, $this, $job,
            $reserved, $this->connectionName, $queue ?: $this->default
        );
    }
}

...

protected function retrieveNextJob($queue, $block = true)
{
    $nextJob = $this->getConnection()->eval(
        LuaScripts::pop(), 3, $queue, $queue.':reserved', $queue.':notify',
        $this->availableAt($this->retryAfter)
    );

    if (empty($nextJob)) {
        return [null, null];
    }

    [$job, $reserved] = $nextJob;

    if (! $job && ! is_null($this->blockFor) && $block &&
        $this->getConnection()->blpop([$queue.':notify'], $this->blockFor)) {
        return $this->retrieveNextJob($queue, false);
    }

    return [$job, $reserved];
}

In the process of obtaining data Lua The script uses Redis LPOP  Instructions , The specific code will not be posted , The queue connection is Redis, The default queue is  default.

Although it seems that the underlying implementation is very complex , But the basic principle is the same as that we passed above Redis The native code implementation is consistent . Yes, of course ,Laravel It also supports some more complex operations , Such as delayed push 、 Batch processing, etc , You can study it yourself  RedisQueue  Understand the underlying details of the corresponding implementation source code in .

The message data

Laravel The message data in the queue system will be provided in the form of task classes , And make another layer of packaging for different drivers , So as to facilitate the unified processing of the bottom layer , about Redis Driven queue system , Finally, the obtained data will pass through  RedisJob  Return after encapsulation ,RedisJob  The constructor for is shown below :

public function __construct(Container $container, RedisQueue $redis, $job, $reserved, $connectionName, $queue)
{
    $this->job = $job;
    $this->redis = $redis;
    $this->queue = $queue;
    $this->reserved = $reserved;
    $this->container = $container;
    $this->connectionName = $connectionName;

    $this->decoded = $this->payload();
}

among  $job  The corresponding is the task class instance that the business code pushes to the queue ,$this->payload()  The task class load data after deserialization is returned in , The other fields are automatically obtained by the bottom layer according to the message queue configuration .

Asynchronous processing process

Laravel Multiple Artisan Command to process message queues , these Artisan The source code of the command is located in  vendor/laravel/framework/src/Illuminate/Queue/Console  Under the table of contents :

You can go through  queue:work  perhaps  queue:listen  Command to listen and process the data in the message queue , With  queue:work  For example , The corresponding source code is located in  WorkCommand  in , We focus on  handle  Method implementation

public function handle()
{
    if ($this->downForMaintenance() && $this->option('once')) {
        return $this->worker->sleep($this->option('sleep'));
    }

    $this->listenForEvents();

    $connection = $this->argument('connection')
                    ?: $this->laravel['config']['queue.default'];
    $queue = $this->getQueue($connection);

    return $this->runWorker(
        $connection, $queue
    );
}

  If the system is in maintenance mode , No queues are consumed , Otherwise call  listenForEvents  Method listens for queue events and outputs logs to the command line :

protected function listenForEvents()
{
    $this->laravel['events']->listen(JobProcessing::class, function ($event) {
        $this->writeOutput($event->job, 'starting');
    });

    $this->laravel['events']->listen(JobProcessed::class, function ($event) {
        $this->writeOutput($event->job, 'success');
    });

    $this->laravel['events']->listen(JobFailed::class, function ($event) {
        $this->writeOutput($event->job, 'failed');

        $this->logFailedJob($event);
    });
}

Then get the current queue connection and the default queue from the queue configuration , The configuration here is Redis Queue connection , The default queue is  default, After obtaining the queue system information , You can call  runWorker  Method to run the consumer processing process :

protected function runWorker($connection, $queue)
{
    return $this->worker->setName($this->option('name'))
                 ->setCache($this->cache)
                 ->{$this->option('once') ? 'runNextJob' : 'daemon'}(
        $connection, $queue, $this->gatherWorkerOptions()
    );
}

there  $this->worker  The corresponding is Laravel stay  QueueServiceProvider  Registered in  queue.worker, namely  Worker  Class instance , If it is a one-time implementation ( adopt  --once  Option assignment ), Call  Worker  Class  runNextJob  Method :

public function runNextJob($connectionName, $queue, WorkerOptions $options)
{
    $job = $this->getNextJob(
        $this->manager->connection($connectionName), $queue
    );
    
    if ($job) {
        return $this->runJob($job, $connectionName, $options);
    }

    $this->sleep($options->sleep);
}

Here you can get the task data in the message queue  getNextJob  Method just calls the previous  RedisQueue( The configuration here is Redis queue , Other drivers, and so on ) Of  pop  Method returns through  RedisJob  Encapsulated message data , And then call  runJob  Method to process the task class that represents the message data :

protected function runJob($job, $connectionName, WorkerOptions $options)
{
    try {
        return $this->process($connectionName, $job, $options);
    } catch (Throwable $e) {
        $this->exceptions->report($e);

        $this->stopWorkerIfLostConnection($e);
    }
}

there  process  Method will call  RedisJob  Defined above  fire  Method executes the corresponding task logic ( The lower level calls  Redis  Encapsulate the processing methods on the task class ):

public function process($connectionName, $job, WorkerOptions $options)
{
    try {
        $this->raiseBeforeJobEvent($connectionName, $job);

        $this->markJobAsFailedIfAlreadyExceedsMaxAttempts(
            $connectionName, $job, (int) $options->maxTries
        );

        if ($job->isDeleted()) {
            return $this->raiseAfterJobEvent($connectionName, $job);
        }

        $job->fire();

        $this->raiseAfterJobEvent($connectionName, $job);
    } catch (Throwable $e) {
        $this->handleJobException($connectionName, $job, $options, $e);
    }
}

If it is not executed at one time , It calls  Worker  Class  daemon  Method :

public function daemon($connectionName, $queue, WorkerOptions $options)
{
    if ($this->supportsAsyncSignals()) {
        $this->listenForSignals();
    }

    $lastRestart = $this->getTimestampOfLastQueueRestart();

    [$startTime, $jobsProcessed] = [hrtime(true) / 1e9, 0];

    while (true) {
        if (! $this->daemonShouldRun($options, $connectionName, $queue)) {
            $status = $this->pauseWorker($options, $lastRestart);

            if (! is_null($status)) {
                return $this->stop($status);
            }

            continue;
        }

        $job = $this->getNextJob(
            $this->manager->connection($connectionName), $queue
        );

        if ($this->supportsAsyncSignals()) {
            $this->registerTimeoutHandler($job, $options);
        }

        if ($job) {
            $jobsProcessed++;

            $this->runJob($job, $connectionName, $options);
        } else {
            $this->sleep($options->sleep);
        }

        if ($this->supportsAsyncSignals()) {
            $this->resetTimeoutHandler();
        }

        $status = $this->stopIfNecessary(
            $options, $lastRestart, $startTime, $jobsProcessed, $job
        );

        if (! is_null($status)) {
            return $this->stop($status);
        }
    }
}

and  runNextJob  similar , Just wrapped in the outer layer  while(true)  Implement resident processes , And other code to ensure the robustness of the program .

A complete link for tasks to be sent and processed by analogy

I understand Laravel After the underlying implementation principle of the queue system , Let's look at how to use it in business code . Or take the update of article views as an example , According to the queue -> news -> The three components of the process are implemented in sequence , Easy to compare and understand .

For queue systems , adopt  QUEUE_CONNECTION  Configure the queue driver you want to use , It's configured to  redis,Laravel The bottom layer will use  RedisQueue  This queue implements , There is no need to write extra code for the task .

Yes, of course , except Laravel In addition to the built-in queue driver , You can also refer to these built-in implementations to customize the queue system driver .

Then define a task class as the message data pushed to the queue system ,Laravel Provides  make:job Artisan Command to quickly generate task classes :

php artisan make:job PostViewsIncrement

In fact, you can also use  Queue::pushRaw(string)  Push message data in native string format to Redis queue , however Laravel The provided process does not know how to handle this message , So it is not generally done , If you define the processing logic for string format messages , It's not impossible .

Write the implementation code of this task class as follows , Migrate the article views update business code to  handle  Method :

<?php

namespace App\Jobs;

use App\Models\Post;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Redis;

class PostViewsIncrement implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public Post $post;

    /**
     * Create a new job instance.
     *
     * @param Post $post
     */
    public function __construct(Post $post)
    {
        $this->post = $post;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        if ($this->post->increment('views')) {
            Redis::zincrby('popular_posts', 1, $this->post->id);
        }
    }
}

After defining the task class , It can be accessed through the controller  dispatch  The helper function distributes the task class and pushes it to the queue system :

//  Browse the article 
public function show($id)
{
    $post = $this->postRepo->getById($id);
    //  Distribute queue tasks 
    $this->dispatch(new PostViewsIncrement($post));
    return "Show Post #{$post->id}, Views: {$post->views}";
}

This function will eventually pass  Illuminate\Bus\Dispatcher  Of  dispatch  Method to distribute task classes :

public function dispatch($command)
{
    return $this->queueResolver && $this->commandShouldBeQueued($command)
                    ? $this->dispatchToQueue($command)
                    : $this->dispatchNow($command);
}

If the incoming  $command  Parameter is an implementation of  ShouldQueue  An instance of an interface , Call  dispatchToQueue  Method to push it to the specified queue :

public function dispatchToQueue($command)
{
    $connection = $command->connection ?? null;

    $queue = call_user_func($this->queueResolver, $connection);

    if (! $queue instanceof Queue) {
        throw new RuntimeException('Queue resolver did not return a Queue implementation.');
    }

    if (method_exists($command, 'queue')) {
        return $command->queue($queue, $command);
    }

    return $this->pushCommandToQueue($queue, $command);
}

Here we parse to  queue  A variable is  RedisQueue  example , If the task class defines  queue  Method , Then use the code defined by this method to push the task class queue , Otherwise, call  pushCommandToQueue  Method push :

protected function pushCommandToQueue($queue, $command)
{
    if (isset($command->queue, $command->delay)) {
        return $queue->laterOn($command->queue, $command->delay, $command);
    }
    
    if (isset($command->queue)) {
        return $queue->pushOn($command->queue, $command);
    }
    
    if (isset($command->delay)) {
        return $queue->later($command->delay, $command);
    }
    
    return $queue->push($command);
}

If there is no delay push setting , The task class is not set  queue  attribute , Call  $queue->push($command)  Method to push a task class to a queue , That's what we described above  RedisQueue  Upper  push  Method .

actually , Directly through  Queue::push(new PostViewsIncrement($post))  You can also push task classes to Redis queue , But the use of  dispatch  The way is more elegant 、 steady , There is no need for us to handle task class verification 、 How to handle delayed push 、 How to push to a custom queue 、 Application queue message processing middleware, etc , So we use... In our daily development  dispatch  Method push .

The task class ( The message data ) After a successful push , You can go through Laravel Provided Artisan command  queue:work  As a processing process, it listens to and consumes the task classes in the queue :

php artisan queue:work

Access articles in the browser , You can see the corresponding message queue processing results in the terminal window .

If you look at the data structure of a queued message before it is processed ( The default location is  laravel_database_queues:default  in ):

You can see that this is a process JSON Serialized message data :

job  The corresponding is how to process the message data , The final implementation is  data.command  in  unserialize  Coming out  PostViewsIncrement  On the object  handle  Method .

Review the above Asynchronous processing process The final execution in is the task class  RedisJob  Example of  fire  Method , The source code is as follows :

public function fire()
{
  $payload = $this->payload();

  [$class, $method] = JobName::parse($payload['job']);

  ($this->instance = $this->resolve($class))->{$method}($this, $payload['data']);
}

there  payload  Namely Redis Queue JSON Format message data , We go through  job  The field value is parsed out of the message data processor , And then  data  field value ( Which contains  PostViewsIncrement  Data of task class instances ) Pass it in as a parameter ,CallQueuedHandler  Of  call  It will eventually be based on  Dispatcher  The distribution task class executes , Before that, the middleware defined in the task class will be executed :

public function call(Job $job, array $data)
{
  	try {
      $command = $this->setJobInstanceIfNecessary(
        $job, unserialize($data['command'])
      );
    } catch (ModelNotFoundException $e) {
      return $this->handleModelNotFound($job, $e);
    }
  
    ...

    $this->dispatchThroughMiddleware($job, $command);

    ...
}

protected function dispatchThroughMiddleware(Job $job, $command)
{
    return (new Pipeline($this->container))->send($command)
            ->through(array_merge(method_exists($command, 'middleware') ? $command->middleware() : [], $command->middleware ?? []))
            ->then(function ($command) use ($job) {
                return $this->dispatcher->dispatchNow(
                    $command, $this->resolveHandler($job, $command)
                );
            });
}

If the task class has a corresponding processor class , Run through the processor class , Otherwise, call the task class itself  handle  perhaps  __invoke  Method execution , Here we are  PostViewsIncrement  Defined above  handle  Method :

public function dispatchNow($command, $handler = null)
{
    $uses = class_uses_recursive($command);

    if (in_array(InteractsWithQueue::class, $uses) &&
        in_array(Queueable::class, $uses) &&
        ! $command->job) {
        $command->setJob(new SyncJob($this->container, json_encode([]), 'sync', 'sync'));
    }

    if ($handler || $handler = $this->getCommandHandler($command)) {
        $callback = function ($command) use ($handler) {
            $method = method_exists($handler, 'handle') ? 'handle' : '__invoke';

            return $handler->{$method}($command);
        };
    } else {
        $callback = function ($command) {
            $method = method_exists($command, 'handle') ? 'handle' : '__invoke';

            return $this->container->call([$command, $method]);
        };
    }

    return $this->pipeline->send($command)->through($this->pipes)->then($callback);
}

Come here , We will take Laravel be based on Redis In the implementation of the queue system , The task class representing the message data is defined from , To distribute , To be pushed to the queue , Last pass Artisan The complete link of command asynchronous consumption processing is shown to you , I believe you should have a clear understanding of the underlying implementation and upper use of the queue system : Queue system and asynchronous processing Laravel Frameworks have been provided , In daily development , We just need to write according to the structure of the message task class  handle  processing method , And then pass in the right place  dispatch  Method to distribute , The rest to Laravel Just deal with it , It's that simple .

You can refer to  Laravel Queue documents Learn more about Laravel Queue usage details , besides ,Laravel It also provides an application for Redis An integrated solution for queue systems —— Horizon, It is recommended to use it in production environments as Redis Message queuing system solutions , You will open a special message queue system to introduce the use and deployment of all these features .

The benefits of using a queue system

At the beginning of this tutorial , Xuejun has introduced the advantages of using message queue , Let's make a summary based on it :

  • Separating producers from consumers , Realize code decoupling , Improve system fault tolerance ( After the consumer fails to process , Message data can be processed repeatedly , Until the execution is successful );
  • The consumer processing process can process message data asynchronously , So as to effectively improve the response speed of the system , Enhance the user experience , This is very effective for some time-consuming tasks ( E.g. email sending 、 Database operation 、 File store 、 Reptiles or something IO Intensive operation );
  • except IO Intensive operation , You can also be right about CPU Optimized for intensive operations , For example, start multiple processing processes to split a large time-consuming task into multiple subtasks for execution , Message queues can be thought of as PHP A complementary implementation of asynchronous and concurrent programming ;
  • Due to the first in, first out characteristics of queues , Therefore, it can ensure that the tasks in the same queue can be executed according to the specified sequence , Unlike general concurrent programming, it cannot ensure the execution order of subtasks ;
  • Because Message Queuing Middleware ( Here is Redis) Can be independent of the application ( Here is Laravel project ) Deployment , And theoretically, any number of processing processes can be started to consume the tasks in the message queue , Therefore, it is very convenient to increase the system concurrency through horizontal expansion , Besides ,Laravel It also provides Message Queuing Middleware and frequency limiting functions , The abnormal flow peak can be effectively controlled , Improve the availability of message queuing .

We can optimize the database 、 cache ( With dynamic and static cache )、 Message queuing as Laravel Three board axe with performance optimization , Reasonably combining this set of three board axe moves can effectively deal with the bottleneck of application performance , Improve system throughput .

原网站

版权声明
本文为[weixin_ two billion forty-seven million six hundred and seventy]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206090000212387.html