IPVS的OPS调度

2023-12-19 10:08
文章标签 调度 ops ipvs

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

如下ipvsadm配置命令:

# ipvsadm -A -t 207.175.44.110:80 -s rr --ops

OPS是One-Packet Scheduling的缩写,即单一报文调度。仅应用于UDP协议的虚拟服务,或者是标记UDP报文的防火墙fwmark配置,每个连接仅执行一次报文调度。

以下为ipvsadm代码中对–ops参数的解析部分,可见为虚拟服务置位了标志IP_VS_SVC_F_ONEPACKET。

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 'o':set_option(options, OPT_ONEPACKET);ce->svc.flags |= IP_VS_SVC_F_ONEPACKET;break;

连接OPS

IPVS在创建连接之时,会根据虚拟服务的标志是否设置了IP_VS_SVC_F_ONEPACKET,以及当前报文是否为UDP协议报文,为连接增加标志IP_VS_CONN_F_ONE_PACKET。

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)
{flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && iph->protocol == IPPROTO_UDP) ?IP_VS_CONN_F_ONE_PACKET : 0;/* Create a connection entry. */{struct ip_vs_conn_param p;ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol, caddr, cport, vaddr, vport, &p);cp = ip_vs_conn_new(&p, dest->af, &dest->addr, dest->port ? dest->port : vport, flags, dest, skb->mark);

另外,创建bypass类型的连接结构时,连接结构的flags成员也根据以上相同的判读,决定是否设置IP_VS_CONN_F_ONE_PACKET标志。

int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph)
{if (sysctl_cache_bypass(ipvs) && svc->fwmark && ...)) {unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && iph->protocol == IPPROTO_UDP) ? IP_VS_CONN_F_ONE_PACKET : 0;{ip_vs_conn_fill_param(svc->ipvs, svc->af, iph->protocol, &iph->saddr, pptr[0], &iph->daddr, pptr[1], &p);cp = ip_vs_conn_new(&p, svc->af, &daddr, 0, IP_VS_CONN_F_BYPASS | flags, NULL, skb->mark);

再者,在创建Persistent连接时,也会做如上的判断,决定是否为连接flags增加OPS标志IP_VS_CONN_F_ONE_PACKET。

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)
{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);

