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));
相关推荐
BingoGo5 小时前
PHP Composer 依赖管理完整指南 入门到精通
后端·php
望获linux9 小时前
【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描
java·linux·开发语言·前端·数据库·信息可视化·php
做一位快乐的码农17 小时前
php程序设计之基于PHP的手工艺品销售网站/基于php在线销售系统/基于php在线购物商城系统
开发语言·php
Hello.Reader21 小时前
Kafka 4.0 从零到一8 步快速上手 + 实战要点与避坑
分布式·kafka
苏琢玉21 小时前
一个轻量的PHP+Vue的前后端加密方案,写给有类似需求的朋友
php·composer
neoooo1 天前
Spring Boot 3 + Kafka 实战指南
java·spring boot·kafka
武子康1 天前
大数据-79 Kafka 监控从入门到实战:度量体系、JMX采集与可视化告警全流程 Prometheus、Kafka Eagle
大数据·后端·kafka
piikee1 天前
php内存缓存插件yac的安装配置--平替apcu,多进程共享内存
开发语言·缓存·php·yac·php扩展·php内存缓存·apcu平替
smileNicky2 天前
Kafka 为什么具有高吞吐量的特性?
分布式·kafka
WayneJoon.H2 天前
CTFSHOW | 其他篇题解(一)web396-web416
sql·安全·web安全·网络安全·php