RabbitMQ là gì?

RabbitMQ là một AMQP message broker hay còn gọi là phần mềm quản lý hàng đợi message. Nói đơn giản, đây là phần mềm định nghĩa hàng đợi một ứng dụng khác có thể kết nối đến để bỏ message vào và gửi message dựa trên nó.

Bạn có thể coi nó như một hộp thư nơi bạn xếp chồng các bức thư của mình. RabbitMQ sau đó lấy từng bức thư và đưa nó đến đích của nó.

Message broker là gì?

Message broker là một chương trình trung gian được thiết kế để validating, transforming và routing messages. Chúng phục vụ các nhu cầu giao tiếp giữa các ứng dụng với nhau.

Với Message broker, ứng dụng nguồn (producer) gửi một message đến một server process mà nó có thể cung cấp việc sắp xếp dữ liệu, routing (Định tuyến), message translation, persistence và delivery tất cả các điểm đến thích hợp (consumer).

Có 2 hình thức giao tiếp cơ bản với một Message Broker:

  • Publish và Subscribe (Topics)
  • Point-to-Point (Queues)

Khi nào và tại sao dùng RabbitMQ

RabbitMQ giúp các web server gửi các reponse cho các request rất nhanh thay vì bị ép buộc chạy một procedure ngốn tài nguyên trên một hệ thống. Việc đưa message vào hàng đợi là một giải pháp hay khi ta muốn phân tán message cho nhiều người nhận giúp giảm tải cho các worker xử lý.

VD như user được phép tạo file PDF cho mẫu cv it từ phần mềm tạo CV Online của TopDev, bài toán là khi hàng nghìn user cùng nhấp vào nút tạo PDF, lúc này server nhận rất nhiều request sẽ gây ra vài vấn đề như chậm, quá tải, thậm chí không tạo được file PDF do nghẽn…lúc này chúng ta cần dùng RabbitMQ để đẩy các request này vào hàng chờ. Cơ chế như sau:

Một consumer lấy message từ hàng đợi và bắt đầu xử lý PDF trong lúc với một producer đang bỏ thêm những message mới vào trong hàng đợi. Một request có thể được tạo bằng ngôn ngữ này và xử lý bằng một ngôn ngữ khác. Hai ứng dụng trao đổi với nhau qua các message. Do đó, hai ứng dụng gửi và nhận sẽ có độ ràng buộc thấp.

  Message broker là gì? Sơ lược về RabbitMQ và ứng dụng demo
  RabbitMQ là gì? Tìm hiểu và sử dụng RabbitMQ
Phần 12 : Kết nối RabbitMQ”]

  1. User gửi yêu cầu tạo PDF lên ứng dụng web
  2. Ứng dụng web (producer) gửi message đến RabbitMQ, có chứa thông tin dữ liệu mà user yêu cầu, như tên, email, số điện thoại…
  3. Một exchange được đồng ý từ ứng dụng producer và dẫn chúng đến đúng hàng đợi tạo PDF
  4. Một worker xử lý PDF (consumer) nhận một task và bắt đầu xử lý tạo PDF.

rabbitmq

Cài đặt RabbitMQ

Trong Ubuntu và hệ điều hành debian khác, bạn có thể cài đặt RabbitMQ bằng cách thực hiện các lệnh sau trên terminal của bạn:

echo "deb http://www.rabbitmq.com/debian/ testing main"  | sudo tee  /etc/apt/sources.list.d/rabbitmq.list > /dev/null
sudo wget http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
sudo apt-key add rabbitmq-signing-key-public.asc
sudo apt-get update
sudo apt-get install rabbitmq-server -y
sudo service rabbitmq-server start
sudo rabbitmq-plugins enable rabbitmq_management
sudo service rabbitmq-server restart

Lệnh đầu tiên là nối thêm nguồn rabbitmq vào danh sách nguồn phần mềm. Tiếp theo, chúng ta tải về khóa đăng ký rabbitmq bằng wget .

Sau đó thêm khóa vào Ubuntu. Tiếp theo chúng ta gọi apt-get update để cập nhật danh sách các nguồn phần mềm. Tiếp theo, chúng ta cài đặt máy chủ RabbitMQ, khởi động nó sau đó kích hoạt plugin quản lý RabbitMQ.

