IPVS的Persistent持续调度

2023-12-19 10:08
文章标签 持续 调度 persistent ipvs

本文主要是介绍IPVS的Persistent持续调度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如下ipvsadm配置命令,开启persistent选项之后,ipvs将来之同一个客户端的请求全部调度到一个固定的真实服务器上。对于SSL和FTP这类,其多个报文之间是相互关联的协议,需要开启此功能。但是对于NAT转发模式,由于NAT将对端口号进行修改,FTP服务需要使用ip_vs_ftp模块才能正常工作。

命令行选项netmask默认为255.255.255.255,即仅对一个客户端执行持续调度。如下指定掩码为255.255.255.0,可对同一个网段内的所有客户端,调度到同一个目的服务器进行处理。

# ipvsadm -A -t 207.175.44.110:80 -s rr --persistent 500 --netmask 255.255.255.0

ipvsadm工具将命令行选项p(–persistent)参数,转换为虚拟服务的标志IP_VS_SVC_F_PERSISTENT,和超时时间,下发到内核中。最长时间为MAX_TIMEOUT(31天),如果不指定时长,默认为300秒。

static int parse_options(int argc, char **argv, struct ipvs_command_entry *ce, unsigned int *options, unsigned int *format)
{while ((c=poptGetNextOpt(context)) >= 0){switch (c) {case 'p':set_option(options, OPT_PERSISTENT);ce->svc.flags |= IP_VS_SVC_F_PERSISTENT;ce->svc.timeout = parse_timeout(optarg, 1, MAX_TIMEOUT);break;

持续调度

在主调度函数ip_vs_schedule中,在执行通常的调度处理之前,首先执行的就是以下虚拟服务是否开启了持续调度的判断,即标志IP_VS_SVC_F_PERSISTENT,如果为真,使用持续调度处理函数ip_vs_sched_persist先行进行处理。

struct ip_vs_conn *ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,struct ip_vs_proto_data *pd, int *ignored, struct ip_vs_iphdr *iph)
{/* Persistent service*/if (svc->flags & IP_VS_SVC_F_PERSISTENT)return ip_vs_sched_persist(svc, skb, cport, vport, ignored, iph);

在ipvs函数ip_vs_sched_persist中,如果没有指定当前报文的连接模板,首先创建模板,在创建相应连接结构。后续的报文,如果匹配此模板,将据此模板生成连接结构,而不再执行调度,这样确保了根据模板生成的连接,具有相同的目的服务器,以实现持续调度的功能。

注意以下的客户端地址和掩码的与操作,可实现前述的将一个网段内的所有客户端调度到同一个目的服务器上。

static struct ip_vs_conn *ip_vs_sched_persist(struct ip_vs_service *svc, struct sk_buff *skb, __be16 src_port, __be16 dst_port, int *ignored, struct ip_vs_iphdr *iph)   
{ if (likely(!ip_vs_iph_inverse(iph))) {   src_addr = &iph->saddr;    dst_addr = &iph->daddr;    } else {src_addr = &iph->daddr;    dst_addr = &iph->saddr;    }/* Mask saddr with the netmask to adjust template granularity */
#ifdef CONFIG_IP_VS_IPV6if (svc->af == AF_INET6)ipv6_addr_prefix(&snet.in6, &src_addr->in6, (__force __u32) svc->netmask);else
#endifsnet.ip = src_addr->ip & svc->netmask;

如果配置的IPVS虚拟服务指定了服务端口号,根据端口号是否为FTP服务端口,创建的连接模板有所不同。如果非FTP服务端口,将创建模板:<caddr, 0, vaddr, vport, daddr, dport>,第二项客户端源端口指定为0意味着所有客户端的报文,都将调度到相同的目的地址(最好两项daddr和dport)。反之,如果虚拟服务为FTP服务端口,将创建模板: <caddr, 0, vaddr, 0, daddr, 0>,与第一个模板不同,此连接模板的最后一项dport为零,表明虽然会调度到同一个真实目的服务器,但是目的端口号不是固定的,这是由于在FTP被动模式下,FTP服务端的数据链路端口号不是固定的。

    {int protocol = iph->protocol;const union nf_inet_addr *vaddr = dst_addr;__be16 vport = 0;if (dst_port == svc->port) {/* non-FTP template: <protocol, caddr, 0, vaddr, vport, daddr, dport>* FTP template:     <protocol, caddr, 0, vaddr, 0, daddr, 0>*/if (svc->port != FTPPORT)vport = dst_port;} else {

与以上不同,如果配置IPVS虚拟服务时未指定端口号,或者是使用防火墙标记fwmark配置的虚拟服务,将创建不同于以上的连接模板。对于fwmark配置方式,生成模板:<IPPROTO_IP,caddr,0,fwmark,0,daddr,0>;对于未指定端口号,生成模板:<protocol,caddr,0,vaddr,0,daddr,0>。

            /* Note: persistent fwmark-based services and persistent port zero service are handled here.* fwmark template:     <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>* port zero template:  <protocol,caddr,0,vaddr,0,daddr,0>*/if (svc->fwmark) {protocol = IPPROTO_IP;vaddr = &fwmark;}}/* return *ignored = -1 so NF_DROP can be used */if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0, vaddr, vport, &param) < 0) {*ignored = -1;return NULL;}}

随后使用ip_vs_ct_in_get函数根据以上生成的param参数结构,查询是否为已存在的模板。如果已经存在,进一步检查此连接模板是否可用(主要为模板中的目的服务器是否可用),由函数ip_vs_check_template完成。如果以上条件不满足,将执行重新调度,获取新的目的服务器。

    /* Check if a template already exists */ct = ip_vs_ct_in_get(&param);if (!ct || !ip_vs_check_template(ct, NULL)) {struct ip_vs_scheduler *sched;/* No template found or the dest of the connection template is not available. return *ignored=0 i.e. ICMP and NF_DROP*/sched = rcu_dereference(svc->scheduler);if (sched) {/* read svc->sched_data after svc->scheduler */smp_rmb();dest = sched->schedule(svc, skb, iph);} else {dest = NULL;}if (!dest) {IP_VS_DBG(1, "p-schedule: no dest found.\n");kfree(param.pe_data);*ignored = 0;return NULL;}

得到新的目的服务器之后,随后创建一个新的连接模板。对于IPVS配置中指定端口号,并且其不等于FTP的情况,在模板中固定目的服务器的目的端口。新创建的连接指定标志IP_VS_CONN_F_TEMPLATE。

        if (dst_port == svc->port && svc->port != FTPPORT)dport = dest->port;/* Create a template* This adds param.pe_data to the template, and thus param.pe_data will be destroyed when the template expires */ct = ip_vs_conn_new(&param, dest->af, &dest->addr, dport, IP_VS_CONN_F_TEMPLATE, dest, skb->mark);ct->timeout = svc->timeout;

如果连接模板可用,直接取出其目的服务器结构。

    } else {/* set destination with the found template */dest = ct->dest;kfree(param.pe_data);}

依据目的服务器结构,为当前的报文创建一个连接结构,函数ip_vs_control_add将新建连接的control指针指向模板连接,并增加模板连接结构中的统计计数n_control。

    dport = dst_port;if (dport == svc->port && dest->port)dport = dest->port;flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && iph->protocol == IPPROTO_UDP) ? IP_VS_CONN_F_ONE_PACKET : 0;/* Create a new connection according to the template */ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol, src_addr, src_port, dst_addr, dst_port, &param);cp = ip_vs_conn_new(&param, dest->af, &dest->addr, dport, flags, dest, skb->mark);/* Add its control */ip_vs_control_add(cp, ct);return cp;

