C++ 向kafka中发送数据

kafka是一个分布式流处理的平台,通过kafka我们可以发布和订阅流式记录。有关kafka的介绍可以参考官网或者这篇文章 https://juejin.im/post/6844903495670169607 ,介绍的非常的详细。
我个人喜欢把kafka当做数据库去理解,因为它也有存放数据的功能,但是还是与数据库是不一样的。
kafka中多个broker称为一个集群,一个broker(独立的kafka服务器)中可以创建不同的topic(主题),topic下可以建立多个partition(分区),数据则存放在分区中的一个单元里面(partition可以近似理解为一个数组,存入kafka的一条记录就存放在partition1[0]、partition1[1]…)。
生产者向kafka中生产数据,即把数据推入kafka中,消费者消费kafka中的数据,一个主题可以被多个消费者消费,这个是不同于数据库的地方。
在这里插入图片描述

下面介绍kafka在Linux下的简单使用
1 使用流程
2 问题及解决办法
3 代码示例

1 使用流程

首先服务器上必须已经安装好kafka!
1、在GitHub上下载librdkafka-master.zip安装文件,解压到文件夹https://github.com/edenhill/librdkafka
2、编译文件
cd librdkafka-master //cd到刚刚解压到的文件目录下
chmod 777 configure lds-gen.py
./confgure
make
make install
3、新建文件夹用于存放代码
4、在搭建好的kafka服务器上新建主题"test1"
./kafka-topics.sh --create --zookeeper localhost:2198–replication-factor1 --partitions1 --topic test1
2193是kafka所在的端口,根据自己的实际情况设置 。
5、将/usr/local/lib路径下的librdkafka++.a、librdkafka++.so、librdkafka.so.1放入自己创建的代码的文件夹下;
6、rdkafkacpp.h头文件加入创建的代码文件夹下,并在代码中引入头文件#include “rdkafkacpp.h”
7、在代码中设置broker和topic
std::string brokers=“127.0.0.1:9092”; //地址为kafka服务器地址,这里是随便写的
std::string topic=“test1” //主题为kafka中存在的主题
8、编译代码时加入 -lstdc++ -lrdkafka -lrdkafka++ -lrt -lpthread -L.

2 问题及解决办法

1、Connection refused
thrd:localhost:9092/bootstrap: Connection to ipv6#[::1]: 9092 failed : Connection refused
此类问题是由于地址设置不正确,没有将brokers地址设置为kafka所在的服务器地址,且服务器地址不能使用localhost代替。

2、搭建的kafka上查看不到创建的主题
可以查看rdkafkacpp.h头文件,调用的函数是哪一个,有的函数里的参数里面的topic主题必须是kafka上已经存在的主题。

3、Disconnected While requesting ApiVersion
Disconnected While requesting ApiVersion: might be caused by incorrect security. protocol configuration (connecting to a SSL listener?) or broker version is < 0.10
这个问题是由于代码中brokers的服务端口设置错误导致,应该设置为9092(配置文件中的默认端口):
std::string brokers = “ip::9092”;

4、代码存放的位置不一定与kafka在同一位置上,只要代码中的brokers的地址设置为kafka所在的服务器地址即可。

代码示例

这个是参考github上面的代码改的producer.cpp
想要把代码运行起来,需要参考上面的 1 使用流程 进行设置

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <csignal>
#include <cstring>
#if _AIX
#include <unistd.h>
#endif

#include "rdkafkacpp.h"

static volatile sig_atomic_t run = 1;

static void sigterm (int sig) {
run = 0;
}

//成功发送一次信息调用一次回调函数
class ExampleDeliveryReportCb : public RdKafka::DeliveryReportCb {
public:
    void dr_cb (RdKafka::Message &message) {
    /* If message.err() is non-zero the message delivery failed permanently for the message. */
    if (message.err())
      std::cerr << "% Message delivery failed: " << message.errstr() << std::endl;
    else
      std::cerr << "% Message delivered to topic " << message.topic_name() <<
       " [" << message.partition() << "] at offset " <<
     message.offset() << std::endl;
    }
};

int main () {

std::string brokers = "127.0.0.1:9092";  //这里的IP地址应该设置为kafka所在服务器地址
std::string topic = "test";    //设置主题
std::string errstr;

//设置配置
RdKafka::Conf *conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);

if (conf->set("bootstrap.servers", brokers, errstr) !=
    RdKafka::Conf::CONF_OK) {
    std::cerr << errstr << std::endl;
    exit(1);
}

signal(SIGINT, sigterm);
signal(SIGTERM, sigterm);

ExampleDeliveryReportCb ex_dr_cb;

if (conf->set("dr_cb", &ex_dr_cb, errstr) != RdKafka::Conf::CONF_OK) {
  std::cerr << errstr << std::endl;
  exit(1);
}

//创建 producer 
RdKafka::Producer *producer = RdKafka::Producer::create(conf, errstr);
if (!producer) {
  std::cerr << "Failed to create producer: " << errstr << std::endl;
  exit(1);
}

delete conf;

/*
 * Read messages from stdin and produce to broker.
 */
std::cout << "% Type message value and hit enter " <<
"to produce message." << std::endl;

