Kafka日記(四) 實戰PHP

本篇講解如何使用PHP擴展(用了swoole)

簡單使用,自己可以再封裝一下。

使用api時,$conf->set(‘enable.auto.commit’, ‘false’),可以關閉自動提交,進行手動的提交,開啓自動提交。

php swooleProcess.php 使用swoole創建進程開啓消費,判斷topic的分區數創建進程開始消費

topic不存在會自動創建 創建的分區和副本數量默認broker配置,服務器端配置,代碼無法決定!!!

## 是否允許自動創建topic ,若是false,就需要通過命令創建topic
auto.create.topics.enable =true
 
## 一個topic ,默認分區的replication個數 ,不得大於集羣中broker的個數
default.replication.factor =1
 
## 每個topic的分區個數,若是在topic創建時候沒有指定的話 會被topic創建時的指定參數覆蓋
num.partitions =1
 
實例 --replication-factor3--partitions1--topic replicated-topic :名稱replicated-topic有一個分區,分區被複制到三個broker上。

文章最後有conf和topicConf所有配置項。

swooleProcess.php

<?php
/**
 * Created by PhpStorm.
 * User: zhangwei
 * Date: 2019/3/21
 * Time: 14:48
 */
include_once ('SwooleProcess.class.php');
include_once ('KafkaHelp.class.php');
$topic = 'test9';

$sp = new SwooleProcess($topic);

<?php
/**
 * Created by PhpStorm.
 * User: zhangwei
 * Date: 2019/3/20
 * Time: 8:51
 */
include_once ('./MMysql.class.php');
class KafkaHelp
{

    protected $producer;
    protected $topic;

    /**發送消息到kafka
     * @param $playload 消息內容
     * @param $key 鍵值
     */
    public function produce($playload, $key)
    {
        $producer = $this->producer();

        $topic = $producer->newTopic($this->topic);
        //採用默認的隨機方法選擇分區,$key是用來選擇分區的指標
        $topic->produce(RD_KAFKA_PARTITION_UA, 0, $playload, $key);

        while($producer->getOutQLen() > 0) {
            $producer->poll(50);
        }
    }

    /**生產者
     * @return \RdKafka\Producer
     */
    protected function producer()
    {
        if(!$this->producer) {
            $producer = new \RdKafka\Producer();
            $producer->addBrokers($this->getBroker());
            $this->producer = $producer;
        }
        return $this->producer;
    }


    /**獲取kafka server list
     * @return mixed
     */
    protected function getBroker()
    {
        return '127.0.0.1:9092,127.0.0.1:9093,127.0.0.1:9094';
    }

    /**設置topic
     * @param $topic
     */
    public function setTopic($topic)
    {
        $this->topic = $topic;
    }

    /**
     * 獲取分區
     * @return mixed
     */
    public function getPartitions()
    {
        $consumer = new \RdKafka\Consumer();
        $consumer->addBrokers($this->getBroker());

        $topic   = $consumer->newTopic($this->topic);
        $allInfo = $consumer->getMetadata(false, $topic, 60e3);
        $topics  = $allInfo->getTopics();
        // 循環一個topic
        foreach($topics as $tp) {
            $partitions = $tp->getPartitions(); // 獲取partion信息
            break;
        }
        // 初次創建 $allIndo get不到Topic的partitions信息
        if(!count($partitions)){
            return $this->getPartitions();
        }
        return $partitions;
    }

