标签:单元 物理内存 条目 效率 原理 过滤 程序 计算 处理
推而广之。协议栈的路由表就是为了查找而生,且不说Cisco的Express Forward(CEF体系),单说路由cache就够了。
早期的Linux(迄至2.6.39以往。不谈3.X),在系统路由表至上又构建了一个路由cache,每个cache表项都是一次成功的路由查询结果,内置一个超时过期时间。Linux路由cache设计的前提是:去往一个目标地址的数据包会连续到来。
这也是局部性原理的一种推广。可是和内存訪问以及单一目的地的移民浪潮不同,Linux作为一台路由器并非为一个数据流服务的,而Linux的路由cache中保存的是SourceIP/DestinationIP值对,因此一条路由表中的项将会扩展出N条路由cache项:
1.1.1.0/24-192.168.1.254==>{(2.2.2.1,1.1.1.1,192.168.1.254),(2.2.2.2,1.1.1.1,192.168.1.254),(2.2.2.3,1.1.1.2,192.168.1.254),(2.2.2.3,1.1.1.10,192.168.1.254)...}
假设同一时候过境的基于源IP/目标IP的二元组数据巨大的话(特别是在骨干路由器场景下),路由cache的数目将远远超过路由表项的数目,我在想。路由cache相较于路由表的查询优势体如今哪里呢?难道会有如此高效的路由cache查询算法吗?假设有的话,为何不直接应用于最长前缀匹配的路由表查找呢?非常明白的是,路由表查找远远没有路由cache查找更严格。
路由cache的思想是好的,可是确实不适合软件实现,假设有TCAM硬件的话,也许能够实现并行的多维向量精确匹配,但对于软件实现,因为协议栈天生的多CPU核心利用的弊端,最高效的做法就是分级hash了,而即便是最高效的多级hash实现也不是免费的午餐。假设考虑到异常流量。非常easy将你的路由cache表撑到爆,比方构造海量不同的源IP地址訪问不同的目标IP地址就可以。
TCAM的原理就不讲了,网上资料多的是。
可是Linux似乎没有这么做。
屡次想优化nf_conntrack的查找性能,但总是受制于以下一个理想。即“理想情况下。conntrack的查找只须要做一次hash计算。然后遍历一个元素或者个位数个元素的链表”,假设实现了这个理想。还用费劲优化吗?我假设冲突链表的平均元素个数为10。那么只要10000个hash桶,就能容纳10*10000个连接,效率已经非常高了。可是理想毕竟不过理想。hash值计算的输入是五元组,算法是固定的。因此假设这个hash算法不够好的话,计算结果的散列程度和输入是高度相关的,理论和事实均证明。涉及到查找的hash算法都无法做到理想情况,要想使得hash的输出和输入无关,就要採用对称密钥学中的操作概念:置换,替换,混淆,扩散等,能够參考一下DES/AES的操作步骤,就能够看到这依旧不是一顿免费的午餐!
hash查找须要的是高效,假设一个算法针对输入的散列程度已经足够好了。那就到此为止了。假设散列程度非常不好。那么冲突链表的长度就会有的特别长有的特别短,这对于一个公平调度系统,对性能的影响是非常大的。
我希望使用纯软件来优化转发效率。
记住一件事是重要的,那就是:你不能将总体的每个部分的性能都提升,正如永动机不可能一样,你必须将不重要的部分能力倾注到须要优化的部分。
优化的基准就是,区分一个高速路经和慢速路径。首先查找高速路经,若失败则进入慢速路径查询。同一时候将结果添加高速路经。高速路经非常快,前提是它是排它的,容量小且有限的,就像罗马共和国时期的公民权一样。是要靠奋斗而取得的,到了卡拉卡拉时期。公民权成了既得权,优势自然就没了。使用Bloom能够做到传统路由cache的高效替代方案。
对每个下一跳维护一个固定大小(可是执行期能够动态调整)的Bloom过滤器,数据包到来,首先遍历全部下一跳的Bloom过滤器,结果无非有三种:
a.唯独一个Bloom过滤器返回值为1;
b.有多个Bloom过滤器的返回值为1。
c.没有一个Bloom过滤器的返回值为1;
对于a而言,直接发往那个下一跳就可以。对于b而言,说明存在False Positive。此时说明凡是返回1的Bloom过滤器都有可能指示正确的结果,要么退回慢速路径,要么在全部可能的结果之间广播,对于c而言。此时必须退回到慢速路径。
请注意,我们当然希望结果是a。此时的计算非常之快,N个hash计算就可以,至于计算方式,能够在一个处理器串行,也能够多个处理器并行。
对于Bloom过滤器而言。为了方便删除元素,故使用带有counter的int型占位而不是不过一个表示0和1的bit位。为了防止导致False Positive的结果一直会False Positive,全部的Bloom过滤器在内存中都要有一个后备存储。保存元素的链表,每间隔一段时间,在后台更新hash算法,进行Bloom的update操作。
我并不赞成再引入新的层次。比方再引入一个cache层。因为那会添加维护量。须要进行复杂性管理。解铃还需系铃人,既然为了避免同一IP地址对的计算结果同样,那就改变算法而不是引入新层,在同一层次。代偿是不必要的。
总而言之,Bloom过滤器的hash算法一定要保持静止,所占空间一定要小巧。
就像集卡或者挖掘机一样。好在现实中使能巨型帧的链路它真的有能力传输巨型帧(说明它的路比較宽!
),这就没有什么问题。
可是,假设拥有非常宽的路,就一定要传输巨型帧吗?假设跑小帧岂不效率更好?双向10车道对于跑集卡是没有什么问题。可是跑轿跑预计更好。假设非要运货,那么运输机的吞吐量尽管不比货轮。可是延时却小非常多。
其实。在一段出发后的链路上。即便你传输了巨型帧,也不保在途中被拆分。
因此基于能耗。分组交换效率,分片/重组开销考虑,巨型帧算是没有什么优势了,我之所以在OpenVPN中模拟了巨型帧。是因为在OpenVPN链路上我能够全然控制一切,尽管这须要途径物理网卡以及虚拟网卡的数据帧均是巨型帧,可是我能通过測试证明。针对这些巨型帧的分片/重组开销远远大于OpenVPN的小包加密/解密以及系统调用开销。
那么。巨型帧的初衷是什么?只为了抵消掉分组交换的优点??其实,这是针对主机的优化,特别是执行Windows主机。这样的主机一般都是处在网络的边缘。作为端到端的终点处理。因此对于到来的数据帧,假设中断过于频繁,势必会降低应用层的处理性能,毕竟总的资源是有限的。而巨型帧能够降低中断的数量。
我以前说,巨型帧是合时宜的,此话也不绝对,对于高性能单一链路而言,这是对的。对于途径窄带链路的数据网络而言,巨型帧平添了开销。且在最后一公里的链路上堵路。
中间节点的分片/重组可能并不只一次,只要须要分析协议头的地方。均须要重组分片,比方状态NAT,比方防火墙。比方数据流分类...对于中断的频度,眼下的千兆卡,万兆卡均能够在网卡芯片内进行分片,重组。然后再中断CPU。同一时候也能够积累数据帧到一定量,然后中断CPU一次。接下来改中断为轮询。细节请參看Intel IGB的e1000e驱动程序readme。
你会发现,Linux的bridge。bonding。vlan都是这样的方式实现的,这些机制并没有像NDIS那样插入一个过滤层NDIS驱动,而是直接组合各种xmit。Linux的这样的实现风格要求开发人员对网络协议栈处理逻辑细节十分熟悉。他们在一个函数中拿到的是一个拥有网络协议栈语义的数据单元而不不过一段buffer。
除了协议层的边界,在协议层处理的内部。Linux定义了若干个HOOK点,Netfilter是一个非常重要的框架,基于它能够实现非常棒的防火墙。注意Netfilter并非只用于防火墙,而是协议栈内置的一套框架,它能够实现随意的数据包QUEUE,STOLEN等。在此基础上能够实现IPSec VPN而无需插入不论什么层次。美中不足的是,Linux对于socket的HOOK机制比較少。
假设你想HOOK住connect操作,就必须在OUTPUT chain上去match TCP的syn标志...
以负载均衡的实现为样例,对于NDIS,须要实现一个中间层过滤驱动,而对于Linux,除了IPVS,使用bonding的lb模式也是非常方便的。
协议栈处理中的conntrack HASH查找/Bloom过滤/CACHE查找/大包与小包/分层处理风格
标签:单元 物理内存 条目 效率 原理 过滤 程序 计算 处理
原文地址:http://www.cnblogs.com/yfceshi/p/7071366.html