22. Packet Distributor Library
DPDK包分发库是一种用于在运行时支持单个数据包动态负载均衡的库。在使用这个库时,使用的逻辑核将被考虑为两个角色:首先是分发包lcore,负责负载均衡或分发包,以及一组负责从分发服务器接收数据包并对其进行操作的worker lcore。操作模型如下图所示。
在包分发库中有两种API的操作模式,一种是使用32位的flow_id,一次发送一个数据包;另一种是优化模式,使用15位flow_id,一次发送最多8个数据包。模式是由rte_distributor_create()函数中的类型字段选择的。
22.1. Distributor Core Operation
包分发核执行大多数处理,以确保包在worker之间公平分配。包分发操作如下:
- 通过包分发核线程调用rte_distributor_process() API,将数据包传递到分发组件。
- 每个worker lcore和包分发核共享一个cache line,以便将消息和包传递给worker。处理API调用将轮询所有的worker高速cache line,以查看哪个worker正在请求数据包。
- 当worker请求数据包时,分发器从收到的数据包集中取出数据包分发给workers。因为要分发,分发器必须检查“tag”-存储在mbuf中RSS hash字段中的“标记”,这个标记决定数据包归哪个worker处理。
- 如果接收数据包集中的下一个数据包的标签表明它已经被一个worker处理过(可以理解为同一个流的下一个数据包),那么这个数据包将被排入队列,并在对应worker发出下一步工作请求时优先于其它数据包进行处理。这确保了没有两个具有相同标记的数据包包被并行处理(被不同worker处理),并且所有具有相同标记的包都是按输入顺序处理的。
- 一旦传递给处理API的所有输入数据包都分配给了worker,或者排队等待指定标记的worker处理,那么处理API就会返回给调用者。
可向包分发lcore提供的其他函数有:
- rte_distributor_returned_pkts()
- rte_distributor_flush()
- rte_distributor_clear_returns()
其中最重要的API调用是“rte_distributor_returned_pkts()”,它应该只在调用处理API lcore中调用。它返回给调用者全部已经被worker core核处理了的数据包。在这组返回的数据包集中,所有共享相同标签的包将按照原来的顺序返回。
NOTE:如果worker lcore在内部对包进行缓存,以便在以后批量传输,那么共享标签的数据包可能会被打乱。一旦一个worker lcore请求一个新的数据包,分发服务器就会假设它已经完全完成了之前的数据包,因此具有相同标签的附加包可以安全地分发给其它worker-它可能会迅速的刷新数据包缓存,导致数据包乱序。
NOTE:对于不共享一个标记的包,没有包排序保证。
使用处理和returned_pkts API,可以使用下面的应用程序工作流,通过标签(tag)标识保证在数据包流中的数据包有序。
前面提到的刷新和clear_return API调用可能比处理和returned_pkts API更少地使用,主要提供给库的单元测试。在DPDK API参考文档中可以找到这些函数及其使用的描述。
22.2. Worker Operation
worker core 是实际处理被分发器分发的数据包的core。当每个worker完成了以前的数据包处理时,调用“rte_distributor_get_pkt()”API来请求一个新的包。[上一个包应该返回到分发器组件,将其作为最后一个参数传递给这个API调用。]
由于可能需要改变worker core的数量,这取决于流量负荷,即在较轻负荷时节省电力。某个worker可能会停止处理数据包,通过调用“rte_distributor_return_pkt()”来表示它已经完成了当前的数据包,并且不想要一个新的数据包。