for (std::string line; run && std::getline(std::cin, line);) {
  if (line.empty()) {
    producer->poll(0);
    continue;
  }

//将message传入队列中
retry:
  RdKafka::ErrorCode err =
    producer->produce(topic,
                      RdKafka::Topic::PARTITION_UA,   //随机分区
                      /* Make a copy of the value */
                      RdKafka::Producer::RK_MSG_COPY /* Copy payload */,
                      /* Value */
                      const_cast<char *>(line.c_str()), line.size(),  //需要写入的数据
                       /* Key */
                      NULL, 0,
                      /* Timestamp (defaults to current time) */
                      0,
                      /* Message headers, if any */
                      NULL,
                      /* Per-message opaque value passed to
                       * delivery report */
                      NULL);

  if (err != RdKafka::ERR_NO_ERROR) {
    std::cerr << "% Failed to produce to topic " << topic << ": " <<
      RdKafka::err2str(err) << std::endl;

    if (err == RdKafka::ERR__QUEUE_FULL) {    //存放数据的队列已满,将执行等待
      producer->poll(1000);
      goto retry;
    }

  } else {
    std::cerr << "% Enqueued message (" << line.size() << " bytes) " <<
    "for topic " << topic << std::endl;
  }

  producer->poll(0);  //保持常态
}

std::cerr << "% Flushing final messages..." << std::endl;
producer->flush(10*1000 /* wait for max 10 seconds */);

run = true ;   //之前因为没有加这个就报错了

if (producer->outq_len() > 0)  //发送数据
  std::cerr << "% " << producer->outq_len() <<
          " message(s) were not delivered" << std::endl;

delete producer;

return 0;
 }

--------如有侵权,联系删除!

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kafka是一个高性能、分布式消息队列系统,可以用于处理实时数据流。在Kafka,延迟队列可以通过两种方式来实现: 1. Kafka的topic partition分区。可以通过设置消息在分区的时间戳来实现延迟消息的功能。在消息被消费之前,它们将被保留在分区。一旦到达指定的延迟时间,消息将被消费。 2. Kafka的消费者组。可以将延迟消息作为一个特殊的主题发送到Kafka,并使用单独的消费者组进行消费。在消费者组,可以使用定时器或其他方法来处理延迟消息。 以下是使用C++实现Kafka的延迟队列的示例代码: ```c++ #include <iostream> #include <string> #include <librdkafka/rdkafkacpp.h> using namespace std; int main() { string brokers = "localhost:9092"; string topic = "delayed_messages"; RdKafka::Conf* conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); conf->set("metadata.broker.list", brokers, errstr); conf->set("dr_cb", true, errstr); RdKafka::Producer* producer = RdKafka::Producer::create(conf, errstr); RdKafka::Topic* rd_topic = RdKafka::Topic::create(producer, topic, NULL, errstr); // 发送延迟消息 string message = "hello"; int64_t delay_time = 1000; // 延迟1秒 int64_t timestamp = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ).count() + delay_time; RdKafka::Headers* headers = RdKafka::Headers::create(); headers->add("timestamp", std::to_string(timestamp)); RdKafka::ErrorCode err = producer->produce( rd_topic, RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, const_cast<char*>(message.c_str()), message.size(), NULL, 0, 0, headers ); // 关闭Kafka连接 producer->flush(1000); delete headers; delete rd_topic; delete producer; delete conf; return 0; } ``` 在上面的代码,我们使用librdkafka C++库来连接到Kafka,并创建一个生产者实例。然后,我们创建一个主题,并将延迟消息发送到分区。 请注意,我们在消息头添加了一个时间戳,它表示消息应该在何时被消费。我们使用了C++11的std::chrono库来计算当前时间戳加上延迟时间。 在消费者端,我们可以使用Kafka的Consumer API来创建一个消费者组,并在指定的时间戳之后消费消息。例如,以下是使用Kafka Consumer API来消费延迟消息的示例代码: ```c++ #include <iostream> #include <string> #include <librdkafka/rdkafkacpp.h> using namespace std; int main() { string brokers = "localhost:9092"; string topic = "delayed_messages"; string group = "delayed_consumer_group"; RdKafka::Conf* conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); conf->set("metadata.broker.list", brokers, errstr); conf->set("group.id", group, errstr); RdKafka::Consumer* consumer = RdKafka::Consumer::create(conf, errstr); delete conf; RdKafka::Topic* rd_topic = RdKafka::Topic::create(consumer, topic, NULL, errstr); // 订阅主题 RdKafka::ErrorCode err = consumer->subscribe(rd_topic, NULL); while (true) { RdKafka::Message* message = consumer->consume(1000); if (message->err() == RdKafka::ERR_NO_ERROR) { // 获取消息头的时间戳 const RdKafka::Headers* headers = message->headers(); const RdKafka::Header* timestamp_header = headers->get("timestamp"); int64_t timestamp = std::stoll((const char*)timestamp_header->value()); // 判断是否到达消费时间 int64_t current_time = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::system_clock::now().time_since_epoch() ).count(); if (current_time >= timestamp) { cout << "Received Message: " << string((char*)message->payload(), message->len()) << endl; } } delete message; } // 关闭Kafka连接 consumer->unsubscribe(); delete rd_topic; delete consumer; return 0; } ``` 在上面的代码,我们使用Kafka的Consumer API来创建一个消费者实例,并订阅延迟消息的主题。然后,我们在一个循环不断地消费消息,并判断是否到达消费时间。如果到达了,我们就将消息输出到控制台。 请注意,我们在消息头添加了一个时间戳,以便在消费者端可以判断何时开始消费消息。我们使用了C++11的std::chrono库来计算当前时间戳。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值