Gearman - Multi workers parallel

Mở đầu

Nếu bạn là tín đồ của truyện hoặc phim kiếm hiệp, chắc hẳn chúng ta rất quen thuộc với thuật PHÂN THÂN. Thường thì chỉ có các đại cao thủ, tuyệt kĩ đầy mình, nhất nhì võ lâm mới luyện nổi tuyệt kĩ này. Ngày bé mình cũng rât thích tuyệt kĩ này của Tôn Ngộ Không, một thần tượng của bao trẻ em thuở thiếu thời. Vậy tại sao chúng ta lại thích tuyệt kĩ này đến vậy? Có lẽ đơn giản là sức mạnh của một người được nhân lên hàng chục hàng trăm lần tùy thuộc số PHÂN THÂN.

Một ngày đẹp trời, mình cũng đang lạc mình giữa bộn bề dự án. Và mình gặp những vấn đề nan giải như:

  • Lúc user đăng ký tài khoản, phải gửi mail cho admin.
  • Push notification tới các devices.
  • Lúc user upload, chúng ta cần resize lại nhiều cỡ ảnh.

Chúng ta có thể thấy các vấn đề nêu trên đều tốn rất nhiều thời gian. Thông thường khi user thực hiện một request, nếu chúng ta thực hiện hết các nhiệm vụ trên rồi mới response về thì mất rất nhiều thời gian (>3s). User chả thích tẹo nào và sẽ rời bỏ hệ thống của bạn. Giải pháp được đưa ra là chúng ta sẽ ném các nhiệm vụ không cần thiết đối với user vào QUEUE, một process khác sẽ xử lý nhiệm vụ đó như: ghi log, gửi mail, push notification, resize ảnh ... Process này cần được PHÂN THÂN để tăng tốc độc xử lý (multi workers).

Một số ứng dụng phổ biến xử lý công việc này như là Resque, Gearman ... Vậy cái nào tốt hơn cái nào? Chúng ta nên sử dụng cái nào?

Gearman là gì?

Gearman provides a generic application framework to farm out work to other machines or processes that are better suited to do the work. It allows you to do work in parallel, to load balance processing, and to call functions between languages. It can be used in a variety of applications, from high-availability web sites to the transport of database replication events. In other words, it is the nervous system for how distributed processing communicates.

  • Đơn giản có thể hiểu Gearman là một ứng dụng cho phép bạn xử lý công việc song song, phân chia công việc cân bằng cho các workers, nó là hệ thống kế nối các xử lý phân tán.

Ưu điểm của Gearman

  • Open Source - Free 100% nhé. Gearman là BSD.
  • Multi-language - Hỗ trợ nhiều ngôn ngữ và đang mở rộng ngôn ngữ hơn. Điều đặc biệt là chúng ta có thể viết client đẩy job bằng 1 ngôn ngữ và các workers thực thi có thể viết bằng một ngôn ngữ khác.
  • Flexible - Chúng ta không bị bó buộc trong một design pattern cụ thể nào. Rất nhanh chóng đặt các ứng dụng phân tán cùng nhau sử dụng bất cứ model nào.
  • Fast - Gearman có một protocol và interface đã tối ưu hóa, đa luồng và server được viết bằng C/C++ nên cực kì nhanh.
  • Embeddable - Gearman rất nhanh và nhẹ, cực kì tuyệt vời để tích hợp vào bất cứ ứng dụng nào. Code đơn giản, dễ hiểu.
  • No limits on message size - Gearman hỗ trợ các single messages lên tới 4Gig. Nếu cần lớn hơn có thể chunk messages.
  • Worried about scaling? - Gearman có khả năng mở rộng rât tốt.

Gearman hoạt động như thế nào?

Gearman là một ứng dụng mạnh mẽ gồm 3 phần: client, job server và worker.

  • Client chịu trách nhiệm tạo một job và gửi cho job server.
  • Job server sẽ tìm worker phù hợp để chuyển và chạy job đó.
  • Worker sẽ thực thi công việc được yêu cầu bởi client và gửi response cho client thông qua job server. Gearman cung cấp client và worker APIs để ứng dụng của chúng ta có thể nói chuyện được với job server qua TCP sockets.

Luồng flow cực kì dễ hiểu và đơn giản phải không nào? Client -> Job server -> Worker -> Job server->Client.

