Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 卡夫卡因Docker延迟而超时_Python_Docker_Jenkins_Apache Kafka - Fatal编程技术网

Python 卡夫卡因Docker延迟而超时

Python 卡夫卡因Docker延迟而超时,python,docker,jenkins,apache-kafka,Python,Docker,Jenkins,Apache Kafka,我对卡夫卡和多克完全陌生,有一个问题需要解决。我们针对Kafka(Apache)队列的持续集成测试在本地计算机上运行良好,但在Jenkins CI服务器上时,偶尔会出现以下错误: %3|1508247800.270|FAIL|art#producer-1| [thrd:localhost:9092/bootstrap]: localhost:9092/bootstrap: Connect to ipv4#127.0.0.1:9092 failed: Connection refused %3|1

我对卡夫卡和多克完全陌生,有一个问题需要解决。我们针对Kafka(Apache)队列的持续集成测试在本地计算机上运行良好,但在Jenkins CI服务器上时,偶尔会出现以下错误:

%3|1508247800.270|FAIL|art#producer-1| [thrd:localhost:9092/bootstrap]: localhost:9092/bootstrap: Connect to ipv4#127.0.0.1:9092 failed: Connection refused
%3|1508247800.270|ERROR|art#producer-1| [thrd:localhost:9092/bootstrap]: localhost:9092/bootstrap: Connect to ipv4#127.0.0.1:9092 failed: Connection refused
%3|1508247800.270|ERROR|art#producer-1| [thrd:localhost:9092/bootstrap]: 1/1 brokers are down
工作原理是Docker的形象需要一段时间才能开始,到那时卡夫卡制作人已经放弃了。违规代码是

    producer_properties = {
        'bootstrap.servers': self._job_queue.bootstrap_server,
        'client.id': self._job_queue.client_id
    }
    try:
        self._producer = kafka.Producer(**producer_properties)
    except:
        print("Bang!")

上面的错误行出现在生产者的创建中。但是,没有引发异常,并且调用返回一个外观有效的生产者,因此我无法以编程方式测试代理端点的存在。是否有API来检查代理的状态?

如果与代理的连接失败,客户端似乎不会抛出异常。当生产者第一次尝试发送消息时,它实际上会尝试连接到引导服务器。如果连接失败,它会重复尝试连接到引导列表中传递的任何代理。最终,如果代理出现,将发生send(我们可以在回调函数中检查状态)。 合流的kafka python库正在使用librdkafka库,该客户端似乎没有适当的文档。卡夫卡协议指定的某些卡夫卡生产者选项似乎不受librdkafka支持

以下是我使用的回调的示例代码:

from confluent_kafka import Producer

def notifyme(err, msg):
    print err, msg.key(), msg.value()

p = Producer({'bootstrap.servers': '127.0.0.1:9092', 'retry.backoff.ms' : 100,
        'message.send.max.retries' : 20,
        "reconnect.backoff.jitter.ms" :  2000})
try:
    p.produce(topic='sometopic', value='this is data', on_delivery=notifyme)
except Exception as e:
    print e
p.flush()

此外,检查代理是否存在,您可以在代理的端口上远程登录到代理ip(在本例中为9092)。在卡夫卡集群使用的Zookeeper上,您可以在/brokers/ids下检查znodes的内容,这是似乎对我有用的代码。如果它看起来有点像弗兰肯斯坦,那么你是对的,它是!如果有一个干净的解决方案,我期待着看到它:

import time
import uuid
from threading import Event
from typing import Dict

import confluent_kafka as kafka
# pylint: disable=no-name-in-module
from confluent_kafka.cimpl import KafkaError

# more imports...

LOG = # ...


# Default number of times to retry connection to Kafka Broker
_DEFAULT_RETRIES = 3

# Default time in seconds to wait between connection attempts
_DEFAULT_RETRY_DELAY_S = 5.0

# Number of times to scan for an error after initiating the connection. It appears that calling
# flush() once on a producer after construction isn't sufficient to catch the 'broker not available'
# # error. At least twice seems to work.
_NUM_ERROR_SCANS = 2


class JobProducer(object):
    def __init__(self, connection_retries: int=_DEFAULT_RETRIES,
                 retry_delay_s: float=_DEFAULT_RETRY_DELAY_S) -> None:
        """
        Constructs a producer.
        :param connection_retries: how many times to retry the connection before raising a
        RuntimeError. If 0, retry forever.
        :param retry_delay_s: how long to wait between retries in seconds.
        """
        self.__error_event = Event()
        self._job_queue = JobQueue()
        self._producer = self.__wait_for_broker(connection_retries, retry_delay_s)
        self._topic = self._job_queue.topic

    def produce_job(self, job_definition: Dict) -> None:
        """
        Produce a job definition on the queue
        :param job_definition: definition of the job to be executed
        """
        value = ... # Conversion to JSON
        key = str(uuid.uuid4())
        LOG.info('Produced message: %s', value)

        self.__error_event.clear()
        self._producer.produce(self._topic,
                               value=value,
                               key=key,
                               on_delivery=self._on_delivery)
        self._producer.flush(self._job_queue.flush_timeout)

    @staticmethod
    def _on_delivery(error, message):
        if error:
            LOG.error('Failed to produce job %s, with error: %s', message.key(), error)

    def __create_producer(self) -> kafka.Producer:
        producer_properties = {
            'bootstrap.servers': self._job_queue.bootstrap_server,
            'error_cb': self.__on_error,
            'client.id': self._job_queue.client_id,
        }
        return kafka.Producer(**producer_properties)

    def __wait_for_broker(self, retries: int, delay: float) -> kafka.Producer:
        retry_count = 0
        while True:
            self.__error_event.clear()
            producer = self.__create_producer()
            # Need to call flush() several times with a delay between to ensure errors are caught.
            if not self.__error_event.is_set():
                for _ in range(_NUM_ERROR_SCANS):
                    producer.flush(0.1)
                    if self.__error_event.is_set():
                        break
                    time.sleep(0.1)
                else:
                    # Success: no errors.
                    return producer

            # If we get to here, the error callback was invoked.
            retry_count += 1
            if retries == 0:
                msg = '({})'.format(retry_count)
            else:
                if retry_count <= retries:
                    msg = '({}/{})'.format(retry_count, retries)
                else:
                    raise RuntimeError('JobProducer timed out')

            LOG.warn('JobProducer: could not connect to broker, will retry %s', msg)
            time.sleep(delay)

    def __on_error(self, error: KafkaError) -> None:
        LOG.error('KafkaError: %s', error.str())
        self.__error_event.set()
导入时间
导入uuid
从线程导入事件
从键入导入Dict
导入合流卡夫卡作为卡夫卡
#pylint:disable=模块中没有名称
从confluent_kafka.cimpl导入Kafkaeror
#更多的进口。。。
日志=#。。。
#重试连接到Kafka Broker的默认次数
_默认重试次数=3次
#连接尝试之间的默认等待时间(秒)
_默认值\u重试\u延迟\u S=5.0
#启动连接后扫描错误的次数。看来
#构建后对生产者进行一次flush()不足以捕获“代理不可用”
##错误。至少两次似乎有效。
_NUM\u错误\u扫描=2
类JobProducer(对象):
def uuu init uuu(self,connection_retries:int=_DEFAULT_retries,
retry\u delay\u s:float=\u DEFAULT\u retry\u delay\u s)->无:
"""
构造一个生产者。
:param connection_retries:在引发错误之前重试连接多少次
运行时错误。如果为0,请永远重试。
:param retry_delay_s:两次重试之间的等待时间(以秒为单位)。
"""
self.\u错误\u事件=事件()
self.\u job\u queue=JobQueue()
self.\u producer=self.\u等待\u代理(连接重试、重试延迟)
self.\u topic=self.\u job\u queue.topic
def生产作业(自我,作业定义:Dict)->无:
"""
在队列上生成作业定义
:param job_definition:要执行的作业的定义
"""
值=…#转换为JSON
key=str(uuid.uuid4())
LOG.info('生成的消息:%s',值)
self.\u错误\u事件.清除()
自我制作(自我主题),
值=值,
键=键,
交付时=自我。\交付时)
self.\u producer.flush(self.\u job\u queue.flush\u超时)
@静力学方法
def-on-U交付(错误、消息):
如果出现错误:
LOG.error('无法生成作业%s,错误为:%s',消息.key(),错误)
定义创建制作人(自我)->卡夫卡。制作人:
生产者属性={
“bootstrap.servers”:self.\u job\u queue.bootstrap\u server,
“error\u cb”:self.\u在\u error上,
“client.id”:self.\u job\u queue.client\u id,
}
返回卡夫卡制作人(**制作人财产)
def_uuwait_ufor_broker(self,retries:int,delay:float)->kafka.Producer:
重试\u计数=0
尽管如此:
self.\u错误\u事件.清除()
producer=self.\u创建\u producer()
#需要多次调用flush(),其间有一个延迟,以确保捕获错误。
如果不是self.\u错误\u事件。设置为()
对于范围内的(_NUM_ERROR_SCANS):
生产者齐平(0.1)
如果self.\u error\u event.is\u set():
打破
睡眠时间(0.1)
其他:
#成功:没有错误。
回报生产者
#如果我们到达这里,就会调用错误回调。
重试\u计数+=1
如果重试次数==0:
msg='({}').format(重试计数)
其他:
如果重试\u计数为无:
LOG.error('KafkaError:%s',error.str())
self.\u错误\u事件集()

您是否从同一docker容器运行Kafka代理?您使用的是哪一个Python Kafka库?我认为(我刚刚遇到这个问题,之前没有接触过该技术),Kafka代理位于同一个Docker容器中,我们正在使用Adobe Confluent Kafka库。这看起来很有用。我已经注册了一个错误回调(不是on_delivery回调),当product()后面跟着flush()时,会命中该回调。但是,如果代理可用,卡夫卡还会尝试添加消息吗?或者我可以假设请求需要重试。您如何注册错误回调?通常,错误或成功回调由库在成功地将消息发送到Kafka之后调用,或者在失败时放弃该消息之后调用(可能是在几次重试之后),并且我们的代码必须决定是否执行