느린 작업 처리

가끔 우리는 느린 작업을 처리해야 할 필요가 있습니다. 느린 작업이 webman의 다른 요청 처리에 영향을 미치지 않도록 하기 위해, 이런 작업은 상황에 따라 다른 처리 방안을 사용할 수 있습니다.

방안 1 메시지 큐 사용

참조: redis 큐 stomp 큐

장점

폭발적으로 발생하는 대량의 작업 요청을 처리할 수 있습니다.

단점

결과를 클라이언트에 직접 반환할 수 없습니다. 결과를 푸시해야 할 경우, 다른 서비스와 결합해야 합니다. 예를 들어 webman/push를 사용하여 처리 결과를 푸시할 수 있습니다.

방안 2 HTTP 포트 추가

느린 요청을 처리하기 위해 새로운 HTTP 포트를 추가합니다. 이 느린 요청은 이 포트를 통해 특정한 프로세스 그룹에 들어가서 처리되며, 처리 후 결과를 클라이언트에 직접 반환합니다.

장점

데이터를 클라이언트에 직접 반환할 수 있습니다.

단점

폭발적인 대량 요청을 처리할 수 없습니다.

실행 단계

config/process.php에 다음과 같은 구성 추가.

return [
    // ... 다른 구성 생략 ...

    'task' => [
        'handler' => \Webman\App::class,
        'listen' => 'http://0.0.0.0:8686',
        'count' => 8, // 프로세스 수
        'user' => '',
        'group' => '',
        'reusePort' => true,
        'constructor' => [
            'requestClass' => \support\Request::class, // request 클래스 설정
            'logger' => \support\Log::channel('default'), // 로그 인스턴스
            'appPath' => app_path(), // app 디렉터리 위치
            'publicPath' => public_path() // public 디렉터리 위치
        ]
    ]
];

이렇게 느린 인터페이스는 http://127.0.0.1:8686/ 이 프로세스를 통해 실행될 수 있으며, 다른 프로세스의 작업 처리에 영향을 미치지 않습니다.

프론트엔드가 포트의 차이를 인식하지 않도록 하기 위해 nginx에 8686 포트로의 프록시를 추가할 수 있습니다. 예를 들어 느린 인터페이스의 요청 경로가 모두 /tast로 시작한다고 가정할 때, 전체 nginx 구성은 다음과 유사합니다:

upstream webman {
    server 127.0.0.1:8787;
    keepalive 10240;
}

# 8686 포트의 upstream 추가
upstream task {
   server 127.0.0.1:8686;
   keepalive 10240;
}

server {
  server_name webman.com;
  listen 80;
  access_log off;
  root /path/webman/public;

  # /tast로 시작하는 요청이 8686 포트를 거치도록 설정, /tast를 실제 필요에 따라 변경하세요.
  location /tast {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      proxy_pass http://task;
  }

  # 나머지 요청은 원래 8787 포트를 통해 처리
  location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_http_version 1.1;
      proxy_set_header Connection "";
      if (!-f $request_filename){
          proxy_pass http://webman;
      }
  }
}

이렇게 클라이언트가 도메인.com/tast/xxx에 접근하면 별도의 8686 포트를 통해 처리되고, 8787 포트의 요청 처리에 영향을 미치지 않습니다.

방안 3 http chunked를 이용한 비동기 청크 데이터 전송

장점

데이터를 클라이언트에 직접 반환할 수 있습니다.

workerman/http-client 설치

composer require workerman/http-client

app/controller/IndexController.php

<?php
namespace app\controller;

use support\Request;
use support\Response;
use Workerman\Protocols\Http\Chunk;

class IndexController
{
    public function index(Request $request)
    {
        $connection = $request->connection;
        $http = new \Workerman\Http\Client();
        $http->get('https://example.com/', function ($response) use ($connection) {
            $connection->send(new Chunk($response->getBody()));
            $connection->send(new Chunk('')); // 빈 청크 전송으로 response 종료
        });
        // 먼저 http 헤더를 전송하고, 이후 데이터는 비동기로 전송
        return response()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

提示
본 예제에서는 workerman/http-client 클라이언트를 사용하여 비동기적으로 http 결과를 가져오고 데이터를 반환하였습니다. 다른 비동기 클라이언트(예: AsyncTcpConnection)도 사용할 수 있습니다.