ip_vs实现分析(9)

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: [email protected]
来源:http://yfydz.cublog.cn


11. IPVS预估器

IPVS预估器用的估算在一个短暂时间间隔内的连接率,可在用户空间开一个daemon定时读取预估器的值以实现较长时间的预估。
预估算法为:
取最后8秒钟内,每两秒取一个采样点进行平滑处理:
    avgrate = avgrate*(1-W) + rate*W
    其中 W = 2^(-2) = 0.25,速率单位是KBytes/s

预估代码在net/ipv4/ipvs/ip_vs_est.c中实现。

11.1 数据结构
预估器结构定义如下:

struct ip_vs_estimator
{
// 链表的下一项
 struct ip_vs_estimator *next;
// IPVS统计
 struct ip_vs_stats *stats;
// 上次的连接数
 u32   last_conns;
// 上次的进入包数
 u32   last_inpkts;
// 上次发出包数
 u32   last_outpkts;
// 上次进入字节数
 u64   last_inbytes;
// 上次发出字节数
 u64   last_outbytes;
// 连接率
 u32   cps;
// 进入的包数率
 u32   inpps;
// 发出的包速率
 u32   outpps;
// 进入的速率
 u32   inbps;
// 发出的速率
 u32   outbps;
};

11.2 新建预估器

int ip_vs_new_estimator(struct ip_vs_stats *stats)
{
 struct ip_vs_estimator *est;
// 分配空间
 est = kmalloc(sizeof(*est), GFP_KERNEL);
 if (est == NULL)
  return -ENOMEM;
 memset(est, 0, sizeof(*est));
// 统计结构,包括IPVS服务,目的服务器等都有这个统计结构,预估器就是根据此统计值计算
 est->stats = stats;
// 将当前统计结构中的值作为预估器中的参数初始值
 est->last_conns = stats->conns;
// 连接率值扩大2^10
 est->cps = stats->cps<<10;
 est->last_inpkts = stats->inpkts;
// 进入包速率值扩大2^10
 est->inpps = stats->inpps<<10;
 est->last_outpkts = stats->outpkts;
// 发出包速率值扩大2^10
 est->outpps = stats->outpps<<10;
 est->last_inbytes = stats->inbytes;
// 进入速率值扩大2^5
 est->inbps = stats->inbps<<5;
 est->last_outbytes = stats->outbytes;
// 发出速率值扩大2^5
 est->outbps = stats->outbps<<5;
 write_lock_bh(&est_lock);
// 将结构加入链表
 est->next = est_list;
 if (est->next == NULL) {
// 初始化定时器,整个链表只有一个定时器
  init_timer(&est_timer);
// 超时两秒
  est_timer.expires = jiffies + 2*HZ;
  est_timer.function = estimation_timer;
  add_timer(&est_timer);
 }
 est_list = est;
 write_unlock_bh(&est_lock);
 return 0;
}
// 定时函数,预估计算
static void estimation_timer(unsigned long arg)
{
 struct ip_vs_estimator *e;
 struct ip_vs_stats *s;
 u32 n_conns;
 u32 n_inpkts, n_outpkts;
 u64 n_inbytes, n_outbytes;
 u32 rate;
 read_lock(&est_lock);
// 循环预估链表对所有预估器数据进行更新
 for (e = est_list; e; e = e->next) {
  s = e->stats;
  spin_lock(&s->lock);
// 当前统计结构中的新数值
  n_conns = s->conns;
  n_inpkts = s->inpkts;
  n_outpkts = s->outpkts;
  n_inbytes = s->inbytes;
  n_outbytes = s->outbytes;
  /* scaled by 2^10, but divided 2 seconds */
// 连接率计算
// 1秒内的连接数之差,扩大2^10
  rate = (n_conns - e->last_conns)<<9;
// 保存连接数
  e->last_conns = n_conns;
// 预估器连接率变化
  e->cps += ((long)rate - (long)e->cps)>>2;
// 统计结构的连接率变化
  s->cps = (e->cps+0x1FF)>>10;

// 进入包率计算,方法和上面相同
  rate = (n_inpkts - e->last_inpkts)<<9;
  e->last_inpkts = n_inpkts;
  e->inpps += ((long)rate - (long)e->inpps)>>2;
  s->inpps = (e->inpps+0x1FF)>>10;

// 发出包率计算,方法和上面相同
  rate = (n_outpkts - e->last_outpkts)<<9;
  e->last_outpkts = n_outpkts;
  e->outpps += ((long)rate - (long)e->outpps)>>2;
  s->outpps = (e->outpps+0x1FF)>>10;
// 进入字节流量率计算,方法和上面相同
  rate = (n_inbytes - e->last_inbytes)<<4;
  e->last_inbytes = n_inbytes;
  e->inbps += ((long)rate - (long)e->inbps)>>2;
  s->inbps = (e->inbps+0xF)>>5;
// 进入字节流量率计算,方法和上面相同
  rate = (n_outbytes - e->last_outbytes)<<4;
  e->last_outbytes = n_outbytes;
  e->outbps += ((long)rate - (long)e->outbps)>>2;
  s->outbps = (e->outbps+0xF)>>5;
  spin_unlock(&s->lock);
 }
 read_unlock(&est_lock);
 mod_timer(&est_timer, jiffies + 2*HZ);
}

