zoukankan      html  css  js  c++  java
  • 使用librdkafka库实现kafka的生产和消费实例生产者

    一、生产者

    librdkafka进行kafka生产操作的大致步骤如下:

    1、创建kafka配置

    rd_kafka_conf_t *rd_kafka_conf_new (void)

    2、配置kafka各项参数

    rd_kafka_conf_res_t rd_kafka_conf_set (rd_kafka_conf_t *conf,  
                                           const char *name,  
                                           const char *value,  
                                           char *errstr, size_t errstr_size) 

    3、设置发送回调函数

    void rd_kafka_conf_set_dr_msg_cb (rd_kafka_conf_t *conf,  
                                      void (*dr_msg_cb) (rd_kafka_t *rk,  
                                      const rd_kafka_message_t *  
                                      rkmessage,  
                                      void *opaque)) 

    4、创建producer实例

    rd_kafka_t *rd_kafka_new (rd_kafka_type_t type, rd_kafka_conf_t *conf,char *errstr, size_t errstr_size)  

    5、创建topic

    rd_kafka_topic_t *rd_kafka_topic_new (rd_kafka_t *rk, const char *topic, rd_kafka_topic_conf_t *conf)  

    6、异步调用将消息发送到指定的topic

    int rd_kafka_produce (rd_kafka_topic_t *rkt, int32_t partition,  
                  int msgflags,  
                  void *payload, size_t len,  
                  const void *key, size_t keylen,  
                  void *msg_opaque)  

    7、阻塞等待消息发送完成

    int rd_kafka_poll (rd_kafka_t *rk, int timeout_ms) 

    8、等待完成product请求完成

    rd_kafka_resp_err_t rd_kafka_flush (rd_kafka_t *rk, int timeout_ms)

    9、销毁topic

    void rd_kafka_topic_destroy (rd_kafka_topic_t *app_rkt)  

    10、销毁producer实例

    void rd_kafka_destroy (rd_kafka_t *rk)

    代码示例product.c

    #include <stdio.h>  
    #include <signal.h>  
    #include <string.h>  
      
    #include "../src/rdkafka.h"  
      
    static int run = 1;  
      
    static void stop(int sig){  
        run = 0;  
        fclose(stdin);  
    }  
      
    /* 
        每条消息调用一次该回调函数,说明消息是传递成功(rkmessage->err == RD_KAFKA_RESP_ERR_NO_ERROR) 
        还是传递失败(rkmessage->err != RD_KAFKA_RESP_ERR_NO_ERROR) 
        该回调函数由rd_kafka_poll()触发,在应用程序的线程上执行 
     */  
    static void dr_msg_cb(rd_kafka_t *rk,  
                          const rd_kafka_message_t *rkmessage, void *opaque)
    {
    if(rkmessage->err) fprintf(stderr, "%% Message delivery failed: %s\n", rd_kafka_err2str(rkmessage->err)); else fprintf(stderr, "%% Message delivered (%zd bytes, " "partition %"PRId32")\n", rkmessage->len, rkmessage->partition); /* rkmessage被librdkafka自动销毁*/ } int main(int argc, char **argv){ rd_kafka_t *rk; /*Producer instance handle*/ rd_kafka_topic_t *rkt; /*topic对象*/ rd_kafka_conf_t *conf; /*临时配置对象*/ char errstr[512]; char buf[512]; const char *brokers; const char *topic; if(argc != 3){ fprintf(stderr, "%% Usage: %s <broker> <topic>\n", argv[0]); return 1; } brokers = argv[1]; topic = argv[2]; /* 创建一个kafka配置占位 */ conf = rd_kafka_conf_new(); /*创建broker集群*/ if (rd_kafka_conf_set(conf, "bootstrap.servers", brokers, errstr, sizeof(errstr)) != RD_KAFKA_CONF_OK){ fprintf(stderr, "%s\n", errstr); return 1; } /*设置发送报告回调函数,rd_kafka_produce()接收的每条消息都会调用一次该回调函数 *应用程序需要定期调用rd_kafka_poll()来服务排队的发送报告回调函数*/ rd_kafka_conf_set_dr_msg_cb(conf, dr_msg_cb); /*创建producer实例 rd_kafka_new()获取conf对象的所有权,应用程序在此调用之后不得再次引用它*/ rk = rd_kafka_new(RD_KAFKA_PRODUCER, conf, errstr, sizeof(errstr)); if(!rk){ fprintf(stderr, "%% Failed to create new producer:%s\n", errstr); return 1; } /*实例化一个或多个topics(`rd_kafka_topic_t`)来提供生产或消费,topic 对象保存topic特定的配置,并在内部填充所有可用分区和leader brokers,*/ rkt = rd_kafka_topic_new(rk, topic, NULL); if (!rkt){ fprintf(stderr, "%% Failed to create topic object: %s\n", rd_kafka_err2str(rd_kafka_last_error())); rd_kafka_destroy(rk); return 1; } /*用于中断的信号*/ signal(SIGINT, stop); fprintf(stderr, "%% Type some text and hit enter to produce message\n" "%% Or just hit enter to only serve delivery reports\n" "%% Press Ctrl-C or Ctrl-D to exit\n"); while(run && fgets(buf, sizeof(buf), stdin)){ size_t len = strlen(buf); if(buf[len-1] == '\n') buf[--len] = '\0'; if(len == 0){ /*轮询用于事件的kafka handle, 事件将导致应用程序提供的回调函数被调用 第二个参数是最大阻塞时间,如果设为0,将会是非阻塞的调用*/ rd_kafka_poll(rk, 0); continue; } retry: /*Send/Produce message. 这是一个异步调用,在成功的情况下,只会将消息排入内部producer队列, 对broker的实际传递尝试由后台线程处理,之前注册的传递回调函数(dr_msg_cb) 用于在消息传递成功或失败时向应用程序发回信号*/ if (rd_kafka_produce( /* Topic object */ rkt, /*使用内置的分区来选择分区*/ RD_KAFKA_PARTITION_UA, /*生成payload的副本*/ RD_KAFKA_MSG_F_COPY, /*消息体和长度*/ buf, len, /*可选键及其长度*/ NULL, 0, NULL) == -1){ fprintf(stderr, "%% Failed to produce to topic %s: %s\n", rd_kafka_topic_name(rkt), rd_kafka_err2str(rd_kafka_last_error())); if (rd_kafka_last_error() == RD_KAFKA_RESP_ERR__QUEUE_FULL){ /*如果内部队列满,等待消息传输完成并retry, 内部队列表示要发送的消息和已发送或失败的消息, 内部队列受限于queue.buffering.max.messages配置项*/ rd_kafka_poll(rk, 1000); goto retry; } }else{ fprintf(stderr, "%% Enqueued message (%zd bytes) for topic %s\n", len, rd_kafka_topic_name(rkt)); } /*producer应用程序应不断地通过以频繁的间隔调用rd_kafka_poll()来为 传送报告队列提供服务。在没有生成消息以确定先前生成的消息已发送了其 发送报告回调函数(和其他注册过的回调函数)期间,要确保rd_kafka_poll() 仍然被调用*/ rd_kafka_poll(rk, 0); } fprintf(stderr, "%% Flushing final message.. \n"); /*rd_kafka_flush是rd_kafka_poll()的抽象化, 等待所有未完成的produce请求完成,通常在销毁producer实例前完成 以确保所有排列中和正在传输的produce请求在销毁前完成*/ rd_kafka_flush(rk, 10*1000); /* Destroy topic object */ rd_kafka_topic_destroy(rkt); /* Destroy the producer instance */ rd_kafka_destroy(rk); return 0; }

    原文博客:http://blog.csdn.net/lijinqi1987/article/details/76582067

  • 相关阅读:
    【POJ 1958】 Strange Towers of Hanoi
    【HNOI 2003】 激光炸弹
    【POJ 3263】 Tallest Cow
    【POJ 2689】 Prime Distance
    【POJ 2777】 Count Color
    【POJ 1995】 Raising Modulo Numbers
    【POJ 1845】 Sumdiv
    6月16日省中集训题解
    【TJOI 2018】数学计算
    【POJ 1275】 Cashier Employment
  • 原文地址:https://www.cnblogs.com/GnibChen/p/8604544.html
Copyright © 2011-2022 走看看