RocketMQ趟坑之旅

        在阿里云的官方文档里,RocketMQ被说的无比优秀,性能超群,运行可靠,使用便捷;RocketMQ本身是否有这么优秀姑且不论;但是RocketMQ对非Java语言的支持绝对是坑,非Java语言在RocketMQ的使用中,被阿里云技术工程师称之为“少语言”,包括C++和C#。官方提供的C++和C#的SDK只支持64位平台,且明确说不支持广播;这样一来由服务器向客户端PC广播消息的典型场景就被明显无视了。

      不过还好,现在RocketMQ不是开源了么,在apache的git上有RocketMQ的源码,里面也有一个开源的C++客户端SDK“rocketmq-cpp”,而且根据阿里云技术客服说,这个开源SDK是支持阿里云商业MQ的。这次趟的就是rocketmq-cpp的坑。

      首先来说说编译, git上rocketmq-cpp的编译说明写的很详细,可以参考https://github.com/apache/rocketmq-externals/blob/master/rocketmq-cpp/README.md

        但是按它的说明,反正在win10上,我是没编译出来。最后还是新建工程,把源文件加进去,配置路径和依赖库,这才成功编译。

        接着根据开源代码里的例子PushConsumer.cpp建了一个测试项目,能编译通过。但是开源SDK的接口参数和阿里云商用MQ的SDK接口参数完全对不上,简直就是“鸡同鸭讲”,rocketmq-cpp_manual_zh.docx里也同样没写清楚,没办法,先随便蒙一个看能不能运行。结果一运行,直接就打印了条错误提示出来:

   (error):create offset store dir:C:\Users\Lin/.rocketmq_offsets/2001:0:9d38:6ab8:2cdf:3a5d:3f57:9a87@DEFAULT/CID_JfSiteConsume error

好像是要创建一个带“:”的目录失败。不过这个目录名挺眼熟,查了下,果然是本机一块网卡的ipv6地址。好吧,根据错误提示找到bug语句,修改代码只使用ipv4地址。

         再次运行,这次正常了,但是测试程序收不到消息,阿里云控制台也看不到消费客户端在线。看来是接口参数没有蒙对。没辙,我只好再去找阿里云的技术客服。这次人品爆发,终于遇上个靠谱的客服,帮我联系到后端的开发者,问清楚了接口参数的含义。这下32位程序终于能在广播模式下收到消息了。

	DefaultMQPushConsumer consumer("CID_JfSiteConsume");
	consumer.setSessionCredentials("ak****", "sk****", "ALIYUN");
	consumer.setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET);
	consumer.setMessageModel(BROADCASTING);
	consumer.setConsumeThreadCount(1);
	//	consumer.setNamesrvAddr("http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet");

	//	consumer.setGroupName("CID_JfSiteConsume");
	consumer.setNamesrvDomain("http://onsaddr-internet.aliyun.com/rocketmq/nsaddr4client-internet");
	//	consumer.setInstanceName("CID_JfSiteConsume");
	MyMsgListener msglistener;
	consumer.registerMessageListener(&msglistener);
	consumer.subscribe("SiteInformMessage", "888");

	try
	{
		consumer.start();
	}
	catch (MQClientException &e)
	{
		std::cout << e << std::endl;
	}

	std::cout << "consumer started"<<std::endl;
	std::string str;
	std::cin >> str;

	consumer.shutdown();

         开始各种情况下的简单测试,突然发现不对啊,为什么每次启动测试程序都会把之前消费过的消息再消费一次,那以后客户端程序启动时岂不是要忙死了。再次联系阿里云的后端开发,日志加数据一通分析,后端开发告诉我说是windows下文件重命名失败导致的:

    if (rename(storefile_bak.c_str(), m_storeFile.c_str()) == -1)
      LOG_ERROR("could not rename bak file:%s", strerror(errno));
    m_offsetTable_tmp.clear();
  }

再次修改bug代码,历史消息重复消费的问题解决了。

        接着测试,然后在网络断开的情况下,测试程序直接崩溃了!!!第三次联系阿里云的后端开发;描述情况,上传日志,这次他告诉说linux下正常,windows没环境,要花点时间分析。有这点时间等他,我还是自力更生吧,看错误提示,感觉像是内存重复释放的问题,一路跟踪调试终于找到了bug点:

void TcpTransport::freeBufferEvent() {
  if (m_bufferEvent) {
    bufferevent_free(m_bufferEvent);
  }
  if (m_eventBase) {
    event_base_free(m_eventBase);
  }
}

发现是网络连接断开时会释放事件句柄,但是又没有对句柄置NULL,导致会出现重复释放的问题。修改bug代码,再次测试,问题解决了。

         目前为止,我还没有发现新的坑,忍不住要吐槽下阿里云的测试,是不是开源代码就不用测试啊,提交这样的代码不脸红么。郑重建议大家,如果涉及到C++或C#使用消息队列,还是绕过阿里云的RocketMQ吧,至少现在的支持实在太差。


编译rocketmq-cpp的vs2013工程和测试代码见下方链接,需要的朋友可以自行下载

https://download.csdn.net/download/skywoodsky/10313347

猜你喜欢

转载自blog.csdn.net/skywoodsky/article/details/79738836
今日推荐