>백엔드 개발 >PHP 튜토리얼 >Laravel 큐의 구현 원리와 문제 해결 방법에 대해

Laravel 큐의 구현 원리와 문제 해결 방법에 대해

不言
不言원래의
2018-06-13 11:45:522424검색

이 글은 주로 Laravel 큐 구현 원리와 문제 해결 기록에 대한 간략한 논의를 소개합니다. 내용이 꽤 좋아서 지금 공유하고 참고하겠습니다.

문제

Laravel을 사용하여 개발된 회사의 두 프로젝트가 동일한 테스트 서버에 배포되고 동일한 Redis를 공유합니다. laravel에서 큐를 사용하면 충돌이 발생합니다.

문제 원인 찾기

laravel 대기열의 작업 클래스 IlluminateQueueRedisQueue.php에서 pushRaw() 메서드를 볼 수 있습니다. IlluminateQueueRedisQueue.php中可以看到pushRaw()方法:

// 将一任务推入队列中
public function pushRaw($payload, $queue = null, array $options = [])
  {
    $this->getConnection()->rpush($this->getQueue($queue), $payload);

    return Arr::get(json_decode($payload, true), 'id');
  }

从该方法中可以看出Lrarvel队列的redis实现是通过list结构实现的,rpush(key, value)是将value推入键值为key的redis队列,key的值则是通过$this->getQueue($queue) 获取到的

protected function getQueue($queue)
  {
    return 'queues:'.($queue ?: $this->default);
  }

所以的redis中list中的key是 'queues:'.($queue ?: $this->default);拼接的,$this->default 的值是 RedisQueue 实例化的时候从configqueue.php配置中加载的 'queue' => 'default',$queue 是添加队列时$this->dispatch( new jobClass()->onQueue($queue) )传入的。

// config\queue.php 文件中的redis配置部分
'redis' => [
      'driver'   => 'redis',
      'connection' => 'default',
      'queue'   => 'default',
      'expire'   => 60,
    ],

至此,两个项目的队列冲突原因就找到了。因为redis队列配置中 'queue' => 'default' 都使用的默认的default,所以当共用redis时,默认的队列list 都是'queue:default',所以导致了冲突。

因为队列监听 监听的队列名称是由 --queue参数决定的,如果不传就是我们上面设置的默认值,若传了就会根据传入的队列名从前往后优先依次处理,具体见代码IlluminateQueueWorker.php中:

protected function getNextJob($connection, $queue)
  {
    if (is_null($queue)) {
      return $connection->pop();
    }

    foreach (explode(',', $queue) as $queue) {
      if (! is_null($job = $connection->pop($queue))) {
        return $job;
      }
    }
  }

$queue就是--queue=传入的参数,当 $queue不存在是直接调用$connection->pop()当参数存在时会将参数解析,优先处理排在前面的队列名称,将队列名称传入pop($queue), pop()会尝试从指定队列或默认队列中获取队列任务

// Illuminate\Queue\RedisQueue.php
public function pop($queue = null)
  {
    $original = $queue ?: $this->default;

    $queue = $this->getQueue($queue);

    if (! is_null($this->expire)) {
      $this->migrateAllExpiredJobs($queue);
    }

    $job = $this->getConnection()->lpop($queue);

    if (! is_null($job)) {
      $this->getConnection()->zadd($queue.':reserved', $this->getTime() + $this->expire, $job);

      return new RedisJob($this->container, $this, $job, $original);
    }
  }

至此搞清了队列执行的原理。

解决方法

将queue的配置文件中默认队列修改为不同的名称,比如: 'queue' => laravel1','queue' => laravel2'。

队列监听 php artisan queue:listen redis --queue=laravel1,syncExpress

rrreee

이 메소드를 보면 Lrarvel 큐의 redis 구현이 목록 구조를 통해 구현되어 있음을 알 수 있습니다. rpush(key, value)는 값을 redis에 푸시하는 것입니다. 키 값을 키로 사용하여 키 값을 $this->getQueue($queue)

rrreee

를 통해 얻습니다. Redis의 목록에서 'queues:'.($queue ?: $this->default);가 연결되어 있으면 $this->default 의 값은 다음과 같습니다. RedisQueue 'queue' => 'default' 인스턴스화 중에 configqueue.php 구성에서 로드되었으며, $queue는 $this-입니다. &gt 대기열을 추가할 때 ;dispatch( new jobClass()->onQueue($queue) ) 가 전달되었습니다.

rrreee

이 시점에서 두 프로젝트 간의 큐 충돌 원인이 발견되었습니다. Redis 대기열 구성의 'queue' => 'default' 는 모두 기본 기본값을 사용하기 때문에 Redis 공유 시 기본 대기열 목록이 모두 'queue:default' 가 되어 충돌이 발생합니다. .

큐 모니터링에서 모니터링하는 큐 이름은 --queue 매개변수에 의해 결정되기 때문에 전달되지 않으면 위에서 설정한 기본값이 되며, 전달되면 앞에서부터 순서대로 처리됩니다. 자세한 내용은 코드를 참조하세요. IlluminateQueueWorker.php:

rrreee

$queue는 --queue에 의해 전달된 매개변수입니다. =.$queue가 존재하지 않는 경우 $를 직접 호출합니다.connection->pop()매개변수가 존재하는 경우 해당 매개변수를 파싱하여 앞의 큐 이름을 먼저 처리합니다. 대기열 이름은 pop($queue), pop()에 전달됩니다. 지정된 대기열 또는 기본 대기열에서 대기열 작업을 가져오려고 시도합니다

rrreee

🎜 🎜이제 우리는 대기열 실행의 원리를 이해했습니다. 🎜🎜🎜해결 방법🎜🎜🎜큐 구성 파일의 기본 큐를 'queue' => laravel1', 'queue' => laravel2'와 같은 다른 이름으로 수정하세요. 🎜🎜Queue listening php artisan queue:listen redis --queue=laravel1,syncExpress🎜🎜🎜Finally🎜🎜🎜문제가 발생하면 서두르지 말고 의사에게 달려가세요. 코드부터 시작하여 구현 원리를 분석 및 이해하고 올바른 지점을 찾는 방법은 간단할 수 있습니다. 🎜🎜위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되었으면 좋겠습니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! 🎜🎜관련 권장사항: 🎜🎜🎜 PHP Laravel 프레임워크의 메시지 큐와 비동기 큐 사용 방법 분석 🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜

위 내용은 Laravel 큐의 구현 원리와 문제 해결 방법에 대해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.