    /**
     * high level
     * @throws Exception
     */
    public function highlevelConsumer()
    {
        $conf = new \RdKafka\Conf();
        //這裏就是自動均衡分配分區給消費者的意思
        $conf->setRebalanceCb(function(\RdKafka\KafkaConsumer $kafka, $err, array $partitions = null){
            switch($err) {
                case RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS:
                    echo 'assign:\n';
                    var_dump($partitions);
                    $kafka->assign($partitions);
                    break;

                case RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS:
                    $kafka->assign(null);
                    break;

                default:
                    throw new \Exception($err);
            }
        });

        $conf->set('group.id', 'comsumer-group-'.$this->topic);
        $conf->set('client.id', 'client-'.$this->topic);
        $conf->set('bootstrap.servers', $this->getBroker());
        $conf->set('enable.auto.commit', 'false');
        $conf->set('enable.auto.offset.store', 'false');

        $topicConf = new \RdKafka\TopicConf();
        $topicConf->set('offset.store.method', 'broker');
        // 如果沒有檢測到有保存的offset,就從最小開始
        $topicConf->set('auto.offset.reset', 'smallest');
        $topicConf->set('request.required.acks',-1);


        $conf->setDefaultTopicConf($topicConf);

        $consumer = new \RdKafka\KafkaConsumer($conf);
        $consumer->subscribe([$this->topic]);

        while(true) {
            $message = $consumer->consume(120 * 1000);
            switch($message->err) {
                case RD_KAFKA_RESP_ERR_NO_ERROR:
                    echo $this->topic.'-'.$message->partition.'-'.$message->offset."\n";
//                    sleep(1);
                    // 連接數據庫
                    $mysqlConfig = [
//                        'host' => '39.108.219.96',
                        'host' => '127.0.0.1',
                        'port' => '3306',
                        'user' => 'root',
//                        'passwd' => '123456',
                        'passwd' => 'root',
                        'dbname' => 'kafka'
                    ];
                    $db = new MMysql($mysqlConfig);
                    $insertMsg = [
                        'payload' => $message->payload,
                        'partition' => $message->partition,
                        'offset' => $message->offset,
                        'len' => $message->len,
                        'timestamp' => $message->timestamp,
                        'keyvalue' => $message->key,
                        'topic_name' => $message->topic_name,
                    ];
                    $resId = $db->insert('consumer',$insertMsg);
                    // 操作成功提交
                    if($resId){
                        $consumer->commitAsync($message);
                    }else{
                        var_dump($resId);
                    }

                    break;
                case RD_KAFKA_RESP_ERR__PARTITION_EOF:
                case RD_KAFKA_RESP_ERR__TIMED_OUT:
                    break;
                default:
                    throw new \Exception($message->errstr(), $message->err);
                    break;
            }
        }
    }

    /**
     * low level
     * @param $partionId
     * @throws Exception
     */
    public function createConsumer($partionId)
    {
        $conf = new \RdKafka\Conf();
        //指定消費組
        $conf->set('group.id', 'comsumer-group-'.$this->topic);
        $conf->set('bootstrap.servers', $this->getBroker());

        $rk = new \RdKafka\Consumer($conf);

        $topicConf = new \RdKafka\TopicConf();
        //自動提交offset間隔時間
        $topicConf->set('auto.commit.interval.ms', 100);
        //保存offset的方式,可以選擇broker或者file
        $topicConf->set('offset.store.method', 'broker');
        //如果沒有檢測到有保存的offset,就從最小開始
        $topicConf->set('auto.offset.reset', 'smallest');

        $topic = $rk->newTopic($this->topic, $topicConf);

        $topic->consumeStart($partionId, RD_KAFKA_OFFSET_STORED);

        while(true) {
            $message = $topic->consume($partionId, 120 * 10000);
            switch($message->err) {
                case RD_KAFKA_RESP_ERR_NO_ERROR:
                    echo $this->topic.'-'.$message->partition.'-'.$message->offset."\n";
                    sleep(1);
                    break;
                case RD_KAFKA_RESP_ERR__PARTITION_EOF:
                case RD_KAFKA_RESP_ERR__TIMED_OUT:
                    break;
                default:
                    throw new \Exception($message->errstr(), $message->err);
                    break;
            }
        }
    }
}

SwooleProcess.class.php:

<?php
/**
 * Created by PhpStorm.
 * User: zhangwei
 * Date: 2019/3/21
 * Time: 14:08
 */
include_once ('KafkaHelp.class.php');
class SwooleProcess{
    public $mpid = 0;
    public $works = [];
    public $kafka;
    public $new_index = 0;

