qpid是一个伟大的软件,apache社区的顶级项目绝非徒有虚名。从2012年开始使用至今,在线上从未发生过事故,一直稳定运行。但从一个20年职业老鸟的角度来看源码的话,还是存在不少问题。一个直观的判断,qpid项目组应该是一群写java的程序员转行写c++代码,我在qpid项目源码中,看到太多java的编程技巧,或者他们是c++深度践行者。
一、源码结构问题
1、代码复杂高。qpid的功能强大,各种辅助功能繁多。在核心代码之外,使用多种依赖组件,导致编译难度增大。虽然qpid使用了cmake降低了编译时,环境配置问题,但组件的编译配置问题,同样也会引起qpid的编译困难。
2、模块化不清晰。在整个qpid-cpp代码中,源码的目录划分得很清晰,有sys,types,framing、client,messaging、broker、qmf这几块。但项目引用源文件时,交叉情况却很严重,这种情况可以从项目文件中可以看出来,这意味着模块化编写和测试时,会存在关联影响。特别是qpidcommon项目,简直是一个全家桶的项目。
3、嵌套层次过深。在面向对象的封装上,qpid项目可谓应用到极致。有两个技巧用得很频繁,一个是壳对象和Impl的分离,一个是接口和实现的分离。理论上,这并没有什么可以指摘的,但应用得太多,就会适得其反,以至于调用链过长,造成性能损失严重。
4、多重继承应用。和Java单根继承不同的是,C++支持多重继承。多重继承优劣就不在这里展开,在我的编程和项目管理实践中,一般不允许使用多重继续,即使是用空类接口也不允许,主要原因在于容易发生错误,而且不容易阅读。确保继承关系是树状单向,在逻辑上会简单很多,减少错误。
5、内存拷贝次数多。客户端的性能通常没有那么苛刻,但是对于总线来说,它的客户端实际上就是服务,那么对性能的要求就不一样了。qpid客户端在内存拷贝上,没有做太多的优化,从message到content到frame,再到最后发往网络,中间历经多次内存拷贝。这些也导致在整体性能上有较大的损失。
二、项目结构调整
1、项目简介。qpid-lite的项目地址:
https://github.com/QuarkCloud/qpid-lite.git ,这个项目目前只支持qpid的客户端。qpid-lite在出发点上,并不是为了优化性能,而是为了更好地研究qpid的实现,所以将非关键代码摒弃掉,紧紧围绕调用链,厘清各个模块、文件、类之间的关系。
2、项目结构。继承qpid的调用逻辑,将全家桶式的common拆分,同时去掉messaging项目,将原先的代码划分为,qpid-sys,qpid-types,qpid-framing,qpid-amqp,让每个项目之间有清晰的调用关系。而qpid-amqp0_10和qpid-amqp1_0两个项目,继承自qpid-amqp,是AMQP0-10和AMQP 1.0的实现。
3、其他项目说明。qpid-driver是从qpid-client继承而来,为
qpid-amqp0_10服务,同时删除不需要的文件。qpid-proton是来自于proton-core项目,因为qpid使用proton支持AMQP 1.0,由qpid-amqp1_0调用。
4、改造方法说明。
(1)、整理原始项目文件vxproj,将包含关系整理清楚,根据调用耦合度,将文件归类到自洽的项目中,特别是qpidcommon项目。
(2)、清理qpidmessaging和qpidclient,拆分成amqp0_10和amqp1_0两个项目,支持不同的协议。通过协议注册机制,由qpid-amqp管理。
(3)、通过上面两步,清理了文件的依赖关系,让他们分别耦合到各个项目中。在项目内部,跟踪调用关系,删除非关联文件,特别是qpid-client项目,qpid对amqp0_10的支持,主要通过qpid-client项目。
(4)、qpid-framing项目比较独立,基本没有改动。它主要定义的是amqp0_10的命令。
(5)、qpid-proton项目式纯c编写,支持amqp1_0,比较独立。没有动,只清理关联性不高的文件。