php实现kafka

kafka类:

php 复制代码
<?php

class b2c_kafka
{
    public $broker_list;
    public $topic;
    public $group_id;
    protected $producer = null;
    protected $consumer = null;
    protected $receive_wait_time;
    protected $receive_wait_num;

    /**
     * 构造方法
     * @param object app
     */
    public function __construct()
    {
        $this->broker_list = 'kafka';
        $this->topic = 'local-cn';
        $this->group_id = ' kafka-map';
        $this->producer = null;
        $this->consumer = null;
        $this->receive_wait_time = 10;
        $this->receive_wait_num = 100;

    }
    /**
     * 获取生产者
     */
    public function Producer()
    {
        $conf = new \RdKafka\Conf();
        // $conf->set('bootstrap.servers', $this->broker_list);
        $conf->set('metadata.broker.list', $this->broker_list);

        // 0:不会等待服务器的反馈。该消息会被立刻添加到 socket buffer 中并认为已经发送完成
        // 1:leader节点会将记录写入本地日志,并且在所有 follower 节点反馈之前就先确认成功
        // all:leader 节点会等待所有同步中的副本确认之后再确认这条记录是否发送完成
        $conf->set('acks', '0');

        //If you need to produce exactly once and want to keep the original produce order, uncomment the line below
        //$conf->set('enable.idempotence', 'true');

        $producer = new \RdKafka\Producer($conf);
        $this->producer = $producer;
        return $this;
    }
    /**
     * 发送消息
     *
     * @param string|array $msg
     * @param string $topic
     * @return void
     */
    public function SendMsg($msg = '', $topic = '')
    {
        if (empty($topic)) {
            $topic = $this->topic;
        }
        $producer = $this->producer;

        $topic = $producer->newTopic($topic);

        if (!is_array($msg)) {
            $msg = [$msg];
        }
        foreach ($msg as $value) {
            $topic->produce(RD_KAFKA_PARTITION_UA, 0, $value);
            $producer->poll(0);
        }
        for ($flushRetries = 0; $flushRetries < count($msg); $flushRetries++) {
            $result = $producer->flush(10000);            
            if (RD_KAFKA_RESP_ERR_NO_ERROR === $result) {
                break;
            }
        }
        if (RD_KAFKA_RESP_ERR_NO_ERROR !== $result) {
            throw new \RuntimeException('Kafka消息发送失败,错误代码:' . $result);
        }
    }

    /**
     * 获取消费者
     *
     * @param string $group_id
     * @return void
     */
    public function Consumer($group_id = '')
    {
        $conf = new \RdKafka\Conf();

        // Set a rebalance callback to log partition assignments (optional)
        $conf->setRebalanceCb(function (\RdKafka\KafkaConsumer $kafka, $err, array $partitions = null) {
            switch ($err) {
                case RD_KAFKA_RESP_ERR__ASSIGN_PARTITIONS:
                    echo "Assign: ";
                    var_dump($partitions);
                    $kafka->assign($partitions);
                    break;

                case RD_KAFKA_RESP_ERR__REVOKE_PARTITIONS:
                    echo "Revoke: ";
                    var_dump($partitions);
                    $kafka->assign(NULL);
                    break;

                default:
                    throw new \Exception($err);
            }
        });
        // Configure the group.id. All consumer with the same group.id will consume
        // different partitions.
        if (empty($group_id)) {
            $group_id = $this->group_id;
        }
        // 设置相同的group,防止一次消息被多次消费。
        // 消费者启动的进程数应小于等于topic的分区数,否则多余的进程是无用的
        $conf->set('group.id', $group_id);

        // Initial list of Kafka brokers
        // $conf->set('bootstrap.servers', $this->broker_list);
        $conf->set('metadata.broker.list', $this->broker_list);

        // Set where to start consuming messages when there is no initial offset in
        // offset store or the desired offset is out of range.
        // 'smallest': start from the beginning
        //earliest:简单理解为从头开始消费,latest:简单理解为从最新的开始消费
        $conf->set('auto.offset.reset', 'earliest');
        // 在interval.ms的时间内定期向ZooKeeper提交使用者已获取的消息的偏移量
        // 自动提交分区消费的位置,手动可确保消息被消费
        $conf->set('enable.auto.commit', true);
        $conf->set('auto.commit.interval.ms', 1000);

        $consumer = new \RdKafka\KafkaConsumer($conf);

        $this->consumer = $consumer;
        return $this;
    }

    /**
     * 接收消息
     *
     * @param string $topic
     * @param array $callback
     * @return void
     */
    public function ReceiveMsg($topic = '', array $callback = [])
    {
        $consumer = $this->consumer;

        if (empty($topic)) {
            $topic = $this->topic;
        }
        if (!is_array($topic)) {
            $topic = [$topic];
        }
        // Subscribe to topic 'test'
        $consumer->subscribe($topic);

        echo "Waiting for partition assignment... (make take some time when\n";
        echo "quickly re-joining the group after leaving it.)\n";

        $i = 0;
        $msg_list = [];
        while (true) {
            $i++;
            if ($i > $this->receive_wait_time) {
                $i = 0;
                if (empty($msg_list)) {
                    continue;
                }
                if (!empty($callback)) {
                    call_user_func_array($callback, [$msg_list]);
                }
                $msg_list = [];
            }
            // 阻塞一秒钟
            $message = $consumer->consume(1000);
            switch ($message->err) {
                case RD_KAFKA_RESP_ERR_NO_ERROR:
                    $msg_list[] = $message->payload;
                    if (count($msg_list) < $this->receive_wait_num) {
                        continue;
                    }
                    if (!empty($callback)) {
                        call_user_func_array($callback, [$msg_list]);
                    }
                    $i = 0;
                    $msg_list = [];
                    break;
                case RD_KAFKA_RESP_ERR__PARTITION_EOF:
                    // echo "No more messages; will wait for more\n";
                    break;
                case RD_KAFKA_RESP_ERR__TIMED_OUT:
                    // echo "Timed out\n";
                    break;
                default:
                    throw new \Exception($message->errstr(), $message->err);
                    break;
            }
        }
    }


}

调用:

php 复制代码
$data['member_id']     = '121221';
$data['ip']            = $this->getIp();
$data['timestamp']     = $this->getMicrotime();
        
$kafkaObj = new kafka();
$kafkaObj->Producer()->sendMsg(json_encode($data, 320));
相关推荐
残月只会敲键盘2 小时前
面相小白的php反序列化漏洞原理剖析
开发语言·php
ac-er88882 小时前
PHP弱类型安全问题
开发语言·安全·php
ac-er88882 小时前
PHP网络爬虫常见的反爬策略
开发语言·爬虫·php
yanwushu2 小时前
Xserver v1.4.2发布,支持自动重载 nginx 配置
mysql·nginx·php·个人开发·composer
Stringzhua2 小时前
【SpringCloud】Kafka消息中间件
spring·spring cloud·kafka
事业运财运爆棚3 小时前
php 如何将数组转成对象数组
php
天下皆白_唯我独黑3 小时前
php 使用qrcode制作二维码图片
开发语言·php
杨荧9 小时前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
zmd-zk10 小时前
kafka+zookeeper的搭建
大数据·分布式·zookeeper·中间件·kafka
激流丶10 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic