分布式运行模式下Kafka Producer的唯一事务ID

时间:2018-07-11 05:34:21

标签: apache-kafka bigdata kafka-producer-api

我有一个基于流程Consume-> Process-> Produce的大数据应用程序。我在提取管道中使用Kafka,并在使用事务生成器来生成消息。我的应用程序的所有部分都运行良好,但是为事务生成器生成ID时存在一个小问题。场景:

假设我的应用程序在一台机器上运行,我实例化了两个拥有自己生产者的使用者,因此例如可以说 生产者1的交易ID为-> Consumer-0-Producer 生产者2的交易ID为-> Consumer-1-Producer 现在,这两个生产者发起的交易不会互相干扰,这就是我所希望的。伪代码看起来像这样:

ExecutorService executorService// responsible for starting my consumers
for (int i = 0; i < 2; i++) {
    prod_trans_id = "consumer-" + str(i) + "-producer"
    Custom_Consumer consumer = new Custom_Consumer(prod_trans_id)
    executorService.submit(consumer)
}

如果我的应用程序可以在单台机器上运行,则可以很好地工作,但是不是这样,因为该应用程序需要在多台机器上运行,所以当同一代码在第二台机器上运行时,生产者将由消费者实例化。机器2的事务ID与机器1上的事务ID相同。我希望产生一种事务ID,使其彼此不冲突且可重复,这意味着如果应用程序崩溃/停止(例如有人先service application stop,然后再service application start),当它重新联机时,它应该使用以前使用的相同的交易ID。我想到了基于UUID的方法,但是,当一台计算机上的应用程序死亡并重新联机时,UUID是随机的,并且不会相同。

1 个答案:

答案 0 :(得分:0)

private final static String HOSTNAME_COMMAND = "hostname";

public static String getHostName() {
        BufferedReader inputStreamReader = null;
        BufferedReader errorStreamReader = null;
        try {
            Process process = Runtime.getRuntime().exec(HOSTNAME_COMMAND);
            inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            if (errorStreamReader.readLine() != null) {
                throw new RuntimeException(String.format("Failed to get the hostname, exception message: %s",
                        errorStreamReader.readLine()));
            }
            return inputStreamReader.readLine();
        } catch (IOException e) {
            try {
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
                if (errorStreamReader != null) {
                    errorStreamReader.close();
                }
            } catch (IOException e1) {
                LogExceptionTrace.logExceptionStackTrace(e1);
                throw new RuntimeException(e1);
            }
            LogExceptionTrace.logExceptionStackTrace(e);
            throw new RuntimeException(e);
        }
    }

然后使用主机名,如下所示:

final String producerTransactionalID = String.format("%s_producer", this.consumerName);

消费者名称设置如下:

for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
            String consumerName = String.format("%s-worker-%d", hostName, i);
            Executor executor = new Executor(
                    Configuration, consumerName
            );
            Executors.add(executor);
            futures.add(executorService.submit(executor));
        }