Linux流负载均衡中Layer7的数据流(连接跟踪)识别问题

简介:

1.支持Layer7的nf_conntrack真的没有必要做

走火入魔之后,你会觉得需要赶紧将“基于五元组的数据流”改成“基于应用层协议固定偏移的数据流”,赶紧动手,越快越好!于是此人在支持zone conntrack的Linux 3.17内核上为nf_conn增加了几个字段:
bool l7; //布尔型,表示是否要进行layer7的匹配。
u32 offset; //应用层流标识的偏移
u32 offlen; //应用层流标识的长度

以上的三个字段在CT target中被设置,同时被设置的还有zone,它表明:
凡 是属于zone $id的数据包都用应用层固定偏移定义的固定长度的流标识来识别一个流,而不再使用传统的五元组来识别一个流。重新定义tuple,同样增加一个bool 型l7,表示它是否是应用层的流标识,同时增加一个MAX_IDLEN长度的数组sid,这意味着流标识别最长是MAX_IDLEN字节。
       话说以上就是基本的数据定义,那么在代码逻辑上,修改也不难,主要是修改resolve_normal_ct函数,取出tmpl模板中的l7,如果它非 0,那就表明需要“应用层流标识”来识别流,此时根据offset,offlen字段,定位到 [iphdr+iphdrlen+transphdrlen]这个位置,取出offlen字节的数据,作为hash计算的key计算hash值,在 __nf_conntrack_find_get之前,tuple被填充成了应用层的sid,同时置位tuple的l7,这意味着在find conntrack的时候,比较的是tuple的sid值而不是五元组。最后,在conn confirm的时候,将conntrack按照其offset,offlen定位的payload信息表示的sid(它已经被放进了tuple结构中, 由其char sid[MAX_IDLEN];字段来标识)来进行插入。
       修改,编译,测试总共用了不到两个小时(买的iMac太TMD给力了!!)。随性,随玩,吃点东西,喝口茶,开始得瑟。这个人就是我啊!
       开始思考所作所为的意义后,也是一个反省的过程!我发现,突然发现,所作的一切都没有意义。conntrack结构体并没有保存什么用于应用层的信息,虽 然我自己扩展了它,能让它保存很多东西,比如路由,socket,等,但是事实上还没有什么地方真的用到了这些,即这些都是自己没事玩玩的东西。 conntrack中保存的最重要的信息就是NAT信息,即tuple信息,这个tuple是基于传统5元组的,你想啊,如果我用基于sessionID 的应用层信息来标识一个tuple,那么NAT怎么办?如果客户端的IP地址发生变化,即使sessionID不变,NAT还是要重新做,还是得不到任何 益处。我的本意就是能省去由于IP地址,端口发生变化后的那一系列重新操作,但是最终还是没有省,因为改变的是IP和端口,需要重新修改或者修饰的依然是 IP和端口这些信息。
       如果上面的代码是写在了纸上,很显然,我会将其撕碎,然后扔进垃圾桶...

2.支持Layer7任意payload哈希计算的reuseport是强大的

Linux 最新的内核已经支持了UDP的reuseport选项,这个机制可以很好地为UDP的负载均衡服务,如果不了解可以bing一下。它之所以可以做负载均 衡,就是它通过一个固定的5元组来计算一个固定hash,然后基于这个固定hash将一个数据包分发到固定的socket,如果IP地址不发生变化,一切 都会很好,但是IP地址在移动环境下会发生变化,这就意味着5元组信息发生了变化,那么重新计算的hash将也会发生变化(不发生变化那是碰撞了!),这 就意味着这个变化了IP的客户端发出的下一个UDP数据包将可能被分发给别的socket,这在基于UDP的长连接服务中是不希望发生的。以下是 __udp4_lib_lookup核心代码:


begin:
    result = NULL;
    badness = -1;
    sk_nulls_for_each_rcu(sk, node, &hslot->head) {
    // sessionID版本的hash计算,服务端不要鉴别sport/saddr为妙!
        score = compute_score(sk, net, saddr, hnum, sport,
                      daddr, dport, dif);
        if (score > badness) {
            result = sk;
            badness = score;
            reuseport = sk->sk_reuseport;
            if (reuseport) {
                // 5元组流版本,根据4元组计算一个hash值
                //hash = inet_ehashfn(net, daddr, hnum, saddr, htons(sport));
        // sid流版本,基于sessionID计算hash。
        // 问题是这个sid怎么传到这里...大修吧
        hash = sid_based_hash(sid, );
                matches = 1;
            }   
        } else if (score == badness && reuseport) {
            matches++;
            // 是否由该sk替换上次匹配到的sk,就看hash值的影响了
            if (((u64)hash * matches) >> 32 == 0) {
                result = sk;
            }   

            hash = hash * 1664525 + 1013904223;
        }   
    }   
    /*  
     * if the nulls value we got at the end of this lookup is
     * not the expected one, we must restart lookup.
     * We probably met an item that was moved to another chain.
     */
    if (get_nulls_value(node) != slot)
        goto begin;



注释中提到了大修,意思是,我必须将一个skb传到这里,才能根据setsockopt的参数reuseport标志,sid的offset,sid的offlen来获取sid,然后计算hash,但这个修理很容易,重新编译一下内核即可。
       在UDP的reuseport中采用sessionID识别一个流是很爽的一件事,因为此时数据已经到传输层了,除却重新封装的数据包,基本都是达到本机 某个UDP服务的,数据包已经到达此地,说明5元组相关的鉴别比如NAT之类的已经完全通过,下一步就是往应用层送数据了,此时根据应用层的sid来识别 一个流,就能确保即便是客户端IP改变了,它发出的请求也能到达同一个UDP服务线程...这也为移动时代提供了一个好的实景,在五元组频繁更换的年代, 如何保持应用层不断开...




 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1612808
相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
27天前
|
Shell Linux C语言
【Shell 命令集合 网络通讯 】Linux 关闭PPP(Point-to-Point Protocol)连接 ppp-off命令 使用指南
【Shell 命令集合 网络通讯 】Linux 关闭PPP(Point-to-Point Protocol)连接 ppp-off命令 使用指南
40 1
|
3月前
|
Java Linux 程序员
Linux 下 JNA 调用动态连接库文件 so
Linux 下 JNA 调用动态连接库文件 so
60 0
|
4月前
|
负载均衡 前端开发 应用服务中间件
【Linux】Nginx安装使用负载均衡及动静分离(前后端项目部署),前端项目打包
【Linux】Nginx安装使用负载均衡及动静分离(前后端项目部署),前端项目打包
360 0
|
27天前
|
监控 网络协议 Linux
【Shell 命令集合 网络通讯 】Linux 显示网络 连接、路由表和网络接口信息 netstat命令 使用指南
【Shell 命令集合 网络通讯 】Linux 显示网络 连接、路由表和网络接口信息 netstat命令 使用指南
51 1
|
3月前
|
Linux Windows
FinalShell连接Linux虚拟机报错java.net.ConnectException: Connection timed out: connect(亲测有效)
FinalShell连接Linux虚拟机报错java.net.ConnectException: Connection timed out: connect(亲测有效)
152 0
|
9天前
|
负载均衡 Java 关系型数据库
linux 下amoeba实现数据库的负载均衡
linux 下amoeba实现数据库的负载均衡
8 1
|
26天前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】Linux 启动和管理SLIP 连接 sliplogin命令 使用指南
【Shell 命令集合 系统管理 】Linux 启动和管理SLIP 连接 sliplogin命令 使用指南
30 0
|
27天前
|
监控 Shell Linux
【Shell 命令集合 网络通讯 】Linux 拨号连接 dip命令 使用指南
【Shell 命令集合 网络通讯 】Linux 拨号连接 dip命令 使用指南
35 0
|
27天前
|
Shell Linux C语言
【Shell 命令集合 网络通讯 】Linux 建立串行连接 cu命令 使用指南
【Shell 命令集合 网络通讯 】Linux 建立串行连接 cu命令 使用指南
28 0
|
27天前
|
存储 安全 Shell
【Shell 命令集合 磁盘维护】Linux 检测和识别硬盘或文件系统中的坏块 badblocks命令使用教程
【Shell 命令集合 磁盘维护】Linux 检测和识别硬盘或文件系统中的坏块 badblocks命令使用教程
35 0