设为首页 加入收藏

TOP

IPVS基于应用层任意偏移字段HASH值的负载均衡算法(四)
2015-02-13 18:23:36 来源: 作者: 【 】 浏览:153
Tags:IPVS 基于 应用层 任意 HASH 负载 均衡 算法
vailable\n");?
? ? ? ? return NULL;?
? ? }?
?
? ? return dest;?
}?
?
static struct ip_vs_scheduler ip_vs_offh_scheduler =?
{?
? ? .name =? ? ? ? "offh",?
? ? .refcnt =? ? ? ATOMIC_INIT(0),?
? ? .module =? ? ? THIS_MODULE,?
? ? .n_list? =? ? ? LIST_HEAD_INIT(ip_vs_offh_scheduler.n_list),?
? ? .init_service =? ? ip_vs_offh_init_svc,?
? ? .done_service =? ? ip_vs_offh_done_svc,?
? ? .update_service =? ip_vs_offh_update_svc,?
? ? .schedule =? ? ip_vs_offh_schedule,?
};?
?
static ssize_t ipvs_sch_offset_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)?
{?
? ? int ret = 0;?
? ? ret = sprintf(buf, "offset:%u;offlen:%u\n", offset, offlen);?
? ? return ret;?
}?
?
/*?
?* 设置offset/offset length?
?* echo offset:$value1? offlen:$value2 >/proc/net/ipvs_sch_offset?
?*/?
static int ipvs_sch_offset_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)?
{?
? ? int ret = count;?
? ? char *p = buf, *pstart;?
? ? if ((p = strstr(p, "offset:")) == NULL) {?
? ? ? ? ret = -EINVAL;?
? ? ? ? goto out;?
? ? }?
? ? p += strlen("offset:");?
? ? pstart = p;?
? ? if ((p = strstr(p, " ")) == NULL) {?
? ? ? ? ret = -EINVAL;?
? ? ? ? goto out;?
? ? }?
? ? p[0] = 0;?
? ? offset = skip_atoi(&pstart);?
? ? if (offset == 0 && strcmp(pstart, "0")) {?
? ? ? ? ret = -EINVAL;?
? ? ? ? goto out;?
? ? }?
? ? p += strlen(";");?
? ? if ((p = strstr(p, "offlen:")) == NULL) {?
? ? ? ? ret = -EINVAL;?
? ? ? ? goto out;?
? ? }?
? ? p? += strlen("offlen:");?
? ? pstart = p;?
? ? offlen = skip_atoi(&pstart);?
? ? if (offlen == 0 && strcmp(pstart, "0")) {?
? ? ? ? ret = -EINVAL;?
? ? ? ? goto out;?
? ? }?
out:?
? ? return ret;?
}?
?
/*?
?* 由于不想修改用户态的配置接口,还是觉得procfs这种方式比较靠普?
?**/?
static const struct file_operations ipvs_sch_offset_file_ops = {?
? ? .owner? ? ? ? ? = THIS_MODULE,?
? ? .read? ? ? ? ? = ipvs_sch_offset_read,?
? ? .write? ? ? ? ? = ipvs_sch_offset_write,?
};?
?
struct net *net = &init_net;?
static int __init ip_vs_offh_init(void)?
{?
? ? int ret = -1;?
? ? if (!proc_create("ipvs_sch_offset", 0644, net->proc_net, &ipvs_sch_offset_file_ops)) {?
? ? ? ? printk("OFFH: create proc entry failed\n");?
? ? ? ? goto out;?
? ? }?
? ? return register_ip_vs_scheduler(&ip_vs_offh_scheduler);?
out:?
? ? return ret;?
}?
?
static void __exit ip_vs_offh_cleanup(void)?
{?
? ? remove_proc_entry("ipvs_sch_offset", net->proc_net);?
? ? unregister_ip_vs_scheduler(&ip_vs_offh_scheduler);?
}?
?
?
module_init(ip_vs_offh_init);?
module_exit(ip_vs_offh_cleanup);?
MODULE_LICENSE("GPL");?


实际上,很多高大上的负载均衡实现都不是基于内核协议栈的,它们要么是直接用硬卡来做,要么是用户态协议栈,所以本文的原则也是可以用到那些方面的,只不过,我所能为力的并且简单的只有Linux IPVS,毕竟先把代码跑起来要比长篇大论好的多,起码我是这么认为的。


4.问题在哪里-连接缓存


我认为IPVS机制该改了,同时我觉得nf_conntrack也该改了。


我们知道,在IPVS中,可能只有一个流的第一个数据包才会去调用“特定协议”的conn_schedule回调,选出一个destination,即real server之后,这些信息就会被保存在“特定协议‘的conn缓存中。如果你看一下这个所谓的“特定协议”,就会发现它事实上是“第四层协议”,即传输层协议,TCP或者UDP,而在这一层,很显然,一个连接就是一个5元组。那么,即便我针对第一个数据包,即一个流的首包选择了一个real server,并将其存入了conn缓存,那么该流的客户端在IP地址变化了之后,显然conn缓存中找不到了,那么就会自动进入conn_schedule,由于使用固定偏移的paylaod进行schedule,那么肯定还是原来的那个real server被选择,此时会在conn缓存中增加一条新的条目用于以后的匹配,老的那条conn缓存没有用了,等待过期,只要客户端不改变IP地址且新的这个conn缓存项不过期,这个缓存将会一直命中,一旦客户端改变了IP地址,一切重新开始。可见,这是一个自动且正确的过程。但是,最好有一个针对旧五元组的删除通知机制,而不是等待它自己过期。


如果等待它自己过期,那么试想一种超时时间很久的情况。客户端A五元组为tuple1使用sessionID1匹配到了一个real server1,设置了conn缓存conn1,过了一些时间,客户端A更换了IP地址,此时理所当然地,它不会再匹配到conn1,缓存不命中,依靠不变的sessionID1它在conn_schedule中选择了同样的real server1,设置了新的conn2缓存项,然后conn1就变成僵尸了,等待超时删除。过了很久,客户端2携带接管了客户端1的老的IP地址和UDP端口,访问了同样的UDP服务,

首页 上一页 1 2 3 4 下一页 尾页 4/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇eclipse:报错信息The superclass .. 下一篇Qt Webkit初学例子(附代码)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: