sogou / workflow

C++ Parallel Computing and Asynchronous Networking Framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

在使用kafka库组件时,突然出现 state=67, errorno= 5003 的错误

zxyAcmen opened this issue · comments

#include "CKafkaConsumer.h"

#include

#include "workflow/KafkaDataTypes.h"
#include "workflow/KafkaMessage.h"
#include "workflow/KafkaResult.h"
#include "workflow/WFTaskFactory.h"
#include "workflow/WFFacilities.h"
#include "workflow/WFGlobal.h"

#include "sys_context/instancetemplate.hpp"
#include "CConvert.h"
#include "log/log.h"
#include "CHttpClient.h"

#include <boost/format.hpp>

#undef LOG_MOD_ID
#define LOG_MOD_ID ("tiis-consumer")

using namespace protocol;

static WFFacilities::WaitGroup wait_consumer_group(1);

CKafkaConsumer::CKafkaConsumer(/* args */) {

}

CKafkaConsumer::~CKafkaConsumer() {

}

void CKafkaConsumer::CommitCb(WFKafkaTask *task) {

int state = task->get_state();
int error = task->get_error();
if (state != WFT_STATE_SUCCESS) {
    LOG_ESYS("CommitCb", "kafka consumer commit failed state= %d error= %d msg= %s",
        state, error, WFGlobal::get_error_string(state, error)
    );
}
return;

}

void CKafkaConsumer::KafkaFetchCb(WFKafkaTask *task) {

SeriesWork *series = series_of(task);
int state = task->get_state();
int error = task->get_error();
bool wait = false;

if (state != WFT_STATE_SUCCESS) {
    wait = true;
    // 错误出现在这行,之前一直都是正常使用,实在不清楚是什么问题了。
    LOG_ESYS("CommitCb", "kafka consumer commit failed state= %d error= %d msg= %s",
        state, error, WFGlobal::get_error_string(state, error)
    );
} else {

    WFKafkaTask *commit = m_KafkaCli_.create_kafka_task("api=commit", m_Retry_,std::bind(&CKafkaConsumer::CommitCb,this, std::placeholders::_1));
    int api_type = task->get_api_type();
    assert(api_type == Kafka_Fetch);

    std::vector<std::vector<protocol::KafkaRecord *>> records_vec;
    std::vector<protocol::KafkaToppar *> toppars;

    protocol::KafkaResult *result = task->get_result();
    result->fetch_records(records_vec);

    bool isCommit = false;

    for (auto &records : records_vec) {
        for (auto &record : records) {
            const void *value;
            size_t value_len;
            const char *topic = record->get_topic();
            int partition = record->get_partition();
            long long offset = record->get_offset();
            record->get_value(&value, &value_len);

            // 这里消费到的数据是pcs服务写到kafka的,需要放到convert中转换一次,写通知到http客户端
            std::string tmpVal((char *)value, value_len);
            LOG_INFO("topic= %s partition= %d offset= %lld value_len= %zu value= %s strVal= %s",
                topic, partition, offset, value_len, value, tmpVal.c_str()
            );
            std::string httpData;
            // 消息转换
            InstanceTemplate<CConvert>::Instance()->UpMsgConvert(tmpVal, httpData);
            // 创建http客户端任务
            InstanceTemplate2<CHttpClient>::Instance()->Post(httpData);

            commit->add_commit_record(*record);
            isCommit = true;
        }
    }

    if (isCommit) {
        series->push_back(commit);
    }
}

if (m_Running_) {
    if (wait) {
        series->push_back(WFTaskFactory::create_timer_task(1000 * 1000, nullptr));
    }
    series->push_back(CreateFetchTask());
} else {
    series->push_back(m_KafkaCli_.create_leavegroup_task(0, nullptr));
}
return;

}

