日常随笔

2023/03/06 essay 共 2495 字,约 8 分钟

评价一台服务器的硬件资源是否能承载10Gbps流量的dpi深度协议解析还原的能力

10 Gbps 的流量意味着每秒钟传输 10,000,000,000 个比特位。 以太网帧通常是 64-1500 字节,平均长度约为 500 字节。 如果我们假设每个数据包的平均大小为 500 bit,则一秒钟内可以传输 10,000,000,000 / 500 = 20,000,000 个数据包。也就是2千万个包 cpu核心数按照刚才栋哥说的12个核心算,每个线程每秒要处理(2000000/12)约为166.6万个数据包,即每个包最多花费1000000/1666666=0.6微秒的时间 0.6微秒能执行的指令个数是有限的,假设1GHZ cpu,即一个纳秒执行一条指令,0.6微秒可以执行600条指令,如果是2.6GHZ主频则可以执行1560条指令 也就是说按照这种估算12 个core,2.6GHZ主频1个数据包处理需要1560个指令,从而评判抓包,解码,流重组和协议还原在处理完这1个包指令数应该小于1560条, 否则要么修改程序架构减少处理一个包的指令集,要么通过在不改变程序架构的基础上提升系统硬件资源(硬件性能、处理器速度、内存带宽等)

万兆网卡是一种网络接口卡,它支持以太网标准的数据传输速率为10Gbps,是千兆网卡的10倍速率。在万兆网卡中,帧前导和帧间隙是两个重要的概念。帧前导(Preamble)是在数据帧前面附加的一段固定长度的数据,用于同步接收方的时钟。在以太网中,帧前导长度为7个字节(56位),其内容为10101010…1010(即连续的Alternating 1和0)。发送方在发送数据帧前,会先发送帧前导,接收方通过解析帧前导来获取数据帧的时钟同步信息,确保数据的正确接收和解析。帧间隙(Interframe Gap)是相邻两个数据帧之间的一段时间间隔,用于隔离不同数据帧之间的干扰。在万兆网卡中,帧间隙长度为96个比特时间,即96个时钟周期。帧间隙由物理层控制,它在发送数据帧后,会在发送方和接收方之间插入一段固定长度的空闲时间,避免不同数据帧之间的干扰。总之,帧前导和帧间隙是以太网中用于同步和隔离数据帧的两个重要概念,它们保证了数据的正确接收和解析,提高了网络的可靠性和稳定性

假设,我们要跑满10GE网卡,每个包64字节,这就需要2000万PPS(注:以太网万兆网卡速度上限是1488万PPS,因为最小帧大小为84B《Bandwidth, Packets Per Second, and Other Network Performance Metrics》),100G是2亿PPS,即每个包的处理耗时不能超过50纳秒。

PCH 的作用

PCH(Precompiled Headers)是一种编译优化技术,其主要作用是减少编译时间。通常情况下,每次编译一个源文件时,都需要先将相关的头文件包含进来,这个过程会消耗大量的时间。而使用PCH技术,则可以将常用的头文件预编译成一个二进制文件,然后在每次编译源文件时直接引用这个二进制文件,从而大幅度缩短编译时间。

PCH技术的原理是将头文件和代码分别编译,然后将它们合并成一个二进制文件,供后续编译使用。当下次编译时,只需要链接这个二进制文件即可,从而避免了每次编译时都要重新编译头文件的操作,提高了编译效率。

在实际应用中,PCH技术通常适用于对大型项目的开发,其对编译时间的优化效果非常显著。

atomic原理

C++中的atomic类型是一种可原子访问的数据类型,它可以保证多线程并发访问时的线程安全。

原子操作是指在执行时不会受到其他线程干扰的操作,也可以认为是一组不可分割的操作,要么全部执行成功,要么全部失败,不会有部分执行的情况。

C++中的atomic类型通过特殊的硬件指令来实现原子操作。这些指令可以确保在一次操作中读取、修改、写入内存位置。在执行这些指令时,CPU将锁定该内存位置,以确保其他线程无法访问该位置,直到当前线程完成对该位置的操作并释放锁。

atomic类型提供了一系列操作函数来执行原子操作,例如load、store、exchange、compare_and_exchange等。这些操作函数可以确保原子操作以及处理器内存缓存一致性。

当多个线程同时访问同一个atomic变量时,所有操作都是原子的,即所有线程并发执行这些原子操作不会发生竞争、锁、死锁等问题。而在使用非原子操作时,多个线程同时访问同一个变量时,可能会发生竞争条件,可能会导致数据不正确的问题。

因此,使用C++ atomic类型可以确保多线程程序的正确性和安全性

C++的atomic类型底层实现机制可以分为两种:

1.使用硬件指令实现

当C++程序使用atomic类型进行原子操作时,会触发底层硬件指令,这些指令可以保证操作的原子性。具体而言,可以使用锁操作来保证操作的原子性,比如使用x86处理器的lock instruction。

在执行锁操作时,CPU会锁定内存位置,以确保其他线程无法访问该位置。然后,CPU执行操作,并在完成操作后释放锁。由于锁定和释放锁的操作需要消耗大量的CPU资源,因此这种实现方式效率相对较低。

2.使用编译器自动生成与处理器指令集相关的代码实现

C++的atomic类型也可以使用编译器自动生成与处理器指令集相关的代码实现。当编译器发现程序使用了atomic类型进行原子操作时,会自动生成一些代码,使得这些原子操作在硬件中可以实现。

具体而言,在底层实现中会使用CAS(Compare and Swap)等指令来保证数据在多线程程序中的一致性。CAS指令可以比较内存中的值与原值,如果相等,则用新值替换原值,否则不进行任何操作。这个操作是原子性的,在CPU指令级别上可实现线程安全。

在实现中,编译器会使用一些技术来确保原子操作的正确性,比如编写内联汇编程序、使用volatile关键字保证操作被执行、使用内存屏障来保证内存访问顺序等。

总之,无论使用哪种底层实现方式,atomic类型都可以确保在多线程程序中的数据一致性。但使用编译器自动生成代码的实现方式效率更高,而直接使用硬件指令的实现方式效率相对较低

文档信息

Search

    Table of Contents