昨天,我们看到,多核处理器的出现大大提升了软转发的吞吐量,但缓存的优化成为多核的瓶颈。除了在MBUF方面做了优化之外,还有一个重要的地方——计数器的优化。
无论是交换机,还是路由器,一个重要的功能就是接口计数器。
图中可以看到,路由器上的每个接口都有收发数据包的数量计数,和字节数计数。由于每个接口的数据包都有可能被任何一个处理器核心处理,我们需要想一想:如果每个处理器核心都对计数器进行操作,CPU内部会发生什么?
如果处理器核心A从RAM读取这个计数器,并加上了一个数,与此同时,处理器核心B也要对这个计数器进行累加操作。于是,两个处理器就发生了冲突。为了解决这一问题,CPU提供了锁的机制,但是这样一来……
所有的处理器核心都要在处理计数器的时候排队了,处理效率是可想而知的。
因此,工程师们为每个核心分配了一套计数器,每个核心处理完一个数据包,都在属于自己的计数器上进行累加操作,在执行查看计数器指令时再进行累加。这样,就完美地解决了前面提到的问题。
当然,由于基于多核的网络处理器还有着一些网络处理专用加速协处理器,如Parser(报文解析器),它可以读取数据包的前64字节,并按照预设的寄存器值读取二层地址、三层地址、TCP/UDP端口号等信息,把CPU核心的时间从重复性的解析数据包中解放出来,也大大加速了数据包的处理。在这些因素加持之下,8核32线程做到10M以上的pps并不难。
话分两头,各表一枝。
Intel放弃了IXP NP产品线以后,目睹MIPS/ARM在10Gbps到100Gbps的网络设备市场攻城略地,心中酸楚可想而知。但是,由于英特尔主导的x86体系有着天然的限制……
基于X86处理器的路由器最初实现如上图。随着时间的推移,共享式的PCI总线演进为点对点的PCI-E总线。
实际上,由于网卡早就支持DMA,所有的网卡接收到的数据包都可以直接写入RAM中,问题出在后面的流程。
我们知道,在DMA完成后,网卡会向CPU核心发起中断。CPU的某个核心处理中断,打断原有的流程,进入内核态,访问网卡接收到的数据包,并拷贝到用户态,返回到操作系统。 这里面有三个问题:
DPDK就是通过解决这些问题,大大提升了Intel处理器在Linux下的数据包处理性能。
我们反复提到cache,目前看来,有必要插播一期专题,好好聊一聊这个东西,因为,这个概念在后面的计算与存储设备硬核技术内幕中也会多次提到……