[MSA] Laravel RabbitMQ 사용

Hoone·2021년 8월 2일
1
post-thumbnail

RabbitMQ

AMQP (Advanced Message Queueing Protocol) 프로토콜을 따르는 오픈소스 메세지 브로커 소프트웨어(message broker software) 입니다.

Microservice 간에 메세지를 전달하는 중개자 역할을 합니다.
예를들면 제품 서비스와 제품에 대한 후기 서비스가 있는데 제품 서비스에서 삭제가 발생하면 후기 서비스에도 해당 제품에 대한 후기를 삭제하라고 메세지를 전달해야하는데 그 중개자 역할을 하는게 RabbitMQ입니다.

message-queue-and-rabbitmq
출처: www.cloudamqp.com

아래의 이미지처럼 제품 서비스에서 메세지 브로커로 제품이 삭제되었다라는 메세지를 보내면
메세지 브로커가 리뷰 서비스에 그 메세지를 전달합니다.

message-queue-and-rabbitmq
출처: www.cloudamqp.com

앞서 말한 예시를 실제로 구현해보겠습니다.

사전에 미리 Laravel로 product와 review 서비스를 만들고 CRUD에 대한 API 기능까지 구현해놓았습니다.
이 서비스에 RabbitMQ를 연결해서 메세지를 주고 받는 예제를 만들어보겠습니다.

Laravel RabbitMQ 연결

laravel queue에서 RabbitMQ를 사용하기 위한 드라이버가 필요합니다.

Install package

vladimir-yuldashev/laravel-queue-rabbitmq 패키지를 product-service에 설치합니다.

composer require vladimir-yuldashev/laravel-queue-rabbitmq

install laravel-queue-rabbitmq package

Config 설정

config/queue.php에 connection을 추가합니다.

'rabbitmq' => [
    
    'driver' => 'rabbitmq',
    'queue' => env('RABBITMQ_QUEUE', 'default'),
    'connection' => PhpAmqpLib\Connection\AMQPLazyConnection::class,

    'hosts' => [
        [
            'host' => env('RABBITMQ_HOST', '127.0.0.1'),
            'port' => env('RABBITMQ_PORT', 5672),
            'user' => env('RABBITMQ_USER', 'guest'),
            'password' => env('RABBITMQ_PASSWORD', 'guest'),
            'vhost' => env('RABBITMQ_VHOST', '/'),
        ],
    ],

    'options' => [
        'ssl_options' => [
            'cafile' => env('RABBITMQ_SSL_CAFILE', null),
            'local_cert' => env('RABBITMQ_SSL_LOCALCERT', null),
            'local_key' => env('RABBITMQ_SSL_LOCALKEY', null),
            'verify_peer' => env('RABBITMQ_SSL_VERIFY_PEER', true),
            'passphrase' => env('RABBITMQ_SSL_PASSPHRASE', null),
        ],
        'queue' => [
            'job' => VladimirYuldashev\LaravelQueueRabbitMQ\Queue\Jobs\RabbitMQJob::class,
        ],
    ],

    /*
     * Set to "horizon" if you wish to use Laravel Horizon.
     */
    'worker' => env('RABBITMQ_WORKER', 'default'),
     
],

.env

RabbitMQ 연동을 위한 환경설정을 추가합니다.
그리고 QUEUE_CONNECTIONrabbitmq로 변경합니다.

QUEUE_CONNECTION=rabbitmq

...

RABBITMQ_HOST=
RABBITMQ_PORT=5672
RABBITMQ_USER=
RABBITMQ_PASSWORD=
RABBITMQ_VHOST=

cloudamqp.com 가입

https://www.cloudamqp.com 접속해서 가입하면 Instance 목록페이지가 열리는데 Create New Instance 버튼을 클릭해서 Instance를 생성합니다.

목록 이미지

앞에서 추가한 설정파일(.env)에 Instance 정보를 추가합니다.

생성된 이미지

review-service 에도 동일하게 설치 및 설정을 합니다.

Job 생성

product service에서 제품 삭제 메세지를 보내기 위한 job을 생성합니다.

php artisan make:job ProductDeleted

메세지를 보낼 때 삭제된 product 정보를 첨부하기 위해서 __construct에 추가합니다.

product-service/app/Jobs/ProductDeleted.php

<?php

namespace App\Jobs;

...

class ProductDeleted implements ShouldQueue
{
    ...
 
    private $data;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
    }
}

product가 삭제되면 삭제한 product id를 첨부해 메세지를 보내도록 코드를 추가합니다.

product-service/app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use App\Jobs\ProductDeleted;

class ProductsController extends Controller
{
    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Product  $product
     * @return \Illuminate\Http\Response
     */
    public function destroy(Product $product)
    {
        $product->delete();

        ProductDeleted::dispatch([
            'id' => $product->id
        ]);
        return response(null);
    }
}

Job 생성 - review service

product 삭제에 대한 메세지 수신을 위해 review-service에 동일하게 ProductDeleted job을 생성합니다.

php artisan make:job ProductDeleted

review-service/app/Jobs/ProductDeleted.php

<?php

namespace App\Jobs;

use App\Models\Review;
...

class ProductDeleted implements ShouldQueue
{
    ...
 
    private $data;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data)
    {
        $this->data = $data;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
    	if ($this->data) {
            Review::where('product_id', $this->data['id'])->delete();
            echo "Review has been deleted. product_id: ".$this->data['id'].PHP_EOL;
        }
    }
}

메세지를 받기 위해
php artisan queue:work 또는 php artisan rabbitmq:consume 명령을 실행합니다.

이제 실제로 product를 삭제해보고 review service에 메세지가 전달이 되는지 테스트합니다.

Product 삭제

현재 product service에 3개의 product가 등록되어있습니다.

product list api 결과화면

review service에는 각 product에 대한 review가 등록되어있습니다.

review list api 결과화면

product를 삭제하기전에 먼저 review service에 queue worker를 띄웁니다.

php artisan queue:work

review service queue:work 실행화면

이제 product service에 product 삭제하는 API를 실행하고 review service에 메세지가 전달되는지 테스트합니다.

product delete 호출화면

위 이미지처럼 product_id가 3인 product가 삭제되면 RabbitMQ를 통해 review service에 메세지가 수신됩니다.

그럼 이제 실제로 review가 삭제됐는지 확인합니다.

review service 삭제된 화면

이미지에서처럼 product_id3인 review가 삭제되었습니다.

지금까지 laravel 프로젝트에 RabbitMQ를 이용해 다른 마이크로서비스 간에 메세지를 주고 받는 예제를 아주 간단하게 만들어봤습니다.
물론 아주 간단한 예제지만 Message broker를 이해하는데 약간의 도움이 되었기를 바랍니다.

작업한 예제 프로그램은 Github에 올려져있습니다.

profile
도움이 되고픈 개발자

0개의 댓글