近日基於項目的解耦與削峰需求,決定在項目中引入消息隊列。因為同時項目部分業務已經遷移到Java上,所以消息隊列組件又要兼顧Java環境下的使用,選來選去對比了RabbitMQ、RocketMQ和Kafka,最后還是決定使用Kafka。Kafka原是Linkin的日志收集組件,慢慢的已經發展成為了一個具有消息隊列/存儲/流處理功能的的高效組件,需基於Zookeeper使用。我們項目因Dubbox已經有現成的Zookeeper可供使用,同時又有日志收集的需求,所以就選它了。
選定了組件后,Java是親生兒子,組件的支持當然不在話下,而.Net環境下就有那么一點尷尬,沒有官方客戶端支持,只有幾個在github上的開源項目可供使用。如果你在幾個開源項目中一眼就看見了金光閃閃的Maintainer: Microsoft,那么十有八九你也入坑了。
CSHARPCLIENT-FOR-KAFKA
Microsoft提供的客戶端,這個開源項目文檔缺失、源代碼復雜且注釋少得可憐,連最基本的Producer和Consumer都不得不去把整個項目clone下來去看項目的Demo是怎么實現的。項目依賴.Net Framework 4.5,依賴ZookeeperNet,而ZookeeperNet組件依賴log4net,但是因為ZookeeperNet很久未更新,他依賴的log4net是使用oldkey的版本(<=1.2.10),而項目中原有的項目中有組件(Log4mongo)依賴的log4net版本是newkey的版本(>1.2.10)。編譯時會報這個錯 Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=692fbea5521e1304'
光折騰這個log4net的問題就花了大半天,最后還是把log4mongo的源碼作為項目引用,然后把整個項目的newkey的log4net引用全部改成了同版本號的oldkey的引用才可以編譯通過。 然而一切才剛剛開始,我這邊的情況是Zookeeper部屬在內網的一台測試機上ip地址192.168.1.123,而Producer和Consumer布在我的開發機上(ip:192.168.1.124)。 我跑Demo時按照下面這種寫法,居然報了一個UnableToConnectToHostException
,最后導入源碼才發現這貨將ip解析為機器名,然后通過機器名加端口去連……WTF! 當然,知道是什么原因后,改下host就解決了。
var brokerConfig = new BrokerConfiguration() { BrokerId = 0, Host = "192.168.1.123", Port = 9092 };
好不容易終於可以生產和消費了,但是我們是有集群需求的,看到布多台Consumer的實例代碼我又懵逼了。我就不貼出來了,有興趣的可以去感受下。
總之后來我跑起來了BalanceConsumer的示例。但是發現有時Producer產生的消息Consumer偶爾會接收不到,不知道我自己代碼寫錯了還是partition什么的沒配置好還是這個破Microsoft客戶端本來就有這個問題。總之我已然崩潰……手頭上又有別的事,決定先把這貨丟到一旁。
事情過了大半個月,再次准備死磕的時候發現有個issue有更新,說有用NodeJS客戶端封裝的解決方案,以及推薦了另外一個.Net客戶端rdkafka-dotnet。
RDKAFKA-DOTNET
rdkafka-dotnet是一個基於C++客戶端librdkafka的.Net客戶端,官方對librdkafka的介紹是
Robust high performance C/C++ library with full protocol support
總之就是健壯/高性能/全協議/全版本支持,可想而知基於librdkafka衍生的.Net客戶端也不會差。 筆者使用rdkafka-dotnet后,發現也會需要修改host文件,其他的Producer/Consumer的代碼都非常簡潔易懂,消費集群也非常容易配置,而且使用這個后根本就沒碰到過Consumer接收不到消息的情況。
想說的
其實Apache有和CSharpClient-for-Kafka一起列出rdkafka-dotnet,只是我被耀眼的Microsoft迷惑了,別的項目看都沒看,也是自己對kafka不了解才走這么多冤枉路,就當時間買個教訓了。以后多試多看多學吧!