    public function __construct($topic){
        try {
            $this->kafka= new KafkaHelp();
            $this->kafka->setTopic($topic);

            $this->processName = 'kafka-queue:'.$topic;
            swoole_set_process_name($this->processName.'master');
            $this->mpid = posix_getpid();

            $partitions = $this->kafka->getPartitions();
            foreach($partitions as $key => $part) {
                $partitionId = $part->getId();

                $this->createProcess($partitionId);
            }

            $this->processWait();
        }catch (\Exception $e){
            die('ALL ERROR: '.$e->getMessage());
        }
    }

    public function run(){
        for ($i=0; $i < $this->max_precess; $i++) {
            $this->new_index = $i;
            $this->CreateProcess();
        }
    }

    public function CreateProcess($partitionId){
        $process = new swoole_process(function(swoole_process $worker)use($partitionId){
            swoole_set_process_name($this->processName.'-'.$partitionId);
            $this->kafka->highlevelConsumer();
        }, false, false);
        $pid=$process->start();
        $this->works[$partitionId]=$pid;
        return $pid;
    }
    public function checkMpid(&$worker){
        if(!swoole_process::kill($this->mpid,0)){
            // 這句提示,實際是看不到的.需要寫到日誌中
            file_put_contents('/tmp/swoole_process_runtime.log', "Master process exited, I [{$worker['pid']}] also quit\n", FILE_APPEND);
            $worker->exit();
        }
    }

    /**
     * 重啓進程
     * @param $ret
     * @throws Exception
     */
    public function rebootProcess($ret){
        $pid=$ret['pid'];
        $index=array_search($pid, $this->works);
        if($index!==false){
            $index=intval($index);
            $new_pid=$this->CreateProcess($index);
            echo "rebootProcess: {$index}={$new_pid} Done\n";
            return;
        }
        throw new \Exception('rebootProcess Error: no pid');
    }

    public function processWait(){
        while(1) {
            if(count($this->works)){
                $ret = swoole_process::wait();
                if ($ret) {
                    $this->rebootProcess($ret);
                }
            }else{
                break;
            }
        }
    }
}

MMysql.class.php

<?php
/**
 * Desc: php操作mysql的封裝類
 * Author zhifeng
 * Date: 2017/04/15
 * 連接模式:PDO
 */

class MMysql {

    protected static $_dbh = null; //靜態屬性,所有數據庫實例共用,避免重複連接數據庫
    protected $_dbType = 'mysql';
    protected $_pconnect = true; //是否使用長連接
    protected $_host = 'localhost';
    protected $_port = 3306;
    protected $_user = 'root';
    protected $_pass = 'root';
    protected $_dbName = null; //數據庫名
    protected $_sql = false; //最後一條sql語句
    protected $_where = '';
    protected $_order = '';
    protected $_limit = '';
    protected $_field = '*';
    protected $_clear = 0; //狀態,0表示查詢條件乾淨,1表示查詢條件污染
    protected $_trans = 0; //事務指令數

    /**
     * 初始化類
     * @param array $conf 數據庫配置
     */
    public function __construct(array $conf) {
        class_exists('PDO') or die("PDO: class not exists.");
        $this->_host = $conf['host'];
        $this->_port = $conf['port'];
        $this->_user = $conf['user'];
        $this->_pass = $conf['passwd'];
        $this->_dbName = $conf['dbname'];
        //連接數據庫
        if ( is_null(self::$_dbh) ) {
            $this->_connect();
        }
    }

    /**
     * 連接數據庫的方法
     */
    protected function _connect() {
        $dsn = $this->_dbType.':host='.$this->_host.';port='.$this->_port.';dbname='.$this->_dbName;
        $options = $this->_pconnect ? array(PDO::ATTR_PERSISTENT=>true) : array();
        try {
            $dbh = new PDO($dsn, $this->_user, $this->_pass, $options);
            $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  //設置如果sql語句執行錯誤則拋出異常,事務會自動回滾
            $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果(防SQL注入)
        } catch (PDOException $e) {
            die('Connection failed: ' . $e->getMessage());
        }
        $dbh->exec('SET NAMES utf8');
        self::$_dbh = $dbh;
    }