11.3 删除预估器
void ip_vs_kill_estimator(struct ip_vs_stats *stats)
{
 struct ip_vs_estimator *est, **pest;
 int killed = 0;
 write_lock_bh(&est_lock);
// 链表头
 pest = &est_list;
// 循环根据参数提供的统计结构地址查找预估器
 while ((est=*pest) != NULL) {
// 根据统计地址比对
  if (est->stats != stats) {
   pest = &est->next;
   continue;
  }
  *pest = est->next;
// 直接释放预估器内存
  kfree(est);
  killed++;
 }
// 预估链表为空后删除定时器
 if (killed && est_list == NULL)
  del_timer_sync(&est_timer);
 write_unlock_bh(&est_lock);
}
 
11.4 预估器统计值清零
void ip_vs_zero_estimator(struct ip_vs_stats *stats)
{
 struct ip_vs_estimator *e;
 write_lock_bh(&est_lock);
// 循环根据参数提供的统计结构地址查找预估器
 for (e = est_list; e; e = e->next) {
  if (e->stats != stats)
   continue;
// 将预估器参数值清空
  /* set counters zero */
  e->last_conns = 0;
  e->last_inpkts = 0;
  e->last_outpkts = 0;
  e->last_inbytes = 0;
  e->last_outbytes = 0;
  e->cps = 0;
  e->inpps = 0;
  e->outpps = 0;
  e->inbps = 0;
  e->outbps = 0;
 }
 write_unlock_bh(&est_lock);
}
 
12. IPVS的/proc参数
IPVS在/proc目录下建立了以下文件:
/proc/net:
 /proc/net/ip_vs:IPVS的规则表
 /proc/net/ip_vs_app:IPVS应用协议
 /proc/net/ip_vs_conn:IPVS当前连接
 /proc/net/ip_vs_stats:IPVS状态统计信息
/proc/sys/net/ipv4/vs:
 /proc/sys/net/ipv4/vs/am_droprate:丢包率(缺省10)
 /proc/sys/net/ipv4/vs/amemthresh:可用内存阈值(缺省1024)
 /proc/sys/net/ipv4/vs/cache_bypass:是否建立旁路cache项
 /proc/sys/net/ipv4/vs/debug_level:调试级别
 /proc/sys/net/ipv4/vs/drop_entry:确定删除连接处理级别
 /proc/sys/net/ipv4/vs/drop_packet:丢包级别
 /proc/sys/net/ipv4/vs/expire_nodest_conn:是否删除没有目的服务器的连接
 /proc/sys/net/ipv4/vs/lblc_expiration:lblc算法的到期时间(缺省1天)
 /proc/sys/net/ipv4/vs/lblcr_expiration:lblcr算法的到期时间(缺省1天)
 /proc/sys/net/ipv4/vs/nat_icmp_send:NAT模式下连接异常时发送ICMP包
 /proc/sys/net/ipv4/vs/secure_tcp:更安全的TCP状态转换
 /proc/sys/net/ipv4/vs/sync_threshold:连接同步时的包数阈值数值
 /proc/sys/net/ipv4/vs/timeout_close:TCP sCL状态超时
 /proc/sys/net/ipv4/vs/timeout_closewait:TCP sCW状态超时
 /proc/sys/net/ipv4/vs/timeout_established:TCP sES状态超时
 /proc/sys/net/ipv4/vs/timeout_finwait:TCP sFW状态超时
 /proc/sys/net/ipv4/vs/timeout_icmp:ICMP超时
 /proc/sys/net/ipv4/vs/timeout_lastack:TCP sLA状态超时
 /proc/sys/net/ipv4/vs/timeout_listen:TCP sLI状态超时
 /proc/sys/net/ipv4/vs/timeout_synack:TCP sSA状态超时
 /proc/sys/net/ipv4/vs/timeout_synrecv:TCP sSR状态超时
 /proc/sys/net/ipv4/vs/timeout_synsent:TCP sSS状态超时
 /proc/sys/net/ipv4/vs/timeout_timewait:TCP sTW状态超时
 /proc/sys/net/ipv4/vs/timeout_udp:UDP超时

你可能感兴趣的:(IP)