Linux内核协议栈的socket查找缓存路由机制

简介:
是查路由表快呢?还是查socket哈希表快?这不是问题的根本。问题的根本是怎么有效利用这两者,让两者成为合作者而不是竞争者。这是怎么回事?
       我们知道,如果一个数据包要到达本地,那么它要经过两次查找过程(暂时不考虑conntrack):IP层查找路由和传输层查找socket。怎么合并这两者。
       Linux内核协议栈采用了一种办法:在socket中增加一个dst字段作为缓存路由的手段,skb在查找路由之前首先查找socket,找到的话,就将缓存的dst设置到skb,接下来在查找路由的时候,发现已经有了dst,就省去了路由查找的过程。
       问题是,socket的dst字段什么时候设置的呢?当然是“和该socket相关的第一个skb”到来的时候设置上的,无疑即便这第一个skb找到了 socket,此时的socket上的dst也是NULL,那么它会去老老实实查找路由表,如果找到,则将找到的路由项设置到socket的dst字段。
       这个特性在Linux的实现中叫做ip_early_demux,在内核文档中,描述如下:
ip_early_demux - BOOLEAN Optimize input packet processing down to one demux for
    certain kinds of local sockets.  Currently we only do this
    for established TCP sockets.
    It may add an additional cost for pure routing workloads that
    reduces overall throughput, in such case you should disable it.
    Default: 1
对于forward转发,这个特性必然要降低性能,但是我并不是想说这个显而易见的问题,我想说的有两点:
1.层次cache逻辑
我 们知道,路由查找是一个“尽力而为”的多对一匹配过程,skb和路由entry并不是精确的一一对应关系,因此不能在路由entry中缓存socket, 但是却可以在socket中缓存路由entry,因为socket和skb是一个一一对应的关系(我说的不是TCP listen socket..),同样,我也能在路由cache中缓存socket,因为路由cache和skb也是一一对应的关系。
       然而linux内核还是去掉了路由cache的支持,不过这没关系,只要知道一点就够了:一一对应的精确匹配项可以缓存更加松散的非一一对应的匹配项。如 果将目光移到conntrack,就知道该怎么做了,我曾经将路由entry缓存到了conntrack里面,按照这个逻辑,是合理的,同样 的,socket也可以被缓存到conntrack里面,这一点已经有了iptables相关的match和target。
2.自动还是手动
既 然Linux有了ip_early_demux配置参数,问题就是什么时候开启它而什么时候关闭它。特别是,在你事先不知道有多少包是到达本地,有多少包 是forward的情况下,这个问题显得更加不易回答。此时,是相信管理员的非0即1的配置呢,还是让系统去动态自适应?

       如何统计包显得尤为重要,典型情况下,如果有超过60%的包是到达本地的,那么就开启它,反之则关闭它。ip_early_demux配置参数作为一个全 局的参数并没有什么不好,因为如果不是这样,那么就会出现另一个问题,即如何判断一个包是否要进行early_demux...对于边界非七层设备,一般 而言,流量是分类的,分为管理面流量和数据面流量,对于前者而言,流量的终点就是本地,而对于后者,本机仅仅做forward,如果能事先高效地将包进行 平面分类,那么两个ip_early_demux配置会显得更好,对于带外管理而言,Linux的nsnamespace可以很好地完成这个任务。


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1601786


相关文章
|
8天前
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
|
22天前
|
网络协议 安全 Java
Java网络编程入门涉及TCP/IP协议理解与Socket通信。
【6月更文挑战第21天】Java网络编程入门涉及TCP/IP协议理解与Socket通信。TCP/IP协议包括应用层、传输层、网络层和数据链路层。使用Java的`ServerSocket`和`Socket`类,服务器监听端口,接受客户端连接,而客户端连接指定服务器并交换数据。基础示例展示如何创建服务器和发送消息。进阶可涉及多线程、NIO和安全传输。学习这些基础知识能助你构建网络应用。
26 1
|
2月前
|
存储 缓存 自然语言处理
深入PHP内核:理解Opcode缓存与性能优化
【5月更文挑战第14天】 在动态语言的世界里,PHP一直因其高性能的执行效率和广泛的社区支持而备受青睐。随着Web应用的复杂性增加,对性能的要求也越来越高。本文将探讨PHP的Opcode缓存机制,解析其对性能提升的贡献,并展示如何通过配置和使用不同的Opcode缓存方案来进一步优化PHP应用的性能。我们将深入到PHP的核心,了解Opcode是如何生成的,以及它如何影响最终的执行效率。
|
10天前
|
网络协议 Linux 分布式数据库
【Linux】DNS系统,ICMP协议,NAPT技术详解
NAPT(Network Address Port Translation),也被称为端口地址转换,是一种NAT(网络地址转换)的形式。NAPT允许多个设备在内部网络上使用私有IP地址,并通过单个公共IP地址与外部网络进行通信。NAPT通过改变传输层的端口号来实现这一点,从而允许多个内部设备共享同一个公共IP地址。
16 0
|
11天前
|
缓存 JavaScript
vue 页面缓存 keep-alive(含配置清除页面缓存 exclude,局部缓存,动态缓存,路由控制缓存 $route.meta.keepAlive)
vue 页面缓存 keep-alive(含配置清除页面缓存 exclude,局部缓存,动态缓存,路由控制缓存 $route.meta.keepAlive)
14 0
|
1月前
|
程序员 API 开发者
Socket与HTTP协议的实践
【6月更文挑战第4天】本文介绍了Python中的网络编程,包括Socket编程和基于HTTP协议的实践。Socket编程是网络通信的基础,Python的`socket`模块简化了其使用。文中展示了服务器和客户端的简单示例,以及如何通过多线程处理多个客户端连接。另外,文章讨论了HTTP协议,推荐了`requests`库,并给出了发送GET和POST请求的例子。最后,总结了Socket编程和HTTP协议在网络编程中的应用及其在Web开发和API交互中的重要性。
24 5
|
1月前
|
网络协议 应用服务中间件 网络性能优化
解析TCP /UDP协议的 socket 调用的过程
【6月更文挑战第2天】该文介绍了传输层的两种主要协议TCP和UDP的区别。TCP是面向连接、可靠的,提供顺序无错的数据传输,而UDP则是无连接、不可靠的,不保证数据顺序或不丢失。
|
2月前
|
Linux C语言
|
17天前
|
缓存 JavaScript API
Vue-Router路由动态缓存组件(keep-alive),vue2/vue3不同写法
Vue-Router路由动态缓存组件(keep-alive),vue2/vue3不同写法
|
2月前
|
存储 缓存 PHP
深入PHP内核:理解Zend Engine与Opcode缓存
【5月更文挑战第30天】 在PHP的开发世界中,性能优化是一个永恒的话题。随着现代Web应用的复杂性日益增加,仅仅依靠代码层面的优化已经远远不够。本文将深入探讨PHP的执行心脏——Zend Engine,以及如何通过Opcode缓存机制提升PHP应用的执行效率。我们将透过对Zend Engine工作原理的分析,了解Opcode缓存的实现原理,并通过实例来展示其对性能提升的显著影响。