声明
本文不涉及任何特定API,也不针对任何特定的厂商,但是仍然值得透露一点的是,某些加速板卡厂商的成功点和失败点恰恰都是在于其通用性,在这个人们依然依赖专业板卡的时代,依然将板卡视为解决专业化问题的时代,代理这些板卡并声称其能解决通用问题的厂商要慎重!虽然,我很看好通用化的板卡,可是我不是专家,即便我是专家,大家不是也总是攻击专家么?总之,矛盾的解决需要自己的判断力。
开始
如今出现了各种各样的PCIe加速板卡,这些板卡往往专注于处理一件事,从而释放CPU的越来越重的压力,当这种往通用计算机主板上插卡以实现某种处理加速的办法成为趋势的时候,SDN就更多变成一种纯粹的概念了。CTMD,这些概念老子都TMD知道,关键是如何用起来。
有一家代理商来到了公司,说他们的板卡多么猛,让我有了一点兴趣!其实我一直以来都希望有一款能用硬件处理数据包路由查找,包过滤的板卡或者设备,但是一直都没有如愿,我之所以好奇是因为我想明白Cisco是怎么做的,我想明白这些板卡是怎么设计的,无非就是一些门电路,怎么能组合成如此复杂的硬件算法呢?!事实上,门电路并不复杂,它完全遵循了UNIX的思想,或者说UNIX遵循了它的思想!当一系列门电路组合在一起的时候,就可以实现任何你想实现的东西,可以看下加法器的实现,比较简单。
在我的正文之前,我不得不说的就是社会化生产,时至今日,不管再简单的东西,我们靠个人都无法完成,我如果要想油炸一个狮子头,我必须浪费掉一锅油,我认为这个事情不值得,所以我选择买。这就会社会分工,各行其是,各司其职!我和厨师之间的接口就是货币,我把钱给他,他把狮子头给我(货币真是个好东西,替代了物物交换,使任何价值的任意交换成为了可能),当然我没有考虑饭店老板,忽略了他们是因为我看不起他们。MD,我现在发现我连闺女的一个小玩具桶都做不好了,要想当年,我爸可是给我做了一个玩具桶啊...我爸还做了一个盒子,精致至极,现在还留着,虽然不是奢侈品,但是我觉得他那个年代的人,从木工,到定型,都是他一个人做的,我很崇拜!但是现在不行了,如果你想要做出一个哪怕再简单不过的东西,你都需要一套完整的设备...完整的设备对于个人来讲负担太大了,就是说,社会化生长时期,一切都要靠分工。这不正是UNIX的思想么?
做且仅做好一件事,这是一个伟大的思想。它造就了一种可能,即通过一个交换媒介,可以将简单的小元素组合出任意复杂的东西,这个交换媒介就是设计。RISC处理器是一个微观上的代表,而超多核心架构则是一个宏观上的代表,控制面和数据面的分离则是另一个代表。
OS内核软件架构开销
单核心时代在内核实现协议栈不会暴露什么问题,不管是用户态程序还是内核代码,都共享一个执行流,如果频繁切换反而会带来切换本身的开销,因此内核往往代理许多事务。但是到了多核时代,内核就应该尽可能地放权,仅仅作为一个管理员存在,更多的事务交给用户态。用户态可以自由且方便地将不同的任务绑定到不同的核心,让这些核心专注且发疯地干活,不再受到内核事务的干预,比如任意的中断导致的内核抢占、线程切换、处理器之间进程迁移,定时器等内核任务带来的开销。
多核心时代的OS内核
有一段时间,我是多么地欣赏Linux内核的进程在处理器核心间的负载均衡机制,多么欣赏诸多的所谓启发式智能化进程调度机制,但是现在,我走向了相反的方向,其实,那些机制确实很智能,比如给睡眠太久的进程多一些执行的机会,比如按照历史权值平滑地进行进程迁移,等等这些。实际上引入这种智能正是因为内核认为用户态进程不会也没有能力在多核心架构这种舞台上进行完美的表演,又一次,内核代理了这些本应该由用户态进程自己负责的事务。事实上,一直以来,内核始终保留了一个接口,该接口可以禁止掉内核对用户态进程的种种干预,比如你可以将进程强行绑定在一个核心上。
按照UNIX最初的思想,内核就是一个控制面,数据面由用户态构成。但是处理器的架构让这个思想成了幻想。
最初,系统只有一个处理器核心,不得不设计出分时系统以便多个任务包括操作系统内核本身可以共享一个执行流。这种内核和应用程序对等化的扩展改变了人们的思想,从而几乎所有的通用操作系统都继承了这个思想。那就是不再刻意区分什么数据面和控制面,人们的视线转移到了哪里呢?操作系统的核心任务转移到了如何提高分时系统的效率的同时在所有进程包括内核本身之间做到(加权)公平调度,而这些,用户态根本不用管。最终,被惯坏了的用户空间导致内核中一系列的智能算法出现,事实上,这些算法的依据都是内核基于能获取的不多的进程状态猜测的,内核永远也不会知道进程的本意到底是什么。这就导致了一些误解出现的可能,比如内核文档说开启一个选项会提高性能,结果反而令人尴尬地降低了性能...
本小节的标题是“多核心时代的OS内核”,但是到此为止我都还没有提到这个新时代的OS内核到底应该是什么样子的,但是借古看今知未来,我想理解了上面那段历史以及其带来的悲哀后,新时代的OS内核是什么样子应该有一个大致的轮廓了。
首先,内核没有必要和用户程序共处一个分时系统了,当然如果你愿意,你依然可以让它们共处。实际上虚拟化就是这方面的体现,一个多核心系统上跑多个OS内核...对于核心的利用,内核要给用户态更多的控制权。我们思考一下计算机编程的本质,就是对CPU的编程,让它执行我们的程序,而不是针对OS内核提供的系统调用接口的编程。此时,OS内核需要做得仅仅就是处理好共享资源的管理和分配即可,当时间在多核心下已经不再是共享资源的时候,它就应该放弃这部分的管理权,除非当一个核心上存在多个进程共处一个分时系统的时候,或者说有进程主动要求的时候,它才需要介入。这就提供了一个可能,在某一个核心或者某几个核心上取消分时,专注于一个工作。这也预示了一个趋势,那就是超多核系统架构,按照逻辑分配处理器核心,而不是按照进程来分配处理器核心。前后接力,这就可能完全避免切换以及切换导致的一系列开销。
硬件架构的开销
传统意义上,非片上完成的操作总是需要一条将所有一切连接起来的总线,往往这条总线就是瓶颈!Intel的架构使这一风格变的流行,曾经有人在比拼自己的电脑的性能时,前端总线的带宽是一个硬性指标,后来AMD在兼容IA32的前提下改变了这个事实,但是还是不彻底。如果使用片上存储器将会解决这一问题,但是受限于工艺技术以及冷却因素,片上存储器一般都不会很大,但是即便是不使用片上存储器也还是有办法的,那就是改变处理器核心和存储器之间的连接方式,使用矩阵的连接方式替换总线方式。实际上,极端点说,多核心时代,总线的存在就是一个错误。换句话说,总线是单核心时代的遗物。
PCIe总线似乎开了一个好头,软化了硬总线,将总线拓扑事实上变成了基于HUB的星型拓扑,重复了以太网的进化模式,也许只有当初的交换式以太网可以与其媲美。但是,PCIe本质上还是为了互联外围设备的,并不适合处理器和内存之间的连接,但是它的思想却是可以借鉴的。那就是改变拓扑,从而,全互联拓扑,矩阵拓扑代等交换结构替了总线拓扑。只要总线变成交换式的,那么“总线”也就成了一个名称,像CSMA/CD变成文物一样,昔日的前端总线上跑的各种协议也将不复存在。
新架构上的协议栈
协议栈属于数据面,因此正确的做法就是用户态的协议栈,利用多核心分发执行流,比如一组核心专门处理链路层转发,一组核心专门负责ACL匹配,一组核心专门负责包分类...完全没有切换,这使所有的cache都是新鲜可用的,矩阵连接方式使每一个核心都能快速访问到不同的内存区域,减少了总线竞争和被迫等待。
网络数据被网卡接收以后,应该放到用户态的一个buffer,如果你觉得这不是和内核没有关系了吗?不!网卡是靠驱动接收数据的,而驱动是OS内核直接管理的,也就是说,从网卡芯片接收的动作是发生在内核态的,只是内核随即就把这个数据包放到了用户态,并没有在内核协议栈处理它。类似的思想也被用在了磁盘操作的Direct IO中,即内核不再保留缓冲,完全由用户态自己负责。
关于协处理器
我本人是不看好协处理器的,因为它是对通用计算的一种反叛,部分或者彻底抵消了编程带来的方便性灵活性以及经济利益,比如最开始的ASIC转发芯片,将指令完全固化在硬件,后来的协处理器增加了灵活性,使之变成可编程的,但是能完成的功能毕竟有限,不过正如你所看到的,事情正在一步步走向通用化。上世纪的CPU+编程取代了各种专用设备,当这种架构变成瓶颈的时候,专用设备又出现了,比如上面提到的ASIC,各种加密卡,协处理器之类,然而由于GPU和各种超多核心处理器的实现,更高层次的向通用化的统一进程正在进行中。
目前的路由卡上所谓的智能芯片其实就很专业化,也就是说它并没有通用处理能力,典型的路由芯片用普通的比较器,移位寄存器,选择器,复用器就可以完成,只要懂点计算机组成原理的可以说都可以设计出一个简单,如果你想看下其软件原理,那就看下Linux的TRIE路由查找算法的实现,或者看一下BSD的路由查找算法,它们都比纯硬件实现复杂了不少,但是基本思想却是一致的。如果想提高性能,可以采用并行的CAM匹配。虽然大大加快了路由查找效率,但是随着通用处理器架构越来越扁平化(低主频,低功耗,多核心),我想专用芯片的神话快要被打破了吧。
新架构和传统架构的交互
新的超多核心架构目前更多是以板卡的形式存在,更多地采用PCIe的方式插在传统架构设备的主板PCIe槽中,造成这种局面的原因除了传统主板的既有投资等经济因素之外,另外的原因在于大多数的这些新架构板卡都带有一定的专用性,比如GPU,Intel千兆/万兆卡,cavium加密卡,Tilera Gx处理卡,我个人对GPU和最后一个Tilera处理卡比较看好。
如果以板卡的形式存在,受既有投资和传统思维的影响,主程序还是跑在老架构上,这就不可避免地要和主设备进行交互, 我认为,这种办法是极其不妥的,传统大而全的帝国式OS内核,传统拥堵不堪的主板总线,传统单核思想下设计的应用程序都将成为瓶颈和累赘。为何不直接将程序扔在板卡上呢?如果这样,就涉及到板卡上的工作由谁充当控制面的问题,当然是由新架构时代的OS内核了。也就是说,板卡上跑着一个超级轻量级的OS内核,该内核最大限度的放权给用户态应用,不处理协议栈,只提供共享资源的管理和调度。Tilera Gx处理卡提供了这种方式。这样,PCIe就不再是数据面意义上的接口了,更多地充当了管理面的接口,这样管理面由老架构主机提供,控制面由板卡OS内核提供,数据面由板卡用户态提供,如果不需要管理,极端点说,PCIe完全就是一个供电接口。
要澄清的一点是,很多人使用加速板卡的目的是弥补主板处理器主频和功耗而带来的不足,他们的着眼点还是主板,而认识不到传统意义的主板上的系统只是一个管理平面而已。他们的需求促使PCIe带宽不断的提升,最终PCIe也会吃不消的,总的来讲,大多数的人只是将这些板卡用于加速而已,并没有将数据面让其完整接管的意思,这实际上是一个错误的思想。这个思想的本质是单一通路思想,人们自古以来就一直在拒绝无边界的东西,于是有了各种门和口,比如古代的城门,现在的绕城高速出口等,如果循着这个思想,这些门或者口随着流量的增加早晚会成为瓶颈,于是打破这些门或者口才是正确的思想。干吗非要主板和板卡协作,直接全部交给板卡岂不更好?!
关于核心网络技术
事实上,类似Cisco这类厂商在很早的时候就已经采用这种新架构的思想了,只是说核心网络业务一般都比较单一,不外乎路由,交换,防火墙等,因此这种模式也就没有被推广。只是在进入后终端虚拟化时代之后,数据中心这种资源子网的压力不断增加,才迫使服务器已经采用或者将要采用分离了数据面,控制面,管理面的混合架构。如果在这种分离的思想上更进一步,那就是SDN了,而SDN正是传统核心网络技术和云时代的数据中心技术共同催生的。SDN在平面分离思想之外,额外加入了在管理面上集中化的思想,就像一个线扎一样,它提供了一个统一的视图。每一种网络技术都有过这样的过程。
本来并没有路,走的人多了也就有了路,这些路起初是无人管理的,但是最终却有了人集中管理,路网时至今日都是这么发展的,不管是古罗马的道路网还是中国的铁路网。电话网何尝不是这样,如果你看到19世纪末的电线杆,你会发现它们是多么得乱,可是现在你还觉得乱吗?可以说,整个人类文明就是一个结网的过程,该过程中不断重复着分布和集中,融合和分离,而主角就是,数据面,控制面,管理面。
最后说说SDN,它并非想象的那么简单,可能需要一点颠覆性的思维才能更好的理解。要记住的是,如今的网络都是分布式控制的,这是一个正常的技术演化过程导致的必然结果,也是历史发展的必然。总体来讲,这是分层协议模型的必然,在这个模型中,网络分为承载网和叠加网,即叠加网作为承载网的载荷运行,任何一层都可以做承载网,任何一个层都可以做叠加网,比如X over Y,分为以下三种模式:
1.典型的按照协议栈顺序封装的,如UDP over IP,HTTP over TCP,IP over Ether;
2.常见到不典型的上层封装下层的,如PPPoE,IPoATM...OpenVPN本质上也是基于这个模型的,它属于IP/Ether over UDP/TCP;
3.任意两层之间加入新层的,如IPsec的ESP/AH,SSL/TLS。
可是SDN打破了所有这一切。SDN的世界,数据完全依照流表的建议转发,而流表的建立完全和数据的转发分离,换句话说,即使没有分层协议栈,只需要告诉一个数据包该从设备的哪个端口发送出去,就能完成数据包的路由,也就是说,协议栈的处理大大减少了层层解析包头协议头的工作量,只是匹配流表就可以了,就算你自己定义一个非TCP/IP的协议,只要能建立流表,就能将其转发!而流表的建立,根本和具体协议无关,它是一套独立的协议!因此,想当然的,极端一点,你可以将分层协议彻底转移到控制面,而在数据面完全抛弃分层协议...
总结
看看新架构板卡所呈现的,看看现实中我们遇到的。因此,SDN并不是什么新的思想,而是一个古老的思想,从UNIX出生的年代开始,我们绕了一圈,最终又回到了UNIX的思想。
令人无限遐想的各种PCIe加速板卡,布布扣,bubuko.com