bool CKafkaConsumer::Init(const std::string &brokerAddr, const std::string &topic,
const std::string group, const std::string cliID, int startAt) {
if (brokerAddr.empty() || topic.empty()) {
LOG_ESYS(" ","broker or topic is empty pls check the param");
return false;
}
m_BrokerAddr_.assign(brokerAddr);
m_Topic_.assign(topic);
m_CliID_.assign("tiis_consumer_cli");

if (group.empty()) {
    m_Group_ = "tiis-consumer";
} else {    
    m_Group_.assign(group);
}

if (!cliID.empty()) {
    m_CliID_.assign(cliID);
}

m_OffsetTimestamp_ = KAFKA_TIMESTAMP_UNINIT;
if (startAt == 0) {
    m_OffsetTimestamp_ = KAFKA_TIMESTAMP_EARLIEST;
} else {
    m_OffsetTimestamp_ = KAFKA_TIMESTAMP_LATEST;
}

m_Retry_ = 2;

if (m_KafkaCli_.init(m_BrokerAddr_, m_Group_) != 0) {
    LOG_ESYS("CKafkaConsumer::Init","failed broker= %s group= %s", m_BrokerAddr_.c_str(), m_Group_.c_str());
    return false;
}

LOG_ISYS("CKafkaConsumer", "init success broker= %s group= %s", m_BrokerAddr_.c_str(), m_Group_.c_str());
return true;

}

bool CKafkaConsumer::Start() {
m_Running_ = true;
WFKafkaTask *task = CreateFetchTask(true);
SeriesWork *series = Workflow::create_series_work(task, [this](const SeriesWork *w) {
wait_consumer_group.done();
});
series->start();
return true;
}

bool CKafkaConsumer::Stop() {
m_Running_ = false;
wait_consumer_group.wait();
m_KafkaCli_.deinit();
LOG_INFO("---------------------------------CKafkaConsumer exit ---------------------------------");
return true;
}

WFKafkaTask *CKafkaConsumer::CreateFetchTask(bool first) {

std::string query;
WFKafkaTask *task;
protocol::KafkaConfig config;

query.append("api=fetch&topic=").append(m_Topic_);

config.set_client_id(m_CliID_.c_str());
config.set_fetch_max_bytes(512 * 1000);
config.set_fetch_timeout(100);

if (first && m_OffsetTimestamp_ != KAFKA_TIMESTAMP_UNINIT) {
    config.set_offset_timestamp(m_OffsetTimestamp_);
    config.set_offset_store(KAFKA_OFFSET_ASSIGN);
}

task = m_KafkaCli_.create_kafka_task(query, m_Retry_, [this](WFKafkaTask *task){
    this->KafkaFetchCb(task);
});
task->set_config(std::move(config));

return task;

}

这个是错误截图,请大佬们帮忙看看这样使用是不是有问题
image

67是任务错误,通过WFGlobal::get_error_string可以打出错误原因。

Kafka fetch api failed 这个就是错误原因输出

我们看一下。是持续出现,还是可恢复呢?

我刚刚看了下机器内存,没什么内存了,然后加了内存,现在又正常了,没加内存前,一直失败,不知道是不是这个情况,任务里是不是要使用到内存,如果可以的话错误信息可以加详细些,这样方便查,刚出来的时候一脸懵逼。

你是加了什么机器的内存?kafka broker吗?

workflow所在机器,和内存没有关系。只要程序没有崩溃,行为不应该有什么区别。

加的服务器本身的内存
7a3260db10e48dd77ad6a5e64c5d40c6

嗯嗯,现在大多数服务器没有打开虚拟内存,所以,如果出现内存耗尽的情况,一般直接OOM退出,不会提示内存用完。

我们的程序里没有直接挂,主要是因为我们检查了malloc的返回值,所以你可以得到一个错误。因为内存耗尽的情况程序用于提示错误的资源都没有了,所以这种情况下行为无法确定的。大多数应用程序都是直接崩溃。

如果内存小,可以通过减少handlers_threads和poller_threads,降低内存使用。

handlers_threads

这个在哪里设置呢,找了一下没有找到设置入口。

@zxyAcmen 可以看看这个文档哈:https://github.com/sogou/workflow/blob/master/docs/about-config.md
其他的基本用法也可以通过github搜索项目,很快就可以找到了

如果内存小,可以通过减少handlers_threads和poller_threads,降低内存使用。

运行了几天,好像又出现这个问题了,然后看了下内存使用了2.1个内存,导致没有内存可用。不知道是不是用法不对还是怎样,我是参考一个大佬提供的例子写的,实现不明白哪里有问题,程序里也没有用缓存和new动作。
D9)UWNJ_Z}$PS8D29G~8R 9

这个程序里总共会有三个组件的任务,http(c、s端), kafka(p/c端)和redis的任务,我单独运行redis相关的任务,观察的时候内存不会有变化,但是加上kafka的任务,内存就一直在涨。