    /**
     * 字段和表名添加 `符號
     * 保證指令中使用關鍵字不出錯 針對mysql
     * @param string $value
     * @return string
     */
    protected function _addChar($value) {
        if ('*'==$value || false!==strpos($value,'(') || false!==strpos($value,'.') || false!==strpos($value,'`')) {
            //如果包含* 或者 使用了sql方法 則不作處理
        } elseif (false === strpos($value,'`') ) {
            $value = '`'.trim($value).'`';
        }
        return $value;
    }

    /**
     * 取得數據表的字段信息
     * @param string $tbName 表名
     * @return array
     */
    protected function _tbFields($tbName) {
        $sql = 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="'.$tbName.'" AND TABLE_SCHEMA="'.$this->_dbName.'"';
        $stmt = self::$_dbh->prepare($sql);
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $ret = array();
        foreach ($result as $key=>$value) {
            $ret[$value['COLUMN_NAME']] = 1;
        }
        return $ret;
    }

    /**
     * 過濾並格式化數據表字段
     * @param string $tbName 數據表名
     * @param array $data POST提交數據
     * @return array $newdata
     */
    protected function _dataFormat($tbName,$data) {
        if (!is_array($data)) return array();
        $table_column = $this->_tbFields($tbName);
        $ret=array();
        foreach ($data as $key=>$val) {
            if (!is_scalar($val)) continue; //值不是標量則跳過
            if (array_key_exists($key,$table_column)) {
                $key = $this->_addChar($key);
                if (is_int($val)) {
                    $val = intval($val);
                } elseif (is_float($val)) {
                    $val = floatval($val);
                } elseif (preg_match('/^\(\w*(\+|\-|\*|\/)?\w*\)$/i', $val)) {
                    // 支持在字段的值裏面直接使用其它字段 ,例如 (score+1) (name) 必須包含括號
                    $val = $val;
                } elseif (is_string($val)) {
                    $val = '"'.addslashes($val).'"';
                }
                $ret[$key] = $val;
            }
        }
        return $ret;
    }

    /**
     * 執行查詢 主要針對 SELECT, SHOW 等指令
     * @param string $sql sql指令
     * @return mixed
     */
    protected function _doQuery($sql='') {
        $this->_sql = $sql;
        $pdostmt = self::$_dbh->prepare($this->_sql); //prepare或者query 返回一個PDOStatement
        $pdostmt->execute();
        $result = $pdostmt->fetchAll(PDO::FETCH_ASSOC);
        return $result;
    }

    /**
     * 執行語句 針對 INSERT, UPDATE 以及DELETE,exec結果返回受影響的行數
     * @param string $sql sql指令
     * @return integer
     */
    protected function _doExec($sql='') {
        $this->_sql = $sql;
        try {
            $res = self::$_dbh->exec($this->_sql);
        } catch (PDOException $e) {
            die('Exception : ' . $e->getMessage());
        }
        return $res;
    }

    /**
     * 執行sql語句,自動判斷進行查詢或者執行操作
     * @param string $sql SQL指令
     * @return mixed
     */
    public function doSql($sql='') {
        $queryIps = 'INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|SELECT .* INTO|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK';
        if (preg_match('/^\s*"?(' . $queryIps . ')\s+/i', $sql)) {
            return $this->_doExec($sql);
        }
        else {
            //查詢操作
            return $this->_doQuery($sql);
        }
    }

    /**
     * 獲取最近一次查詢的sql語句
     * @return String 執行的SQL
     */
    public function getLastSql() {
        return $this->_sql;
    }

    /**
     * 插入方法
     * @param string $tbName 操作的數據表名
     * @param array $data 字段-值的一維數組
     * @return int 受影響的行數
     */
    public function insert($tbName,array $data){
        $data = $this->_dataFormat($tbName,$data);
        if (!$data) return;
        $sql = "insert into ".$tbName."(".implode(',',array_keys($data)).") values(".implode(',',array_values($data)).")";
        return $this->_doExec($sql);
    }

