首页 > 编程知识 正文

高性能混凝土的概念,钢筋的力学性能有哪些

时间:2023-05-03 22:29:57 阅读:182125 作者:2895

互联网上的五组标识从一个APP应用程序到远程的另一个APP应用程序的连接。 为了保证端到端的可达性,显然在全球范围内5组必须是唯一的。

保证五元组的全球唯一性看起来是繁重的劳动。 例如,举例说明IPv4网络,并且仅考虑TCP和UDP,一个pentapple空间包括两个32比特IPv4地址、两个16比特端口、以及一个协议

但在分布式互联网环境下,五图的全局唯一性其实非常容易保证,网络计算能力分布在世界的各个角落,这个五图的唯一性得到了全世界所有计算机的保证:

因为每个计算机的IP地址都不一样,所以可以全面排除2 32 2^{32} 232种可能的计算能力。 访问目标不同时,全面卸载2 32 2^{32} 232种可能的计算力。 …最终,也许用万位数的端口类别来计算就可以了。 然而,互联网上的主机并不是完全对等分布的。 这完全是NAT的存在!

NAT的存在,将已经是分布在每台计算机的保证五元组唯一的计算重新集中了起来!

由于互联网计算机的分布特性,在连接初期,元组的唯一性得到保证,一个元组通过任一中间设备时,该设备可以完全保证该元组的唯一性。

但是,当一台设备对5组数据包进行NAT时,由于NAT设备没有全局的5组信息库,所以在进行NAT时必须通过慎重的计算确保NAT后5组的唯一性。 当然,它只保证通过本地连接的五对唯一性。

对于由Linux内核Netfilter实现的NAT,五元组的唯一性由get_unique_tuple函数实现。 这里不分析这个函数的实现。 那个大致在说下面的事。

对于SNAT,尽可能使用已保存的已知tuple。 这是因为访问地址不同的概率很高,因此计算能力大幅下降。 (【第一步】)万不得已再次网罗了tuple命名空间,但依然有很多trick进行了优化,多次盲搜索后放弃了。 get_unique_tuple并不囊括整个命名空间,如果盲搜索失败则停止,NAT的失败并不意味着tuple命名空间的枯竭。 但以上过程仍然是繁重的劳动,尤其是在流量较大的情况下。

可能有人会怀疑,我只配置了一个NAT规则,只将特定流的一个源IP地址转换为目的。 这怎么能影响全局?

很多人都有这样的疑问,其实这很容易解释:

只要开启33558www.Sina.com/NAT,所有数据流就必须同等对待。 在实际符合NAT规则之前,系统不知道规则和一致情况。 实际上,5组的唯一性完全由NAT自己保证。 因此,只要NAT处于打开状态,就必须对所有流施加get_unique_tuple这样的繁重的劳动!

即使一个流不匹配任何NAT规则,NAT仍然执行nf_nat_alloc_null_cdhsding以将所有流合并到一个全局tuple命名空间中。 这在NAT实际执行get_unique_tuple时提供优化。

在运行SNAT的HOOK点上,将tuple添加到nf_nat_bysource链表中,为上述NAT只有开启和关闭之说,与规则如何无关。提供依据。 注册NAT的HOOK函数时,以前的conntrack没有包含在NAT全局tuple命名空间中,也没有添加到nf_nat_bysource链表中。 没有问题吧? 我让别人解决这个问题,答案是:

没有问题。 只会损害性能。 如果流与进入nf_nat_fn时记录的5-tuple冲突,则流不是同时NEW

nat_initialized,早就命中了不是吗?

然而真的是这样吗?非也!

我想表达的是,nf_nat_alloc_null_cdhsding这个函数是必须的,同时它可能会默默改变你的连接的源端口,信吗?

我不想过多的解释细节,如果你懂nf_conntrack和NAT的细节,应该知道我下面的脚本再说什么。

给出测试拓扑环境:

客户端 192.168.56.101:12345 连接服务器 192.168.56.102:80

首先,我们设置以下的iptables规则,仅仅TRACK到达80端口的连接,同时添加一条无关的NAT规则,以注册conntrack HOOK(由于conntrack HOOK的延迟注册,需要实际添加一条NAT规则):

*raw-A PREROUTING -p udp -j NOTRACK-A PREROUTING -p tcp -m tcp ! --sport 80 -j NOTRACK-A OUTPUT -p tcp -m tcp ! --dport 80 -j NOTRACK-A OUTPUT -p udp -j NOTRACK*nat-A OUTPUT -d 2.3.4.5/32 -p udp -j DNAT --to-destination 5.4.3.2

其次,我给出一个python程序,一个TCP客户端,cdhsd特定的地址端口,连接特定的地址端口:

#!/usr/cdhs/python3import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)sock.cdhsd(('192.168.56.101', 12345))server_address = ('192.168.56.102', 80)sock.connect(server_address)sock.close();

最后,我给出一个stap脚本,它的意思是:

在python新建连接被conntrack记录前什么也不做。在python新建连接被NEW后模拟创建一个“与之reply方向冲突”的conntrack项,在实际中这完全是可能的。观察python新建连接发出的包,其端口号竟然变了!

脚本如下:

#!/usr/cdhs/stap -g%{#include <net/netfilter/nf_conntrack.h>%}probe module("nf_nat").function("__nf_nat_alloc_null_cdhsding"){if ($manip == 1) {// 在OUTPUT NAT执行时,模拟一个完全正常的可能发生的conntrack item插入system("conntrack -I --protonum 6 --timeout 100 --reply-src 192.168.56.102 --reply-dst 192.168.56.101 --state SYN_SENT --reply-port-dst 12345 --reply-port-src 80 --src 1.1.1.1 --dst 192.168.56.102");// 防止stap同步问题,延迟一会儿再整mdelay(100);}}// 打印一些看似无关紧要的信息,但确实给出了tuple冲突的结果probe module("nf_conntrack").function("nf_conntrack_tuple_taken").return{printf("nf_conntrack_tuple_taken ret:%dn", $return);}%{struct nf_conn *thief = NULL;%}function alertit(stp_ct:long)%{struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;struct nf_conntrack_tuple *tuple;unsigned short port;tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;port = ntohs((unsigned short)tuple->dst.u.all);if (port == 80 && thief == NULL) {STAP_PRINTF("The thief coming!n");thief = ct;}%}probe module("nf_conntrack").function("nf_conntrack_hash_check_insert"){alertit($ct);}function run_away(stp_tuple:long, stp_ct:long)%{struct nf_conntrack_tuple *tuple = (struct nf_conntrack_tuple *)STAP_ARG_stp_tuple;struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;struct nf_conntrack_tuple *t;if (thief) {t = &thief->tuplehash[IP_CT_DIR_REPLY].tuple;//t->dst.u.all = 100; // 这两条注释本来是想破坏掉这个conntrack项的//t->src.u.all = 100;thief = NULL;STAP_PRINTF("The thief ran away...n");}%}probe module("nf_conntrack").function("nf_conntrack_alter_reply"){run_away($newreply, $ct);}

执行stap脚本,然后执行client.py,但是我们看一下tcpdump抓包:

21:18:50.098848 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [S], seq 1990086505, win 64240, options [mss 1460,sackOK,TS val 814885365 ecr 0,nop,wscale 7], length 021:18:50.098872 IP 192.168.56.102.80 > 192.168.56.101.35010: Flags [S.], seq 1199002250, ack 1990086506, win 65160, options [mss 1460,sackOK,TS val 2915891341 ecr 814885365,nop,wscale 7], length 021:18:50.099064 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 814885466 ecr 2915891341], length 0

可以看到,端口已经不是12345了,它变成了35010,这一切都是在 get_unique_tuple 中,此处不细聊。

一个真实的场景就是,在192.168.56.101.12345 > 192.168.56.102.80发起, conntrack初始NEW之后,confirm之前 有一个conntrack项被创建,或者是直接恶意插入的,或者某个流是真的命中了一条NAT规则:

src 1.1.1.1:12345 dst 192.168.56.102:80 --> src 192.168.56.101:12345 dst 192.168.56.102:80

那么原始测试流的源端口将会被偷偷地,默默地改变!

关于nf_nat_alloc_null_cdhsding,我已经单独写了一篇文章,这其实是我一直都想说的话题:
https://blog.csdn.net/dog250/article/details/112691374

下图展示一个nf_conntrack/NAT的宏观场面,我把重体力劳动都用浅红色底色表示:

现在我们看到一些相对耗时的重体力劳动,如果要优化性能,避开这些位置,或者优化这些位置均可。

nf_conntrack已经在这些方面有所工作了,比方说如果没有一条NAT规则被添加,那么就干脆不注册conntrack HOOK(这并不完美,因为其它的模块只要注册了conntrack HOOK,NAT依然是数据包的必经之路)。

不管怎么说,认清conntrack & NAT的性能瓶颈到底在哪儿是必要的,如果你的机器连接数达到了几十万上百万,你看看你的conntrack hash表的大小是不是很小,遍历一次冲突链表的开销会不会很大,这些情况有时候并不是nf_conntrack本身的问题,可能仅仅是你的配置问题。必要的时候,想办法把不相关的流量NOTRACK掉也是一种优化方案,比方说,对于那些频繁的又没有NAT,status filter等需求的短连接,NOTRACK将会避开get_unique_tuple以及spin lock从而大大提高单机性能。

浙江温州皮鞋湿,下雨进水不会胖。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。