但是在ip_vs_sched_persist函数中创建Persistent的模板连接时,其连接结构的flags固定设置IP_VS_CONN_F_TEMPLATE标志,可见模板连接与OPS无关。

    /* Check if a template already exists */ct = ip_vs_ct_in_get(&param);if (!ct || !ip_vs_check_template(ct, NULL)) {/* Create a template */ct = ip_vs_conn_new(&param, dest->af, &dest->addr, dport, IP_VS_CONN_F_TEMPLATE, dest, skb->mark);

这样,就保证了OPS可以同Persistent选项一同使用,即使OPS的每个连接仅调度一次,但是由于模板连接的存在,还是可以保证同一个客户端的请求调度到同一个真实服务器上。

# sudo ipvsadm -A -u 207.175.44.110:80 -s rr --ops --persistent 

OPS连接同步

对于仅执行一次调度的OPS连接,不需要同步到对端Slave,如下函数ip_vs_sync_conn中的判断。但是如果此OPS连接关联有控制模板连接,因为模板连接是可能长时间存在的,执行模板连接的同步。

void ip_vs_sync_conn(struct netns_ipvs *ipvs, struct ip_vs_conn *cp, int pkts)
{/* Do not sync ONE PACKET */if (cp->flags & IP_VS_CONN_F_ONE_PACKET)goto control;sloop:if (!ip_vs_sync_conn_needed(ipvs, cp, pkts))...control:/* synchronize its controller if it has */cp = cp->control;if (!cp) return;goto sloop;

OPS连接操作

在IPVS的连接创建函数ip_vs_conn_new中,最后将创建好的连接插入到全局链表ip_vs_conn_tab中。

struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,const union nf_inet_addr *daddr, __be16 dport, unsigned int flags, struct ip_vs_dest *dest, __u32 fwmark)
{/* Hash it in the ip_vs_conn_tab finally */ip_vs_conn_hash(cp);return cp;

以下为链表插入函数,可见,对于设置了IP_VS_CONN_F_ONE_PACKET标志的连接结构,不执行插入操作,直接返回了。加入全局链表会增加连接的计数到2,直接返回导致的后果是,此连接的引用计数为1,在IPVS调度完成之后,此连接将被释放。

static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
{if (cp->flags & IP_VS_CONN_F_ONE_PACKET)return 0;if (!(cp->flags & IP_VS_CONN_F_HASHED)) {cp->flags |= IP_VS_CONN_F_HASHED;refcount_inc(&cp->refcnt);hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]);

OPS连接的释放在函数ip_vs_in中,如下在连接执行完成报文发送函数之后,使用函数ip_vs_conn_put释放连接的引用计数。

static unsigned int ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)
{if (unlikely(!cp)) {if (!ip_vs_try_to_schedule(ipvs, af, skb, pd, &v, &cp, &iph))return v;}if (cp->packet_xmit)ret = cp->packet_xmit(skb, cp, pp, &iph);ip_vs_conn_put(cp);return ret;

对于OPS连接,由于其设置有IP_VS_CONN_F_ONE_PACKET标志,并且其引用计数等于1,在连接创建时仅初始化了连接定时器,并未启动,定时器并不处在pending状态,使用__ip_vs_conn_put_notimer函数处理。

void ip_vs_conn_put(struct ip_vs_conn *cp)
{if ((cp->flags & IP_VS_CONN_F_ONE_PACKET) && (refcount_read(&cp->refcnt) == 1) &&!timer_pending(&cp->timer))/* expire connection immediately */__ip_vs_conn_put_notimer(cp);

如下所示,调用__ip_vs_conn_put函数递减连接的引用计数,对于OPS连接此处将引用计数递减到零。之后,直接调用连接定时器的超时处理函数ip_vs_conn_expire,处理连接的释放。

static void __ip_vs_conn_put_notimer(struct ip_vs_conn *cp)
{__ip_vs_conn_put(cp);ip_vs_conn_expire(&cp->timer);
}
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
{smp_mb__before_atomic();refcount_dec(&cp->refcnt);
} 

如下为超时处理函数逻辑,由于OPS连接并没有连接到全局链表中,所以ip_vs_conn_unlink解除链接函数总是成功。接着将执行以下的清理工作,释放连接。

static void ip_vs_conn_expire(struct timer_list *t)
{if (likely(ip_vs_conn_unlink(cp))) {del_timer(&cp->timer);if (cp->control)ip_vs_control_del(cp);if ((cp->flags & IP_VS_CONN_F_NFCT) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET)) {smp_rmb();if (ipvs->enable) ip_vs_conn_drop_conntrack(cp);}if (unlikely(cp->app != NULL)) ip_vs_unbind_app(cp);ip_vs_unbind_dest(cp);if (cp->flags & IP_VS_CONN_F_NO_CPORT)atomic_dec(&ip_vs_conn_no_cport_cnt);if (cp->flags & IP_VS_CONN_F_ONE_PACKET)ip_vs_conn_rcu_free(&cp->rcu_head);elsecall_rcu(&cp->rcu_head, ip_vs_conn_rcu_free);atomic_dec(&ipvs->conn_count);return;

OPS连接随机删除

函数ip_vs_conn_ops_mode用于判断连接所关联的虚拟服务是否设置了IP_VS_SVC_F_ONEPACKET标志,以及此连接是否关联了目的服务器,以上条件都成立的话,返回真。

static inline bool ip_vs_conn_ops_mode(struct ip_vs_conn *cp)
{struct ip_vs_service *svc;if (!cp->dest)return false;svc = rcu_dereference(cp->dest->svc);return svc && (svc->flags & IP_VS_SVC_F_ONEPACKET);

目前仅在函数ip_vs_random_dropentry中使用到以上的连接是否为OPS的判断函数,如下,如果在判断的连接为一个模板连接,即设置了IP_VS_CONN_F_TEMPLATE标志,并且其所控制的派生连接数不为空,不能删除此连接。或者,其派生的连接为空,但是此连接不是OPS连接,也不能删除它。

即如果OPS的模板连接,没有派生连接的话,在ip_vs_random_dropentry函数中是可以将其删除的。

void ip_vs_random_dropentry(struct netns_ipvs *ipvs)
{for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) {unsigned int hash = prandom_u32() & ip_vs_conn_tab_mask;hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {if (cp->ipvs != ipvs)continue;if (cp->flags & IP_VS_CONN_F_TEMPLATE) {if (atomic_read(&cp->n_control) || !ip_vs_conn_ops_mode(cp))continue;

内核版本 4.15

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



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

相关文章

搭建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

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

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

【Linux】探索进程优先级的奥秘,解锁进程的调度与切换

目录 进程优先级: 是什么? 为什么存在进程优先级的概念呢? Linux为什么调整优先级是要受限制的? PRI vs NICE Linux的调度与切换 概念准备: 那我们到底怎样完成进程的调度和切换呢? 区分:寄存器VS寄存器的内容 Linux实现进程调度的算法,需要考虑优先级,考虑进程饥饿问题,考虑效率问题。 解决优先级问题: 解决进程饥饿问题: 解决效率的问题:

k8s调度(pod亲和、反亲和、污点、容忍度)

pod亲和性 针对对象为Pod,目的是实现,新建Pod和目标Pod调度到一起,在同一个Node上。 示例: apiVersion: v1kind: Podmetadata:name: testpod01labels:app: myapp01env: test1spec:containers:- name: testpod01image: nginx:1.23.2---apiVersio

黑马程序员---银行业务调度系统

模拟实现银行业务调度系统逻辑 需求分析: 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口。 有三种对应类型的客户:VIP客户,普通客户,快速客户(办理如交水电费、电话费之类业务的客户)。 异步随机生成各种类型的客户,生成各类型用户的概率比例为:         VIP客户 :普通客户 :快速客户 =  1:6:3。 客户办理业务所

RMS调度详解

1.RMS调度简介 任务按单调速率优先级分配(RMPA)的调度算法,称为单调速率调度(RMS)。RMPA是指任务的优先级按任务周期T来分配。它根据任务的执行周期的长短来决定调度优先级,那些具有小的执行周期的任务具有较高的优先级,周期长的任务优先级低。 2.RMS调度实现介绍 SylixOS目前关于RMS调度分为创建、删除、调度三个部分组成。创建和删除就不予介绍。重点关注下调度算法的实现。调度

Kubernetes Scheduler:Pod调度的双步骤—预选(Predicates)和优选(Priorities)

Kubernetes Scheduler:Pod调度的双步骤—预选(Predicates)和优选(Priorities) 1、预选(Predicates)2、优选(Priorities) 💖The Begin💖点点关注,收藏不迷路💖 在Kubernetes中,Pod的调度是由Scheduler负责的。Scheduler通过两个关键步骤——预选(Predicat

【蓝桥杯嵌入式(一)程序框架和调度器】

蓝桥杯嵌入式(一)程序框架和调度器 序、代码命名规则零、STM32和8051⼀、软件及环境安装⼆、⼯程框架搭建1.时钟配置2、SYS配置3、⼯程配置4、NVIC配置5.、Keil配置 三、系统初始化四、任务调度器 链接: 视频出处 序、代码命名规则 以下是一些常见的举例 零、STM32和8051 链接: 8位和32位单片机最本质区别 ⼀、软件及环境安装