Điều này cung cấp quản lý API dựa trên HTTP để theo dõi máy chủ RabbitMQ của bạn. Cuối cùng, chúng ta khởi động lại máy chủ RabbitMQ để thay đổi sẽ có hiệu lực. Tên người dùng và mật khẩu mặc định là guest . Và cổng mặc định trong đó nó chạy là 5672 .

Nếu bạn đang sử dụng hệ điều hành khác, bạn có thể tìm cách cài đặt RabbitMQ cho hệ điều hành cụ thể của bạn tại đây: http://www.rabbitmq.com/download.html .

Làm việc với RabbitMQ

Khi bạn đã cài đặt xong RabbitMQ, chúng ta có thể cài đặt thư viện AMQP cho PHP. Điều này thực hiện giao thức AMQP (Giao thức hàng đợi thông điệp nâng cao). Như tên cho thấy nó là một giao thức được sử dụng để gửi thông điệp.

Bắt đầu bằng cách tạo một danh mục mới, đây là nơi chúng tôi sẽ đặt tất cả các tệp để thử nghiệm RabbitMQ. Tiếp theo, tạo một tệp composer.json (đọc thêm composer là gì?) và thêm các phần sau:

{
  "require": {
      "videlalvaro/php-amqplib": "2.2.*"
  }
}

Tiếp theo, mở terminal và cd của bạn vào thư mục bạn đã tạo trước đó, sau đó thực hiện composer install để cài đặt thư viện AMQP.

Trước khi chúng ta tiếp tục, hãy cài đặt Swiftmailer . Bạn có thể làm điều đó bằng cách thực hiện lệnh sau từ terminal của bạn. Thao tác này cũng thêm mục nhập vào Swiftmailer vào composer.json của bạn:

composer require swiftmailer/swiftmailer @stable

Gửi message

Đầu tiên cho phép tạo biểu mẫu được sử dụng để gửi email. Điều này sẽ chấp nhận tên và địa chỉ email của người gửi, địa chỉ email của người nhận và sau đó là chủ đề và thông điệp. Đặt tên cho tệp form.php :

<?php
if(!empty($_GET['sent'])){
?>
<div>
    Your message was sent!
</div>
<?php
}
?>
<form action="mailer.php" method="POST">
    <div>
        <label for="from">From</label>
        <input type="text" name="from" id="from">
    </div>
    <div>
        <label for="from_email">From Email</label>
        <input type="text" name="from_email" id="from_email">
    </div>
    <div>
        <label for="to_email">To Email</label>
        <input type="text" name="to_email" id="to_email">
    </div>
    <div>
        <label for="subject">Subject</label>
        <input type="text" name="subject" id="subject">
    </div>
    <div>
        <label for="message">Message</label>
        <textarea name="message" id="message" cols="30" rows="10"></textarea>
    </div>
    <div>
        <button type="submit">Send</button>
    </div>
</form>

Tiếp theo, tạo tệp sẽ đẩy thư vào hàng đợi. Đặt tên cho tệp tin sender.php . Yêu cầu tệp autoload.php để các phụ thuộc của chúng sẽ được tự động tải bởi PHP. Sau đó sử dụng AMQPConnection và AMQPMessage từ thư viện AMQP.

AMQPConnection cho phép chúng ta tạo một kết nối mới đến máy chủ RabbitMQ và AMQPMessage cho phép chúng ta tạo các thông điệp mà chúng ta có thể đẩy vào hàng đợi.

<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLibConnectionAMQPConnection;
use PhpAmqpLibMessageAMQPMessage;

$connection = new AMQPConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('email_queue', false, false, false, false);

$data = json_encode($_POST);

$msg = new AMQPMessage($data, array('delivery_mode' => 2));
$channel->basic_publish($msg, '', 'email_queue');

header('Location: form.php?sent=true');
?>

Chia nhỏ nó, trước tiên chúng ta tạo một kết nối mới bằng cách tạo một thể hiện mới của lớp AMQPConnection . Điều này đòi hỏi các đối số sau đây:

  • host – máy chủ mà máy chủ RabbitMQ đang chạy. Trong trường hợp này, chúng ta đã cài đặt RabbitMQ trên cùng một máy tính, chúng ta đang chạy tập lệnh. Vì vậy, nó phải là localhost .

