如下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调度相关推荐

  1. 一个IO的传奇一生 (9) -- Noop和Deadline调度器

    Linux中常见IO调度器 Noop调度器算法 Noop是Linux中最简单的调度器,这个调度器基本上没做什么特殊的事情,就是把邻近bio进行了合并处理.从IO的QoS角度来看,这个Noop调度器就是 ...

  2. ipvs负载均衡(三)ipvs三种工作方式

    IPVS负载均衡(三)IPVS三种工作方式之NAT模式 IPVS是LVS(Linux Virtual Server)项目重要组成部分,目前包含于官方Linux Kernel,IPVS依赖于netfil ...

  3. LVS负载均衡之ipvsadm部署安装(安装篇)

    在上一节我们讲到了关于lvs的工作原理,本节我们将会讲到关于lvs部署安装的相关细节,比如安装前的注意事项等等: Lvs是linux virtual server的缩写.虚拟的服务器.可以在Linux ...

  4. LVS集群应用配置详解

    一. 目录 关于集群的介绍. 什么是负载均衡以及为什么需要负载均衡. 负载均衡技术的特点. 负载均衡集群的常见解决方案. lvs介绍及管理工具. 实现lvs集群服务的三种类型方法介绍. LVS调度算法 ...

  5. K8S学习之service

    service 一种可以访问后端pod的策略,通过访问service来访问到service关联的后端pod,通常是通过Label Selector实现的. 在kubernetes集群中有三类ip地址: ...

  6. 轻量级 Kubernetes 集群发行版 K3s 完全进阶指南

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! 深入理解官方文档,轻松学会使用 K3S 工具! K3s 是一个轻量级的 Kubernetes 发行版,它针对边缘计 ...

  7. K3s 工具进阶完全指南

    ❝ 本文转自 Escape,原文:https://www.escapelife.site/posts/754ba85c.html,版权归原作者所有.欢迎投稿,投稿请添加微信好友:cloud-nativ ...

  8. Block multi-queue 架构解析(一)数据结构

    Linux块设备层已逐步切换到multiqueue , Linux5.0以后单队列代码已被完全移除.multiqueue核心思路是为每个CPU分配一个软件队列,为存储设备的每个硬件队列分配一个硬件派发 ...

  9. IPVS的Persistent持续调度

    如下ipvsadm配置命令,开启persistent选项之后,ipvs将来之同一个客户端的请求全部调度到一个固定的真实服务器上.对于SSL和FTP这类,其多个报文之间是相互关联的协议,需要开启此功能. ...

最新文章

  1. SpringBoot - 实践阿里巴巴【Manager 层_通用业务处理层】
  2. 学习Kotlin(五)函数与Lambda表达式
  3. 如何找到cache-control header是从后台何处设置的
  4. JAVA 笔记(三)
  5. 学术不端!211大学一名博士被撤销学位!
  6. java同时关闭两个窗口_在一个窗口中同时关闭多个窗口的问题(Swing中事件多点传送的问题) | 学步园...
  7. eclipse护眼颜色和字体大小设置
  8. 什么是 “动态规划” , 用两个经典问题举例。
  9. My SQL随记 001 常用名词/结构化语言
  10. 【python工具】获取linux和windows系统指定接口的IP地址
  11. IT Library第4期《备份域升为主域控制器》
  12. 用SecureCRT连接采用NAT方式上网的虚拟机
  13. python 修改图片_Python实现批量修改图片格式和大小的方法【opencv库与PIL库】
  14. C语言段错误的有用总结
  15. 对龙果支付系统的简单了解
  16. 2015年到2017年 国家自然基金有关深度学习和计算机视觉的部分项目
  17. 计算机操作系统只有windows对不对,计算机应用基础 第二章 操作系统
  18. 居家洁士扫地机器人_如何避免买到“智障”扫地机器人,看这篇
  19. 正点原子潘多拉上STlinkV2.1固件遇到的坑
  20. 搭建8086汇编语言学习环境——dosbox

热门文章

  1. 如何快速开发游戏服务端框架?
  2. css3基础100问之字体和文本有哪些属性和用法呢?(18)
  3. CVPR 2023放榜了!录用率25.78%!2360篇论文被接收
  4. Android 启动优化(一) - 有向无环图
  5. 计算机室的管理制度和管理职责,计算机教室管理制度和管理员职责.doc
  6. Android视频实时传输
  7. 对NFA和DFA的认识
  8. 解决Ubuntu系统关机时间过长
  9. 金蝶客户常见问题(一)
  10. python中字符串的两种序号体系_Python字符串 --Python3