    /**
     * 刪除方法
     * @param string $tbName 操作的數據表名
     * @return int 受影響的行數
     */
    public function delete($tbName) {
        //安全考慮,阻止全表刪除
        if (!trim($this->_where)) return false;
        $sql = "delete from ".$tbName." ".$this->_where;
        $this->_clear = 1;
        $this->_clear();
        return $this->_doExec($sql);
    }

    /**
     * 更新函數
     * @param string $tbName 操作的數據表名
     * @param array $data 參數數組
     * @return int 受影響的行數
     */
    public function update($tbName,array $data) {
        //安全考慮,阻止全表更新
        if (!trim($this->_where)) return false;
        $data = $this->_dataFormat($tbName,$data);
        if (!$data) return;
        $valArr = '';
        foreach($data as $k=>$v){
            $valArr[] = $k.'='.$v;
        }
        $valStr = implode(',', $valArr);
        $sql = "update ".trim($tbName)." set ".trim($valStr)." ".trim($this->_where);
        return $this->_doExec($sql);
    }

    /**
     * 查詢函數
     * @param string $tbName 操作的數據表名
     * @return array 結果集
     */
    public function select($tbName='') {
        $sql = "select ".trim($this->_field)." from ".$tbName." ".trim($this->_where)." ".trim($this->_order)." ".trim($this->_limit);
        $this->_clear = 1;
        $this->_clear();
        return $this->_doQuery(trim($sql));
    }

    /**
     * @param mixed $option 組合條件的二維數組,例:$option['field1'] = array(1,'=>','or')
     * @return $this
     */
    public function where($option) {
        if ($this->_clear>0) $this->_clear();
        $this->_where = ' where ';
        $logic = 'and';
        if (is_string($option)) {
            $this->_where .= $option;
        }
        elseif (is_array($option)) {
            foreach($option as $k=>$v) {
                if (is_array($v)) {
                    $relative = isset($v[1]) ? $v[1] : '=';
                    $logic    = isset($v[2]) ? $v[2] : 'and';
                    $condition = ' ('.$this->_addChar($k).' '.$relative.' '.$v[0].') ';
                }
                else {
                    $logic = 'and';
                    $condition = ' ('.$this->_addChar($k).'='.$v.') ';
                }
                $this->_where .= isset($mark) ? $logic.$condition : $condition;
                $mark = 1;
            }
        }
        return $this;
    }

    /**
     * 設置排序
     * @param mixed $option 排序條件數組 例:array('sort'=>'desc')
     * @return $this
     */
    public function order($option) {
        if ($this->_clear>0) $this->_clear();
        $this->_order = ' order by ';
        if (is_string($option)) {
            $this->_order .= $option;
        }
        elseif (is_array($option)) {
            foreach($option as $k=>$v){
                $order = $this->_addChar($k).' '.$v;
                $this->_order .= isset($mark) ? ','.$order : $order;
                $mark = 1;
            }
        }
        return $this;
    }

    /**
     * 設置查詢行數及頁數
     * @param int $page pageSize不爲空時爲頁數,否則爲行數
     * @param int $pageSize 爲空則函數設定取出行數,不爲空則設定取出行數及頁數
     * @return $this
     */
    public function limit($page,$pageSize=null) {
        if ($this->_clear>0) $this->_clear();
        if ($pageSize===null) {
            $this->_limit = "limit ".$page;
        }
        else {
            $pageval = intval( ($page - 1) * $pageSize);
            $this->_limit = "limit ".$pageval.",".$pageSize;
        }
        return $this;
    }

    /**
     * 設置查詢字段
     * @param mixed $field 字段數組
     * @return $this
     */
    public function field($field){
        if ($this->_clear>0) $this->_clear();
        if (is_string($field)) {
            $field = explode(',', $field);
        }
        $nField = array_map(array($this,'_addChar'), $field);
        $this->_field = implode(',', $nField);
        return $this;
    }