连接模板查询

以下查询函数ip_vs_ct_in_get分为两个部分,第一如果PE(Persistent Engine)存在,使用其匹配函数ct_match进行匹配查找。

/* Get reference to connection template */
struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
{   struct ip_vs_conn *cp;hash = ip_vs_conn_hashkey_param(p, false);hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {if (unlikely(p->pe_data && p->pe->ct_match)) {if (cp->ipvs != p->ipvs)continue;if (p->pe == cp->pe && p->pe->ct_match(p, cp)) {if (__ip_vs_conn_get(cp))goto out;}continue;}   

否则,通过对比以下项参数进行匹配:1)协议族; 2)客户端地址; 3)虚拟服务地址; 4)虚拟服务端口; 5)客户端端口; 6)协议; 7)相同的ipvs。最重要的是遍历到的连接的flags必须要有IP_VS_CONN_F_TEMPLATE标志。

        if (cp->af == p->af &&ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&/* protocol should only be IPPROTO_IP if * p->vaddr is a fwmark */ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, p->vaddr, &cp->vaddr) &&p->vport == cp->vport && p->cport == cp->cport &&cp->flags & IP_VS_CONN_F_TEMPLATE &&p->protocol == cp->protocol &&cp->ipvs == p->ipvs) {if (__ip_vs_conn_get(cp))goto out;}}cp = NULL;out:return cp;

