我的开源经历
开源并不是多么牛逼事情,至少在我今天看来是这样的。
为什么还值得拿出来一说,是因为没有参与其中的人都只看到了开源的结果,而完全不了解产生的过程。 这其中发生哪些有趣事情,又是怎样的机缘巧合,一切的细节是值得耐人寻味的。
hs4j-kit
2010年有个名为HandlerSocket-Plugin-for-MySQL1的开源项目,它号称可以将 MySQL
打造成一个高性能的 NoSQL
服务,提供超过750,000 qps
访问能力2,这一下触及到了不少热衷于性能的技术人的G
点。
在随后非常短的时间里,这些人跃跃欲试于自己的工作环境中,并孵化出了不少衍生的开源项目。其中有一个就是hs4j3 ,它提供了支持Java语言使用HandlerSocket的API。
当时,我的主要工作是在为 HDFS 的 NameNode HA 的方案,而 hs4j 恰好能为这个方案提供一种高可靠且高性能存储的可能。在使用的过程,我发现 hs4j 提供的接口用起来就像 JDBC 的一样繁复啰嗦,由此萌发一个思路:用类似 ORM 方式简化编码实现。然后我就写了 hs4j-kit4,并联系原作者5表达了希望贡献给hs4j的意愿,他看过代码后非常乐意接收,只是提了一个小小的要求:提供一份README。
iPage
2011年我从淘宝数据平台转岗到淘宝中间件,由于我此前有开发消息中间件的经验6,因此在新的岗位上,我有一个很重要的使命就是优化另一个历史悠久的消息中间件Notify7。
Notify的架构设计简单巧妙,即将一张存放消息的表作为消息队列的实现。这样的方案有两点好处:
- 利用数据库可靠性和扩展性,大大降低中间件的开发难度
- 消息是存储于数据库的,中间件几乎是无状态的,很容易水平扩展以支撑海量的吞吐请求
+-- Producer --+
| |
+--------------+
V
+--- Notify ---+ +-- MySQL ---+
| [Queue] | <-> | [Table] |
+--------------+ +------------+
V
+-- Consumer --+
| |
+--------------+
消息中间件最重要的使命是缓解依赖系统间响应能力不匹配的问题,因此,面对消息堆积的容忍程度是消息中间件最为关键的考量指标。Notify这一指标完全要仰仗于MySQL的表现,这样的表现力要支撑双118,需要上百台数据库实例。
为什么不能像Kafka9使用文件系统实现队列呢?这样的话,不仅能够节省好多服务器,还能减少其中的网络开销。其实我不是第一个这样想的人,在我之前已经有人尝试实现并开源了,叫store4j10,只是可靠性远不如数据库的实现,而仅限开发测试环境使用。
在看过store4j的源码后,发现内存索引需要在每次启动时扫描消息队列进行重建。这在大量消息堆积后系统意外重启时,索引重建的过程就会变得很漫长。尽管这类情况平时几乎不太可能出现,可大促活动期间出现的几率立马提升,而且是一旦出现对整个服务链路几乎是致命的。
任何系统都有它的容量极限,超出之后我们是无能为力的。比较妥当的解决办法是:
- 根据业务场景评估容量规模,
- 单机濒临容量极限时,应能自我保护,重定向部分请求至另外的节点,保持自身的最低服务能力。
因此,改善索引重建速度是我认为值得去做的一件事情。与hs4j不同的是,我并未基于store4j源码改进,而是另起炉灶实现了iPage11,原因是改进索引重建速度的设计方案12对原有的代码改动很大,不如重新实现来得容易。
iPage算是我第一个自己发起的开源项目,不仅提供简明扼要的README,还增加了设计文档13,测试用例14,开源协议声明15。
最终iPage凭借突出的性能数据取代了store4j ,但遗憾的是没能取代MySQL成为生产环境的存储实现。
HouseMD
iPage虽未能善终,但来自github上其他程序员的关注,鼓励着我继续前行,才有了后来的HouseMD16。
与此前项目不同,HouseMD是个可运行的实用工具,为此README尤其强调安装17和使用的指引。
酒香也怕巷子深啊,刚发到Github上是无人问津的,但我自信这样工具能够也应该帮助更多的程序员。随后我试着为HouseMD创造一些曝光机会,先是去开源中国发布项目18,而后上Weibo寻求转发19。
随着关注人多了,部分友人也有参与贡献之意,为了方便他们我又专门写了开发指南20,涉及:
- 代码获取
- 编译构建
- IDE 支持
- 贡献建议
- 参考示例
当然这里肯定少不了测试用例21,这次我采用Spec风格实现,让测试代码写的更像是文档。
那时Scala还没有像Spark这样的杀手级应用,了解并掌握这门语言的国内程序员凤毛麟角,故真正有深度的贡献我最终没能等到。不过令我欣慰的是,一个名叫Grey anatomy22项目出现了,它用 Java 实现了HouseMD大部分功能,还额外增加了更多强大的能力。去年,在HouseMD发布三年后,我便在README中声明不再维护,并推荐Grey anatomy作为更好代替者,也是希望它能比HouseMD走的更远。
HouseMD之后,我只有零星一些实验性质的项目放在Github,活跃度不高。
2014年的最后一天,我被领进了挖财在福地的办公区,与刚刚开完会的李治国寒暄了一句,就被领到工位上码代码了,代码了,码了…
config-annotation
我在参与到信贷系统研发之后,孵化出了新的开源项目config-annotation23,关于它的由来与实现细节可见2015年6月我在华东区 Scala 爱好者聚会上的分享24。
为什么config-annotation值得拿来一说呢?尽管它的Star和 Fork数量都不值得一提,但相比HouseMD,它让我对开源文化有了更进一步的理解。
公开你的源代码只是开源的第一步,真正能够爆发无限可能的是与世界上其他的程序员自由协作,相互贡献
这里我做了几件事:
这些都是为了让config-annotation真正融入到开源的世界里,使得任何一个网络能够触达的程序员都能很容易的了解它,使用它,改进它。最终我等来了第一个给我的Pull Request28!
结尾
看到这里, 我相信你会意识到,原来让你高山仰止的开源,其实和你每天的工作没有太大的区别。事实上,我发现不少优秀的程序员参与开源已经成为他们工作的一部分,而并未有明确的界限。
回顾来看,参与开源的过程一直在潜移默化的改变我自己的工作方式,了解我的人应该都看在了眼里:
- 我喜欢用issue按排工作,跟踪进展,追溯变更;
- 我喜欢用README帮助团队快速上手项目,降低沟通成本;
- 我喜欢用Pull Request与同事协作开发,分享设计中心得,讨论Bug上的经验。
言以至此,对于开源是什么,我由衷地希望看到这里的你能够与我感同身受,Let’s Do It!
Using MySQL as a NoSQL- A story for exceeding 750,000qps on a commodity server↩︎
https://github.com/zhongl/hs4j/tree/master/contributes/hs4j-kit↩︎
killme2008,后来我们有幸成了同事。↩︎
TimeTunnel2是我在数据平台开发的消息中间件的第二代,应用场景和Kafka一样。可惜的是,在我完成上线的几个月后它才开源。感谢前同事,你还能在https://github.com/huolong/timetunnel看到它。↩︎
2007年淘宝在调研了业界消息中间件发现没有合适之后,自研的一套系统,它是当时整个淘宝架构体系中最核心的中间件。最初编写者是前淘宝中间件负责人,后任蘑菇街技术副总裁曾宪杰(花名华黎)。↩︎
双11期间,淘宝的交易核心系统是必须保证足够的响应能力的,但像积分,红包,推荐等非业务核心系统几乎都要降级掉,那么连接核心与非核心系统的Notify将可能出现十几亿甚至上百亿消息的堆积。↩︎
https://code.google.com/archive/p/store4j/,作者是前淘宝首席架构师,蘑菇街联合创始人岳旭强(花名黄裳)↩︎
LevelDB是同时期类似设计的一款优秀实现。它是Google出品,尽管有好事者把它 Port 到了 Java 上,但在好奇心的驱使下,我并未直接拿来用,而是在实现 iPage时借鉴一些它设计理念。↩︎
https://github.com/zhongl/iPage/blob/master/src/test/java/com/github/zhongl/api/IPageTest.java↩︎
https://github.com/csug/housemd。有心的朋友可能注意到了HouseMD项目是挂在在CSUG下面,而不是zhongl下,这里有个小插曲。那段时间,因为Scala我先后结识了扶墙老师和 宏江,不久厚颜无耻在Github上创建了CSUG(China Scala User Group)这个(非官方)组织,为了不让主页空荡荡的,于是乎相继把自己的项目贡献到了CSUG下。↩︎
5天之后Github上项目的被Star的数量超过100,成为Scala语言类项目Top1。 此外,killme2008的一篇利用HouseMD诊断Clojure,也助力不少。↩︎
https://github.com/CSUG/HouseMD/tree/master/src/test/scala/com/github/zhongl/housemd/command↩︎
https://github.com/CSUG/csug/blob/master/shanghai-2015-06-06/configuration_meets_scala_macro.pdf↩︎
https://central.sonatype.com/artifact/com.wacai/config-annotation_2.13↩︎