Lưu ý rằng trong thế giới thực, chúng ta cài đặt RabbitMQ trên một máy chủ khác, khác với máy chủ đang sử dụng để phục vụ trang web của chúng ta. Vì vậy, thay vì localhost chúng ta sử dụng địa chỉ IP công cộng của máy chủ đó.

  • port – cổng mà máy chủ RabbitMQ đang chạy.
  • user – tên người dùng để sử dụng để đăng nhập vào máy chủ. Theo mặc định, tên người dùng được đặt thành guest .
  • password – mật khẩu của người dùng. Theo mặc định, mật khẩu được đặt thành guest .

Tiếp theo chúng ta tạo một kênh. Chúng ta có thể làm điều đó bằng cách gọi phương thức channel() từ kết nối mà chúng ta vừa khai báo.

<?php
$channel = $connection->channel();
?>

Tiếp theo, chúng ta khai báo hàng đợi sẽ được sử dụng bằng cách gọi phương thức queue_declare.

<?php
$channel->queue_declare('email_queue', false, false, false, false);
?>

Phương thức queue_declare chiếm các đối số sau:

  • queue name – tên mà bạn muốn sử dụng cho hàng đợi, bạn có thể cung cấp bất kỳ thứ gì cho điều này.
  • passive – một giá trị boolean để xác định xem có nên kiểm tra một trao đổi hiện có hay không.
  • durable – một giá trị boolean để xác định xem RabbitMQ giữ trên một hàng đợi khi máy chủ bị treo.
  • exclusive – một giá trị boolean để xác định xem hàng đợi có được sử dụng bởi chỉ một kết nối hay không.
  • auto-delete – giá trị boolean để xác định xem hàng đợi có bị xóa khi người đăng ký hủy đăng ký cuối cùng hay không.

Tiếp theo, chúng ta chuyển đổi dữ liệu POST mà chúng tôi nhận được từ biểu mẫu thành chuỗi JSON. Chúng ta chỉ có thể truyền các chuỗi như một thông báo, vì vậy chúng ta sẽ phải chuyển đổi chuỗi này sau này thành một mảng trên đầu của người nhận.

<?php
$data = json_encode($_POST);
?>

Tiếp theo chúng ta tạo một tin nhắn mới. Điều này chấp nhận 2 đối số: dữ liệu và một loạt các tùy chọn. Đối với mảng các tùy chọn, chúng tôi chỉ định delivery_mode là 2 có nghĩa là thông báo vẫn tồn tại. Điều này có nghĩa là nó không bị mất khi máy chủ bị lỗi hoặc xảy ra lỗi.

  RabbitMQ là gì? Tìm hiểu và sử dụng RabbitMQ
<?php
$msg = new AMQPMessage($data, array('delivery_mode' => 2));
?>

Tiếp theo, chúng ta xuất bản thông điệp bằng cách gọi phương thức basic_publish() trên kênh. Điều này chấp nhận 3 đối số: thông điệp, trao đổi và tên của hàng đợi.

Nếu bạn đang tự hỏi tại sao chúng ta đặt giá trị trao đổi thành một chuỗi rỗng, đó là bởi vì chúng ta không thực sự cần nó. Việc trao đổi thường được sử dụng cho các mẫu pub-sub. Những gì đang sử dụng ở đây chỉ là xuất bản cơ bản.

<?php
$channel->basic_publish($msg, '', 'email_queue');
?>

Cuối cùng, chúng tôi chỉ chuyển hướng người dùng đến biểu mẫu.

<?php
header('Location: form.php?sent=true');
?>

Nhận thông điệp

Bây giờ đã sẵn sàng để viết lệnh sẽ nhận được các thông điệp được gửi bởi người dùng. Đặt tên cho tệp tin là file receiver.php. Đây là nội dung đầy đủ của tệp:

<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLibConnectionAMQPConnection;

$connection = new AMQPConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('email_queue', false, false, false, false);

echo ' * Waiting for messages. To exit press CTRL+C', "n";

$callback = function($msg){

    echo " * Message received", "n";
    $data = json_decode($msg->body, true);

    $from = $data['from'];
    $from_email = $data['from_email'];
    $to_email = $data['to_email'];
    $subject = $data['subject'];
    $message = $data['message'];

    $transporter = Swift_SmtpTransport::newInstance('smtp.gmail.com', 465, 'ssl')
      ->setUsername('YOUR_GMAIL_EMAIL')
      ->setPassword('YOUR_GMAIL_PASSWORD');

    $mailer = Swift_Mailer::newInstance($transporter);

    $message = Swift_Message::newInstance($transporter)
        ->setSubject($subject)
        ->setFrom(array($from_email => $from))
        ->setTo(array($to_email))
        ->setBody($message);

    $mailer->send($message);

    echo " * Message was sent", "n";
    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};