    /**
     * 清理標記函數
     */
    protected function _clear() {
        $this->_where = '';
        $this->_order = '';
        $this->_limit = '';
        $this->_field = '*';
        $this->_clear = 0;
    }

    /**
     * 手動清理標記
     * @return $this
     */
    public function clearKey() {
        $this->_clear();
        return $this;
    }

    /**
     * 啓動事務
     * @return void
     */
    public function startTrans() {
        //數據rollback 支持
        if ($this->_trans==0) self::$_dbh->beginTransaction();
        $this->_trans++;
        return;
    }

    /**
     * 用於非自動提交狀態下面的查詢提交
     * @return boolen
     */
    public function commit() {
        $result = true;
        if ($this->_trans>0) {
            $result = self::$_dbh->commit();
            $this->_trans = 0;
        }
        return $result;
    }

    /**
     * 事務回滾
     * @return boolen
     */
    public function rollback() {
        $result = true;
        if ($this->_trans>0) {
            $result = self::$_dbh->rollback();
            $this->_trans = 0;
        }
        return $result;
    }

    /**
     * 關閉連接
     * PHP 在腳本結束時會自動關閉連接。
     */
    public function close() {
        if (!is_null(self::$_dbh)) self::$_dbh = null;
    }

}

conf配置項

array(77) {
  ["builtin.features"]=>
  string(45) "gzip,snappy,sasl,regex,lz4,sasl_plain,plugins"
  ["client.id"]=>
  string(7) "rdkafka"
  ["message.max.bytes"]=>
  string(7) "1000000"
  ["message.copy.max.bytes"]=>
  string(5) "65535"
  ["receive.message.max.bytes"]=>
  string(9) "100000000"
  ["max.in.flight.requests.per.connection"]=>
  string(7) "1000000"
  ["metadata.request.timeout.ms"]=>
  string(5) "60000"
  ["topic.metadata.refresh.interval.ms"]=>
  string(6) "300000"
  ["metadata.max.age.ms"]=>
  string(6) "900000"
  ["topic.metadata.refresh.fast.interval.ms"]=>
  string(3) "250"
  ["topic.metadata.refresh.fast.cnt"]=>
  string(2) "10"
  ["topic.metadata.refresh.sparse"]=>
  string(4) "true"
  ["debug"]=>
  string(0) ""
  ["socket.timeout.ms"]=>
  string(5) "60000"
  ["socket.blocking.max.ms"]=>
  string(4) "1000"
  ["socket.send.buffer.bytes"]=>
  string(1) "0"
  ["socket.receive.buffer.bytes"]=>
  string(1) "0"
  ["socket.keepalive.enable"]=>
  string(5) "false"
  ["socket.nagle.disable"]=>
  string(5) "false"
  ["socket.max.fails"]=>
  string(1) "1"
  ["broker.address.ttl"]=>
  string(4) "1000"
  ["broker.address.family"]=>
  string(3) "any"
  ["enable.sparse.connections"]=>
  string(4) "true"
  ["reconnect.backoff.jitter.ms"]=>
  string(1) "0"
  ["reconnect.backoff.ms"]=>
  string(3) "100"
  ["reconnect.backoff.max.ms"]=>
  string(5) "10000"
  ["statistics.interval.ms"]=>
  string(1) "0"
  ["enabled_events"]=>
  string(1) "0"
  ["log_cb"]=>
  string(14) "0x7f0682d56a60"
  ["log_level"]=>
  string(1) "6"
  ["log.queue"]=>
  string(5) "false"
  ["log.thread.name"]=>
  string(4) "true"
  ["log.connection.close"]=>
  string(4) "true"
  ["socket_cb"]=>
  string(14) "0x7f0682d6d3b0"
  ["open_cb"]=>
  string(14) "0x7f0682d828c0"
  ["internal.termination.signal"]=>
  string(1) "0"
  ["api.version.request"]=>
  string(4) "true"
  ["api.version.request.timeout.ms"]=>
  string(5) "10000"
  ["api.version.fallback.ms"]=>
  string(1) "0"
  ["broker.version.fallback"]=>
  string(6) "0.10.0"
  ["security.protocol"]=>
  string(9) "plaintext"
  ["sasl.mechanisms"]=>
  string(6) "GSSAPI"
  ["sasl.kerberos.service.name"]=>
  string(5) "kafka"
  ["sasl.kerberos.principal"]=>
  string(11) "kafkaclient"
  ["sasl.kerberos.kinit.cmd"]=>
  string(114) "kinit -S "%{sasl.kerberos.service.name}/%{broker.name}" -k -t "%{sasl.kerberos.keytab}" %{sasl.kerberos.principal}"
  ["sasl.kerberos.min.time.before.relogin"]=>
  string(5) "60000"
  ["group.id"]=>
  string(5) "test8"
  ["partition.assignment.strategy"]=>
  string(16) "range,roundrobin"
  ["session.timeout.ms"]=>
  string(5) "10000"
  ["heartbeat.interval.ms"]=>
  string(4) "3000"
  ["group.protocol.type"]=>
  string(8) "consumer"
  ["coordinator.query.interval.ms"]=>
  string(6) "600000"
  ["max.poll.interval.ms"]=>
  string(6) "300000"
  ["enable.auto.commit"]=>
  string(4) "true"
  ["auto.commit.interval.ms"]=>
  string(4) "5000"
  ["enable.auto.offset.store"]=>
  string(4) "true"
  ["queued.min.messages"]=>
  string(6) "100000"
  ["queued.max.messages.kbytes"]=>
  string(7) "1048576"
  ["fetch.wait.max.ms"]=>
  string(3) "100"
  ["fetch.message.max.bytes"]=>
  string(7) "1048576"
  ["fetch.max.bytes"]=>
  string(8) "52428800"
  ["fetch.min.bytes"]=>
  string(1) "1"
  ["fetch.error.backoff.ms"]=>
  string(3) "500"
  ["offset.store.method"]=>
  string(6) "broker"
  ["enable.partition.eof"]=>
  string(5) "false"
  ["check.crcs"]=>
  string(5) "false"
  ["enable.idempotence"]=>
  string(5) "false"
  ["enable.gapless.guarantee"]=>
  string(5) "false"
  ["queue.buffering.max.messages"]=>
  string(6) "100000"
  ["queue.buffering.max.kbytes"]=>
  string(7) "1048576"
  ["queue.buffering.max.ms"]=>
  string(1) "0"
  ["message.send.max.retries"]=>
  string(1) "2"
  ["retry.backoff.ms"]=>
  string(3) "100"
  ["queue.buffering.backpressure.threshold"]=>
  string(1) "1"
  ["compression.codec"]=>
  string(4) "none"
  ["batch.num.messages"]=>
  string(5) "10000"
  ["delivery.report.only.error"]=>
  string(5) "false"
}

topicConf配置項

array(15) {
  ["request.required.acks"]=>
  string(2) "-1"
  ["request.timeout.ms"]=>
  string(4) "5000"
  ["message.timeout.ms"]=>
  string(6) "300000"
  ["queuing.strategy"]=>
  string(4) "fifo"
  ["produce.offset.report"]=>
  string(5) "false"
  ["partitioner"]=>
  string(17) "consistent_random"
  ["compression.codec"]=>
  string(7) "inherit"
  ["compression.level"]=>
  string(2) "-1"
  ["auto.commit.enable"]=>
  string(4) "true"
  ["auto.commit.interval.ms"]=>
  string(5) "60000"
  ["auto.offset.reset"]=>
  string(7) "largest"
  ["offset.store.path"]=>
  string(4) "/tmp"
  ["offset.store.sync.interval.ms"]=>
  string(2) "-1"
  ["offset.store.method"]=>
  string(6) "broker"
  ["consume.callback.max.messages"]=>
  string(1) "0"
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章