--- 摄于 2017 年 9 月 藏川线前段
自学习编程以来,一直与网络编程缘分不浅,从最初的 Python 小爬虫项目,Django Web 项目,到 Rust 的 Influxdb client 项目,blog 项目,再到最近的 cita-cli 项目。以上项目都是基于 http 协议构建,从七层/四层网络协议模型上来看,http 属于应用层协议,它架设在 TCP 协议之上,一次 http 通信是一次很短的无状态连接,每次通信结束就直接断开连接,而 TCP 连接属于长连接,只要我们在使用 TCP 连接时不主动断开,那么它的连接会一直存在。
本以为作为菜鸟的我,了解网络协议到特性级别就够使用了,毕竟不是每个人都需要对协议中每个字段的长度、意义等都了然于胸,才能正确得写出基于协议之上的应用程序。在 influxdb client 项目中接触到了解析文本协议的一点东西,可以看成是基于 http 之上的自定义文本协议,到这,稍微了解了一点点关于协议具体内容的案例,直到去年,在参与 CITA 项目的过程中,接触到 Bitcoin 的 peer to peer 网络协议,才慢慢了解到作为互联网时代的网络协议,下面的玄机如此之深,然而,天真如我还是低估了里面的门道,只能说,如果不自己亲手完全实现一遍,永远无法知道里面的小坑到底有多少。
从去年 10 月开始,因为工作原因,开始接触 libp2p 协议,花了点时间看代码,发现由于代码是顺着概念实现的,而概念太多导致看不懂,又回过头去把 libp2p spec 刷了一遍,了解了 swarm、mutiladdr 等概念之后,回过头来继续看代码,大致能理解了,随后开始尝试使用该库(rust-libp2p),由于当时的库中缺少文档和示例,摸索与提问并行之下,好不容易搭建了一个 demo 可以跑起来通信了,正当我欢天喜地得将 demo 封装成库,移植到 CITA 中时,碰到了一些神奇的问题,在尝试自己解决失败,求助也失败的情况下,与组内多人讨论了不下一月的时间,议题就一个:“我们是否需要自己实现 P2P 网络?”
好处是显而易见的,如果出现问题,响应时间会极快,不会因为底层实现的复杂而打断项目进度,坏处也是显而易见的,我们是否有能力实现一个稳定高效的网络库,让它测试完善,并且功能与 rust-libp2p 的实现类似,易于扩展?同时如果真的实现出来了,时间成本、人工成本是否可控,如果实现了一年完成了第一个稳定版,那就没有什么意义了。终于在 11 月的时候,我们艰难地决定重新实现一个 P2P 网络库作为我们项目的网络依赖。平心而论,如果社区有稳定好用的库,我是不会再重复造轮子的,因为在正式环境使用久经考验的库毕竟会放心不少,哪怕底层的具体实现不了解。
一如既往,我选择 stable 版本作为稳定性的保证,然而这就意味着我拒绝了基于 nightly 的各种好用的新特性,比如心心念念的 async 语法糖等。好消息是 TheWarWar 同学已经将 yamux 协议开发得差不多了,虽然后期修了不少问题,但是在 11 月的时候,有个多路复用协议作为打底,心里着实踏实不少。当时,哪怕有 yamux 协议打底,我心里预计,第一个 demo 实现也需要一个月时间,因为菜所以怂。
先看过一遍 yamux 实现,提交几个 fix commit 之后,开始思索,一个能够挂载多种自定义协议 P2P 网络库,到底应该怎么去实现,从看过的 libp2p spec, 到看过的 rust-libp2p 实现代码,再到使用 tokio 的各种实战经历,再到 yamux 的实现、go-libp2p 的实现。思考了一周左右,单纯的思考,没有写一行代码,主要有几个问题:
暂时想通了上面几个问题之后,花了一周写了第一版 demo 的实现(真正关于内部实现的问题,本次就不涉及了,后面的文章再详细说明)。比预计时间少了很多,非常惊喜,虽然在后面写测试的时候发现,确实存在不少 bug,边界条件没有考虑的问题,但是这些都不重要,重要的是,我发现,这东西比我想象中容易不少,突然就有信心继续完成这个库了。
代码仓库:https://github.com/driftluo/p2p 或者 https://github.com/nervosnetwork/p2p
目前,各种功能测试加上了不少,加上协议本身的测试,以及我们内部也在尝试切换,也做了不少上层的测试,但是,我觉得还是不够。我现在比较担心的并不是功能上的 bug,我担心的是 poll 的调度问题,会不会存在调度不均匀的可能,虽然从目前的实现上来看,我对每次 poll 中 loop 的上限做了限制,哪怕其中一个协议的消息过于繁重,也不会导致陷入某个 loop 出不来,但是,这是在推导,并没有真正对多个任务繁重的协议进行真实的测试。这里实际上也是一个优化点,将 future 再次拆小,让小任务独立出去运行,让 tokio 的 work-steal 任务池去调度小任务。
特性来看,至少第一个小版本的特性算是差不多要冻结了,目前只支持 TCP 协议,后续应该会将其扩展到更多的底层协议,加密层也只支持一种加密算法。
我们期望当最简单的第一个版本稳定之后,再考虑扩展的问题,对于加密算法的扩展,本身就预留了可能性,而对于底层协议,目前我有一个模糊想法,大概需要增加两个 Trait 去实现,在我的想法里,这个扩展对当前 API 应该不存在破坏式的更改,这个留待以后实现。
大概很快,0.1 版本就会正式发布到 crate.io 上,如果有朋友对这个库有兴趣,欢迎 PR,欢迎提意见。
不错,你们的感觉很到位,这篇没什么干货,纯属在漫谈,理一下开发过程中的小情绪,压力与成就感同在,真实的开发体验。后面的篇幅应该会重点在于内部各个小库的实现,这篇就当预告。
请登录后评论
评论区
加载更多