beanstalkd 生產環境

什麼是Beanstalkd
   Beanstalkd,一個高性能、輕量級的分佈式內存隊列系統。最初設計的目的是想通過後臺異步執行耗時的任務來降低高容量 Web 應用系統的頁面訪問延遲,支持過有9.5 million 用戶的 Facebook Causes 應用。後來開源,現在有 PostRank 大規模部署和使用,每天處理百萬級任務。Beanstalkd 是典型的類 Memcached 設計,協議和使用方式都是同樣的風格,所以使用過 memcached 的用戶會覺得 Beanstalkd 似曾相識。
   beanstalkd 的最初設計意圖是在高併發的網絡請求下,通過異步執行耗時較多的請求,及時返回結果,減少請求的響應延遲。

特性

1. 優先級(priority)

對於很緊急的消費者可以讓他在隊列中提前,實現插隊行爲

2. 延遲(delay)

設置的任務在多少秒後才能被消費者讀取,可以實現定時任務,如定時點贊等

3. 持久化(persistent data)

出現服務器宕機等情況,數據依然存在

4. 預留(buried)

消費者將無法取出任務,在其他合適的時機在拿出消費

5. 任務超時重發(time-to-run)

消費者必須在指定的時間內處理完任務,否則這個任務將重新被放入隊列

 

安裝

注:beanstalkd是不支持windows的 ,必須要在Linux環境下(本地環境介紹 Linux, php7,mysql5.6,nginx,centos7.4) 

1. yum install -y git 

2.  git clone https://github.com/kr/beanstalkd 

3.  cd beanstalkd 

4. make

5. make install

查看是否安裝 成功: beanstlkd -v

配置文件是  etc/sysconfig/beanstalkd

 

git安裝

#下載軟件-編譯安裝git clone git://github.com/kr/beanstalkd.gitcd beanstalkd
#編譯make#安裝完成-默認安裝在/usr/local/bin/

啓動命令:

#啓動並綁定端口     beanstalkd -l 127.0.0.1 -p 11300 -b /home/software/binstalkd/binlogs
#-b開啓日誌備份,重啓恢復數據
#安裝php操作類   composer require pda/pheanstalk

查看狀態:service beanstalkd status

配置連通性 + 持久化

ip 用 0.0.0.0 允許所有連接,靠配置安全組或防火牆去約束連接,放開 -b 參數 (默認沒有持久化),內存的隊列消息可以落地到硬盤 binlog 實現持久化,斷電可重新讀取隊列消息。

管理工具

親測了很多網上能找到的 beanstalkd 工具,這兩款是我最中意的了,一個命令行,一個 web 的。
命令行:https://github.com/src-d/beanstool
web 界面:https://github.com/ptrofimov/beanstalk_console

beanstalkd 任務狀態

狀態 註釋
delayed 延遲狀態
ready 準備好狀態
reserved 消費者把任務讀出來,處理時
buried 預留狀態
delete 刪除狀態

寫入job

<?php
//創建隊列消息
require_once('./vendor/autoload.php');

use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);

$tubeName = 'email_list';

$jobData = [
    'email' => '[email protected]',
    'message' => 'Hello World !!',
    'dtime' => date('Y-m-d H:i:s'),
];

$pheanstalk->useTube( $tubeName)->put( json_encode( $jobData ) );

消費job

<?php
ini_set('default_socket_timeout', 86400*7);
ini_set( 'memory_limit', '256M' );

// 消費隊列消息
require_once('./vendor/autoload.php');

use Pheanstalk\Pheanstalk;

$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$tubeName = 'email_list';
while ( true )
{
    // 獲取隊列信息, reserve 阻塞獲取
    $job = $pheanstalk->watch( $tubeName )->ignore( 'default' )->reserve();
    if ( $job !== false )
    {
        $data = $job->getData();
        /* TODO 邏輯操作 */

        /* 處理完成,刪除 job */
        $pheanstalk->delete( $job );
    }
}