$channel->basic_qos(null, 1, null);
$channel->basic_consume('email_queue', '', false, false, false, false, $callback);

while(count($channel->callbacks)) {
    $channel->wait();
}
?>

Chia nhỏ nó, 5 dòng mã đầu tiên về cơ bản giống với dòng chúng ta có trong tệp sender.php. Sau đó, chúng ta chỉ xuất một thông báo cho biết cách chúng ta có thể ngừng chạy tệp. Chúng ta cần chạy file này từ terminal để dừng nó, chúng ta chỉ cần nhấn CTRL + C

Tiếp theo, chúng ta khai báo một hàm được đặt tên. Điều này sẽ được sử dụng để xử lý thông điệp mà chúng ta đã chuyển từ người gửi. Điều đầu tiên nó làm là đầu ra tin nhắn đã được nhận. Sau đó, chúng ta sử dụng json_decode() để chuyển đổi chuỗi JSON trở lại một mảng.

<?php
$callback = function($msg){
    echo " * Message received", "n";
    $data = json_decode($msg->body, true);
};
?>

Tiếp theo, chúng ta trích xuất dữ liệu và gán chúng cho từng biến của riêng chúng:

<?php
$from = $data['from'];
$from_email = $data['from_email'];
$to_email = $data['to_email'];
$subject = $data['subject'];
$message = $data['message'];
?>

Tiếp theo chúng ta khai báo một Transporter mới sẽ được sử dụng bởi Swiftmailer. Điều này cho phép chúng ta sử dụng tài khoản gmail để gửi email. Khai báo một cá thể mới chấp nhận 3 đối số: máy chủ, cổng và mã hóa. Sau đó, chúng ta đặt tên người dùng và mật khẩu.

<?php
$transporter = Swift_SmtpTransport::newInstance('smtp.gmail.com', 465, 'ssl')
      ->setUsername('YOUR_GMAIL_EMAIL')
      ->setPassword('YOUR_GMAIL_PASSWORD');
?>

Tiếp theo chúng ta khai báo một cá thể mailer mới và cung cấp transporter làm đối số.

<?php
$mailer = Swift_Mailer::newInstance($transporter);
?>

Tiếp theo tạo một tin nhắn mới, điều này cũng chiếm transporter như đối số của nó. Sau đó chúng tôi đặt chủ đề, từ đâu, đến đâu và nội dung của thông báo.

<?php
$message = Swift_Message::newInstance($transporter)
        ->setSubject($subject)
        ->setFrom(array($from_email => $from))
        ->setTo(array($to_email))
        ->setBody($message);
?>

Cuối cùng chúng ta sẽ gửi thông điệp và xuất thống điệp đã gửi. Dòng cuối hiển thị cho RabbitMQ thấy rằng việc gửi đã thành công.

<?php
$mailer->send($message);
echo " * Message was sent", "n";

$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
?>

Chạy chương trình

Bây giờ bạn có thể chạy bộ nhận thông điệp bằng cách vào terminal và thực hiện lệnh sau:

php receiver.php

Khi chạy, hãy truy cập trình duyệt của bạn và truy cập tệp sender.php . Nhập chi tiết tin nhắn của bạn và nhấp vào gửi. Bạn ngay lập tức được chào đón bởi một ‘Tin nhắn của bạn đã được gửi!’ văn bản nhưng nếu bạn ngay lập tức kiểm tra tài khoản email của mình thì chưa có.

Nếu nó không có thì hàng đợi vẫn đang xử lý nó. Kiểm tra đầu ra được hiển thị trên cửa sổ đầu cuối nơi bạn đã thực thi bộ thu. Bạn sẽ thấy thông báo ‘Đã gửi thư’ nếu email đã được gửi.

Kết luận RabbitMQ

RabbitMQ là một cách hay để triển khai các ứng dụng nhắn tin như ứng dụng chúng ta đã tạo trong hướng dẫn này. Chúng ta chỉ vừa mới làm đơn giản với hướng dẫn này. Tôi khuyên bạn nên kiểm tra http://www.rabbitmq.com/getstarted.html  để tìm hiểu thêm.

Nguồn: Wern Ancheta Blog

Có thể bạn muốn xem thêm:

Xem thêm tuyển dụng ngành công nghệ thông tin hàng đầu tại TopDev