目前IPVS支持的PE引擎只有SIP,其连接匹配函数为ip_vs_sip_ct_match,在这里增加了对PE数据的比较。对于SIP而言,其PE数据为呼叫ID(call id)。

static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param *p, struct ip_vs_conn *ct){bool ret = false;if (ct->af == p->af &&ip_vs_addr_equal(p->af, p->caddr, &ct->caddr) &&/* protocol should only be IPPROTO_IP if d_addr is a fwmark */ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, p->vaddr, &ct->vaddr) &&ct->vport == p->vport &&ct->flags & IP_VS_CONN_F_TEMPLATE &&ct->protocol == p->protocol &&ct->pe_data && ct->pe_data_len == p->pe_data_len &&!memcmp(ct->pe_data, p->pe_data, p->pe_data_len))ret = true;return ret;

内核版本 4.15

这篇关于IPVS的Persistent持续调度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511786

相关文章

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3

一种改进的red5集群方案的应用、基于Red5服务器集群负载均衡调度算法研究

转自: 一种改进的red5集群方案的应用: http://wenku.baidu.com/link?url=jYQ1wNwHVBqJ-5XCYq0PRligp6Y5q6BYXyISUsF56My8DP8dc9CZ4pZvpPz1abxJn8fojMrL0IyfmMHStpvkotqC1RWlRMGnzVL1X4IPOa_  基于Red5服务器集群负载均衡调度算法研究 http://ww

Golang进程权限调度包runtime

关于 runtime 包几个方法: Gosched:让当前线程让出 cpu 以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行GOMAXPROCS:设置最大的可同时使用的 CPU 核数Goexit:退出当前 goroutine(但是defer语句会照常执行)NumGoroutine:返回正在执行和排队的任务总数GOOS:目标操作系统NumCPU:返回当前系统的 CPU 核数量 p

云原生之高性能web服务器学习(持续更新中)

高性能web服务器 1 Web服务器的基础介绍1.1 Web服务介绍1.1.1 Apache介绍1.1.2 Nginx-高性能的 Web 服务端 2 Nginx架构与安装2.1 Nginx概述2.1.1 Nginx 功能介绍2.1.2 基础特性2.1.3 Web 服务相关的功能 2.2 Nginx 架构和进程2.2.1 架构2.2.2 Ngnix进程结构 2.3 Nginx 模块介绍2.4

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

2024年AMC10美国数学竞赛倒计时两个月:吃透1250道真题和知识点(持续)

根据通知,2024年AMC10美国数学竞赛的报名还有两周,正式比赛还有两个月就要开始了。计划参赛的孩子们要记好时间,认真备考,最后冲刺再提高成绩。 那么如何备考2024年AMC10美国数学竞赛呢?做真题,吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一。通过做真题,可以帮助孩子找到真实竞赛的感觉,而且更加贴近比赛的内容,可以通过真题查漏补缺,更有针对性的补齐知识的短板。

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

【电机控制】数字滤波算法(持续更新)

文章目录 前言1. 数字低通滤波 前言 各种数字滤波原理,离散化公式及代码。 1. 数字低通滤波 滤波器公式 一阶低通滤波器的输出 y [ n ] y[n] y[n] 可以通过以下公式计算得到: y [ n ] = α x [ n ] + ( 1 − α ) y [ n − 1 ] y[n] = \alpha x[n] + (1 - \alpha) y[n-1]

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

虚幻中的c++(持续更新)

文章目录 虚幻中的c++UPROPERTY参数 UFUNCTION参数 虚幻中的c++ UPROPERTY 是虚幻中用于声明属性的宏,它用于标记某个属性是一个虚幻托管的属性,并且可以在编辑器中进行访问和操作。其提供了一系列参数,用于定义属性的各种行为,例如是否可编辑、是否可序列化等。 参数 EditAnywhere:允许在编辑器中编辑该属性,包括蓝图类及其在关卡