default_socket_timeout 這個參數是一定要加的,php 默認一般是 60s,假如您沒有在代碼裏面設置,採用默認的話(60s),60s 之內如果沒有 job 產生,腳本就會報 socket 錯誤,我寫的是 7 天超時,您可以根據業務去調整,記住一定要配置,網上很多搜的 consumer 腳本都沒有配置這個,根本不能投入生產環境使用,這是我親自實踐的結果。
  關於 while true 是否死循環,很明確告訴你是死循環,但是不會一直耗性能的那樣執行下去,它會在 reserve 這裏阻塞不動,直到有消息產生纔會往下走,所以大可放心使用,我的項目代碼裏面是使用了方法調用方法自身去實現循環的。

供參考:

public function watchJob()
    {
        $job = $this->pheanstalk->watch( config( 'tube' ) )->ignore( 'default' )->reserve();
        if ( $job !== false )
        {
            $job_data = $job->getData();

            $this->subscribe( $job_data );
            $this->pheanstalk->delete( $job );
            /* 繼續 Watch 下一個 job */
            $this->watchJob();
        }
        else
        {
            $this->log->error( 'reserve false', 'reserve false' );
        }
    }

監控 beanstalkd 狀態

<?php

//監控服務狀態
require_once('./vendor/autoload.php');

use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$isAlive = $pheanstalk->getConnection()->isServiceListening();

var_dump( $isAlive );

可以配合 email 做一個報警郵件,腳本每分鐘去執行,判斷狀態是 false,就給管理員發送郵件報警。

一些相關命令

查看 beanstalkd 服務內存佔用

top -u beanstalkd

後臺運行 consumer 腳本

nohup php googlehome_subscribe.php & 

查看 consumer 腳本運行時間

ps -A -opid,stime,etime,args | grep consumer.php

手工重啓 consumer 腳本

ps auxf|grep 'googlehome_subscribe.php'|grep -v grep|awk '{print $2}'|xargs kill -9 
nohup php googlehome_subscribe.php &

一些總結

  php 要把錯誤日誌打開,方便收集 consumer 腳本 crash 的 log,腳本跑出一些致命的 error 一定要及時修復,因爲一旦有錯就會掛掉,這會影響你腳本的可用性,後期穩定之後可以上 supervisor 這種進程管理程序來管控腳本生命週期。
  一些網絡請求操作,一定要 try catch 到所有錯誤,一旦沒有 catch 到,腳本就崩。我用的是 Guzzle 去做的網絡請求,下面是我 catch 的一些錯誤,代碼片段供參考。

try
{
    /* TODO: 邏輯操作 */
}
catch ( ClientException $e )
{
    $results['mid']    = $this->mid;
    $results['code']   = $e->getResponse()->getStatusCode();
    $results['reason'] = $e->getResponse()->getReasonPhrase();
    $this->log->error( 'properties-changed ClientException', $results );
}
catch ( ServerException $e )
{
    $results['mid']    = $this->mid;
    $results['code']   = $e->getResponse()->getStatusCode();
    $results['reason'] = $e->getResponse()->getReasonPhrase();
    $this->log->error( 'properties-changed ServerException', $results );
}
catch ( ConnectException $e )
{
    $results['mid'] = $this->mid;
    $this->log->error( 'properties-changed ConnectException', $results );
}

        job 消費之後一定要刪除掉,如果長時間不刪除,php 客戶端會有 false 返回,是因爲有 DEADLINE_SOON 這個超時錯誤產生,所以處理完任務,一定要記得刪除,這一點跟 kafka 不一樣,beanstalkd 需要開發者自己去刪除 job。

Beanstalkd FAQ 中文版
http://www.fzb.me/2015-7-31-beanstalkd-faq.html

PHP 消息隊列 beanstalkd
https://www.kancloud.cn/daiji/beanstalkd/735176

Beanstalkd -視頻  帶你玩轉消息隊列
https://www.imooc.com/learn/912

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章