Gearman và Resque (Redis)

  • Resque một ứng dụng khả nổi tiếng, được xây dựng dựa trên Redis queue list type data. Bản chất là các jobs được enque và lưu vào list, các workers chủ động pull jobs từ queue và thực hiện. Ưu điểm là nhẹ và dễ config.
  • Resque được xây dựng cho Ruby, nhưng đã có một cổng cho PHP trên https://github.com/chrisboulton/php-resque
  • Gearman thì là một distributed job server, còn Redis là một distributed store.
  • Gearman job có thể đồng bộ (synchronous) hoặc không đồng bộ (asynchronous). Đồng bộ ở đây đơn giản là thực hiện và phản hồi tức thì. Không đồng bộ chính là ném vào queue và chạy background. Redis chỉ cung cấp xử lý không đồng bộ.
  • Gearman là High availability, khả năng thực hiện và phản hồi nhanh chóng. Nó cung cấp một chiến lược có sẵn (off-the-shelf stragy).
  • Gearman có khả năng mở rộng theo chiều dọc tốt (vertical scalability) bởi vì nó là xử lý đa luồng (multi-threaded processing). Redis chỉ là xử lý đơn luồng (single threaded).

Gearman mạnh mẽ và nhanh hơn so với Resque.

Install gearman

Install gearmand - Gearman job server

RHEL/Fedora

  • Cài đặt gearmand (bản cũ hơn gọi là gearmand-server)
yum install gearmand     

Debain/Ubuntu Package

apt-get install gearman-job-server

Compile and install from tarball (recommend)

  • Đây là cách tốt nhất để cài đặt bản mới nhất (recommend). Đâù tiên download bản mới nhất ở đây
  • Tải xong thì bắt đầu cài đặt:
tar xzf gearmand-X.Y.tar.gz
cd gearmand-X.Y
./configure
make
make install

Starting gearmand

Sau khi cài đặt xong job server, chúng ta chạy câu lệnh sau để khởi động gearmand

gearmand -d 

Cài đặt Client & Worker APIs

Gearman hỗ trợ nhiều APIs extension cho nhiều ngôn ngữ khác nhau: PHP, C, Nodejs, Python ... Ở đây chúng ta sẽ cài đặt Gearman PHP extension.

Cài đặt Gearman PHP extention

  • Tải bản mới nhất tại đây.

  • Sau đó chúng ta tiến hành cài đặt:

tar xzf gearman-X.Y.tgz
cd gearman-X.Y
phpize
./configure
make
make install
  • Config gearman cho apache2 và PHP 5.6. Thêm dòng sau vào file php.ini ở folder /etc/php.
extension=gearman.so        
  • Tạo file gearman.ini trong thư mục /etc/php/5.6/mods-available với nội dung như sau:
# /etc/php/5.6/mods-availabe/gearman.ini
extension=gearman.so"       
  • Tạo link cho php-cli:
ln -s /etc/php/5.6/mods-available/gearman.ini /etc/php/5.6/cli/conf.d/gearman.ini

Kiểm tra gearman PHP extension đã cài đặt thành công hay không?

php -i | grep gearman

/etc/php/5.6/cli/conf.d/20-gearman.ini,
gearman
gearman support => enabled
libgearman version => 1.1.13

Restart apache

sudo /etc/init.d/apache2  restart   

Ví dụ

Chúng ta sẽ xem xét ví dụ đầu tiên về gearman bằng bài toán reserve (đảo ngược một chuỗi kí tự nhập vào).

  • Tạo thư mục gearman:
mkdir ~/gearman
cd ~/gearman
  • Tạo file client.php
<?php
// client.php
// Reverse Client Code
$client = new GearmanClient();
$client->addServer();
print $client->doNormal("reverse", "Hello World!");
  • Đoạn code này khởi tạo một client, cấu hình sử dụng một job server với add_server (mặc định là 127.0.0.1, port 4730) và bảo client API chạy function reverse với workloadHello world!.
  • Tiếp đến chúng tạo file worker.php như sau:
<?php
// worker.php 
// Reverse Worker Code
$worker = new \GearmanWorker();

$worker->addServer();
$worker->addFunction("reverse", "my_reverse_function");

while ($worker->work());

function my_reverse_function($job)
{
   echo $job->workload() . "\n";
   return strrev($job->workload());
};

  • Worker này định nghĩa một hàm my_reverse_function và thực thi đảo ngược chuỗi kí tự nhận được. Nó được sử dụng bởi một worker đăng ký với tên hàm là reverse. Tên này được sử dụng làm tham số truyền vào ở client $client->doNormal("reverse", "Hello World!");
  • $job->workload() luôn là một chuỗi kí tự, chính là tham số data được truyền vào từ client. Nếu tham số là mảng thì client phải json_encode tham số đó. Ở worker chúng ta sẽ json_decode $job->workload().

  • Chúng ta mở terminal và chạy background worker để lắng nghe:
php worker.php
  • Mở terminal khác và chạy client.php
php client.php
// Out put
!dlroW olleH

Kết quả trả về sẽ là !dlroW olleH. Hàm doNormal nghĩa là client muốn thực hiện đồng bộ và trả về kết quả luôn. Nếu muốn chạy background (không đồng bộ) thì chúng ta sẽ sử dụng hàm doBackground. Các hàm cần thiết có thể tham khảo tại http://php.net/manual/en/book.gearman.php . Client sẽ được sửa lại như sau:

<?php
// client.php
// Reverse Client Code
$client = new GearmanClient();
$client->addServer();
$client->doBackground("reverse", "Hello World!");

Khi dữ liệu nhiều, tại một thời điểm có nhiều request thực hiện job đó thì chúng ta nên config chạy nhiều worker để tăng tốc độ xử lý. Để test thì chúng ta có thể mở nhiều terminal khác nhau và chạy worker.php. Khi job server nhận được nhiều job thì sẽ phân phối đồng đều cho các worker.php xử lý. Gỉa sử thời gian thực hiện 1 job là 1s. Chúng ta có 9 jobs. Nếu chạy một worker thời gian thực thi cần thiết là 1 x 9 = 9s. Nhưng nếu chúng ta chạy 3 workers một lúc thì mỗi worker sẽ nhận 3 jobs và thực thi song song nên thời gian cần thiết là 3s. Quá tuyệt vời phải không nào?

Để đơn giản hơn trong việc config và quản lý số worker đang chạy. Chúng ta sẽ dùng supervisor.

Cài đặt supervisor

# Cài đặt supervisor
sudo apt-get install supervisor

# Kiểm tra nếu cài đặt supervisor thành công
supervisord --version
3.3.1

# Restart supervisor
sudo /etc/init.d/supervisor restart      

Cài supervisor để chạy gearman worker

  • Di chuyển tới thu mục /etc/supervisor/conf.d/
sudo -i 
cd /etc/supervisor/conf.d
  • Tạo file gearmanwork.conf với nội dung như sau:
[program:gearmanwork]
command=/usr/bin/php gearman/worker.php
process_name=%(program_name)s_%(process_num)02d
numprocs=10
autostart=true
autorestart=true
stdout_logfile=/var/log/gearmanwork.out.log
stderr_logfile=/var/log/gearmanwork.error.log"          
  • Giải thích: - command : câu lệnh cần thực hiện, ở đây chúng ta chạy worker.php - process_name: config tên của các process - numprocs: config số tiến trình (workers) cần chạy - autostart: Giá trị là true/false chỉ định auto start khi supervisor start. - autorestart: Tự động restart process bị die (vì một lý do không mong muốn) - stdout_logfile: đường dẫn file log của các process - stderr_logfile: đường dẫn log lỗi của các process

  • Update supervisor

supervisorctl reread
supervisorctl update
  • Kiểm tra supervisor gearmanwork đã cài đặt thành công hay chưa bằng câu lệnh:
supervisorctl 
# Result 
gearmanwork:gearmanwork_00       RUNNING   pid 18927, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_01       RUNNING   pid 18926, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_02       RUNNING   pid 18929, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_03       RUNNING   pid 18928, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_04       RUNNING   pid 18931, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_05       RUNNING   pid 18930, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_06       RUNNING   pid 18933, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_07       RUNNING   pid 18932, uptime 1 day, 3:40:24
gearmanwork:gearmanwork_08       RUNNING   pid 650, uptime 0:34:44
gearmanwork:gearmanwork_09       RUNNING   pid 8678, uptime 20:34:43

Chúng ta đã cài đặt gearman và quản lý nó bằng supervisor đơn giản. Nếu số lượng job nhiều chúng ta có thể tăng numprocs worker lên.

Kết luận

Gearman là một ứng dụng rất hữu ích, mạnh mẽ, nhanh chóng và đơn giản để xử lý các nhiệm vụ background. Việc kết hợp với supervisor giúp chúng ta quản lý process dễ dàng hơn. Tích hợp Gearman vào các ứng dụng cần chạy background là một sự lựa chọn tuyệt vời.

Tham khảo