搜狗于今年7月发布了C++异步调度服务器引擎——Workflow,除了计算通信融为一体的高性能特点以外,还集成了多种常用的网络协议,包括:Http、Redis、MySQL,所有协议都是纯自研自解析,无需依赖第三方库,而具体协议所对应的资源复用和线程调度等都由Workflow以统一的方式去进行管理,目前获得了越来越多开发者的青睐和肯定。而最近,Workflow又支持并发布了一项复杂的通用网络协议:Kafka,使得所有使用Workflow及其生态项目的开发者都可以通过统一而简便的方式与Kafka交互,这也是业内唯一一款使用C++语言实现的Kafka客户端,值引得开源社区开发者们的关注。
一、开发背景
在Workflow发布Kafka客户端之前,业内用得比较多的是librdkafka,但这个纯C的kafka客户端有许多不足,以下是我们原先使用时遇到的部分问题:
1、线程资源和网络资源消耗比较多
2、接口设计比较复杂臃肿,使用成本比较高
3、Kafka版本兼容性不是很好
4、消耗资源高,但是性能却不高
5、broker主从切换低版本出现服务hang住情况,高版本偶发丢数据问题
6、异步同步偶发出现丢数据情况
针对这些问题,更好的替代方案是Workflow的Kafka客户端:https://github.com/sogou/workflow
由于实现在Workflow的基础上,作为Kafka客户端即具有超高性能、超大吞吐和极省的资源占用等特点,且和其他协议的接口一样,此Kafka客户端还具有接口清晰,代码可读性强等优点,不仅节省机器成本还节省人力维护成本,非常值得一试。
二、新一代高性能C++ Kafka客户端
Workflow的Kafka客户端使用接口非常简洁,首先需要创建一个client对象:
其他使用方式与框架内的其他任务无异,使用Workflow的同学可以瞬间上手:
为什么Workflow的Kafka客户端能有以上的优点呢?主要得益于以下三方面的细节:
一. 内部基于Workflow的任务流实现。Workflow的核心设计理念是将任务抽象成"任务流"的概念,这样一个任意复杂的任务可以拆分成若干个并行任务流和串行任务流,它们之间通过串联、并联等方式组成一个或者多个串并联图,然后由Workflow内部的引擎高效异步地执行。
以Kafka协议的fetch消息为例,下图是执行过程中任务流的串并联图:
一个fetch消息的任务由一组任务组成,其中包括获取Kafka Broker的Meta任务、一系列的消费者组相关的任务、获取offset的任务和真正的拉取消息的任务。前面的多个任务由于有依赖关系,所以组成串联任务;而最终拉取消息的任务和Broker的个数有关,因此可以将它转换成一个broker数目相同的并行任务。这样做一方面可以使得逻辑很清晰,同时也可以保证执行的高效性。
二. 连接复用。传统的网络通信往往是在程序初始化的时候,创建大规模连接池来提高网络吞吐,这么做的一个弊端是系统资源占用过多,会导致降低程序的鲁棒性。而目前这个Kafka客户端由于内部是基于Workflow框架,Workflow对连接的管理做了很多优化,可以在保证高效高吞吐的同时,将资源控制在一个合理的范围内。
三.内存管理。为了方便用户的使用,内部的所有对象都基于计数实现,通过工厂方法创建任务后,在回调函数中实现处理逻辑即可。内存的分配和释放都是框架自动完成,全程无需手动操作任务级别的内存,非常方便;同时它的逻辑又是完备自洽的,保证了高效可靠。
三、插件式发布,与Workflow完美融合
基于Workflow精巧的层次结构,Kafka协议是以插件式发布的,即无需安装Kafka的用户不会把Kafka相关代码编译进去,由此可以看出Workflow本身的架构解耦和模块对称性都做得非常优秀。
而Kafka的协议由于需要多次交互,Workflow复合任务又天生支持内部交互的隐藏,使得整体使用上对用户非常简洁透明。基于二级工厂模式也可以把许多全局信息统一管理到内存中,也是工程上结合的一大亮点。
可以说,Kafka协议与Workflow的融合相当完美,且目前在搜狗已经大规模使用,经得住工业级检索系统大规模请求的实际考验,欢迎业内需要的开发同学积极尝试并与我们热心的开发小组进行技术交流。