Categories

Varnish的Hash负载均衡器开发总结

大二上学期就立了一个项目,要Varnish-2.0.4加入一个Hash的负载均衡算法(或者叫做负载均衡器)。这样可以在大规模服务器机群中为http请求快速找到空闲的后端服务器,提高http请求响应速度。
因为各种琐碎的事情以及自己和项目小组的拖拖拉拉,终于在第二学期末才把这个项目完成。不过遗憾的是,在我们完成之前,Varnish开发团队已经推出了Varnish版本2.1.0,在这个版本里已经实现了。在此将我们的实现方式与专业的Varnish团队的实现方法作以对比。当做总结和学习。
要使用Varnish负载均衡器,首先用户需要在配置文件中加入了相应的“director”关键字(2.0.4版中只有random和round-robin均衡器),并用VCL语言为此“director”分配好后端服务器。举例如下:
backend breadtalk {
.host = “202.102.58.241″;
.port = “80″;
}
director footoo round-robin {
{ .backend = { .host = “210.51.**.**”; .port = “80″; } }
{ .backend = { .host = “221.231.**.**”; .port = “80″; } }
{ .backend = { .host = “210.51.**.**”; .port = “80″; } }
}
当Varnish启动时配置文件被VCL_complier解析,将包含director的所有配置信息,转化成C语言函数写入一个临时文件中,编译此文件生成动态链接库,供响应Http请求时选取相应策略。
下面先从配置文件的解析开始,对实现的方法进行比较。
在我们的实现方式中,在vcc_backend.c文件中director的解析列表里加入“ip-hash”关键字。调用加入的函数vcc_ParseIpHashDirector对director ip-hash的配置进行解析,将ip-hash的配置转化成C语言代码,加入临时文件中。
在Varnish-2.1.0的实现中,通过在director的解析列表中加入“hash”关键字,并用vcc_ParseRandomDirector函数进行解析,然后将hash的配置转成C语言代码加入临时C文件。vcc_ParseRandomDirector在Varnish-2.0.4中已经存在,2.1.0中对它的实现进行了修改。通过加入标志字来区别random和hash的均衡器。
解析完成,之后就是算法的具体实现部分了。
我们的均衡器,是提取将每次会话所得的sess结构体中所存储的来访ip信息,之后将ip信息的4个段一起求CRC32码,将所得的hash值对后端机群数量求模。所得的值即为响应此ip的后端服务器序号(此序号按照director配置的次序依次为0,1,2,…)。如果对应服务器不能正常响应,均衡器会按照round-robin的方式进行调度,找到能正常响应的后端服务器。Varnish-2.0.4中的sess存储ip的成员是“char * addr”,我们在求CRC32之前,首先对地址进行了转码,将字符串转化成4段的unsigned char 型ip地址。
具体实现代码如下:

static struct vbe_conn *
vdi_ip_hash_getfd(struct sess *sp){
unsigned char dst[5] = {0, 0, 0, 0, '\0'};
get_ip(sp->addr, dst);//这里将字符型的ip地址,转化成4个数字
unsigned char *p = dst;

struct vdi_ip_hash *vs;
struct backend *backend;
struct vbe_conn *vbe;

CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, sp->director->priv, VDI_IP_HASH_MAGIC);

unsigned int regi = get_crc32(p);

backend = vs->hosts[regi % vs->nhosts].backend;
if(backend->healthy){
vbe = VBE_GetVbe(sp, backend);
if(vbe != NULL){
return (vbe);
}
}
if(!backend->healthy || vbe == NULL){
printf("!backend->healthy || vbe == NULL\n");
int i;
for (i = 0; i < vs->nhosts; i++) {
backend = vs->hosts[vs->next_host].backend;
vs->next_host = (vs->next_host + 1) % vs->nhosts;
if (!backend->healthy){
continue;
}
vbe = VBE_GetVbe(sp, backend);
if (vbe != NULL){
return (vbe);
}
}
}
return (NULL);
}

2.1.0的实现方式中,它用来保存会话信息的sess结构体中已经增加了“unsigned char digital[4]”成员,此数组中已经存储了4段的unsigned char型ip地址。2.1.0直接利用此ip求hash值,并利用此ip值定位到能够正常响应的后端服务器上。如果所定位的后端服务器无法正常响应,Varnish会在后端其它服务器中进行随机查找,直到找到正常的为止。
具体实现代码如下:

static struct vbe_conn *
vdi_random_getfd(const struct director *d, struct sess *sp)
{
int i, k;
struct vdi_random *vs;
double r, s1;
unsigned u = 0;
struct vbe_conn *vbe;
struct director *d2;
struct SHA256Context ctx;
unsigned char sign[SHA256_LEN], *hp;

CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC);

if (vs->criteria == c_client) {
SHA256_Init(&ctx);
AN(sp->addr);
SHA256_Update(&ctx, sp->addr, strlen(sp->addr));
SHA256_Final(sign, &ctx);
hp = sign;
}
if (vs->criteria == c_hash) {
hp = sp->digest;
}
if (vs->criteria != c_random) {
u = hp[3] << 24;
u |= hp[2] << 16;
u |= hp[1] << 8;
u |= hp[0] << 0;
r = u / 4294967296.0;
assert(r >= 0.0 && r < 1.0);
r *= vs->tot_weight;
s1 = 0.0;
for (i = 0; i < vs->nhosts; i++) {
s1 += vs->hosts[i].weight;
if (r >= s1)
continue;
d2 = vs->hosts[i].backend;
if (!VBE_Healthy_sp(sp, d2))
break;
vbe = VBE_GetFd(d2, sp);
if (vbe != NULL)
return (vbe);
break;
}
}
for (k = 0; k < vs->retries; ) {
s1 = 0.0;
for (i = 0; i < vs->nhosts; i++) {
d2 = vs->hosts[i].backend;
if (VBE_Healthy_sp(sp, d2))
s1 += vs->hosts[i].weight;
}
if (s1 == 0.0)
return (NULL);
if (vs->criteria != c_random) {
r = u / 4294967296.0;
} else {
r = random() / 2147483648.0; /* 2^31 */
}
assert(r >= 0.0 && r < 1.0);
r *= s1;
s1 = 0.0;
for (i = 0; i < vs->nhosts; i++) {
d2 = vs->hosts[i].backend;
if (!VBE_Healthy_sp(sp, d2))
continue;
s1 += vs->hosts[i].weight;
if (r >= s1)
continue;
vbe = VBE_GetFd(d2, sp);
if (vbe != NULL)
return (vbe);
break;
}
k++;
}
return (NULL);
}

这里的每个服务器用到了weight这个属性,这是Varnish-2.0.4中配置random director时就存在的一个属性,描述某台后端服务器被选取的权重。权重大的,被选取的几率增大。
以上两处为Varnish负载均衡器最核心内容,生成C文件后进行动态编译、调用的方式相同。
两种方式的实现方式差别并不是很大,但是比较可以发现Varnish团队推出的Varnish-2.1.0版本中hash均衡器的实现,整合性比较强,并且直接利用到原有的random均衡器的很多实现方式,这样的做法比较方便。我们的实现方式中,重写了专属于ip-hash的结构体和一些辅助函数,工作量较之2.1.0会有所增多,但是这种方式能够把模块化做的比较好,有利于今后功能的改进和扩展。
通过这个项目的实践,我们读开源代码的能力明显得到了提高,而且对于负载均衡的概念也有了比较深的理解,对于开源web服务器的工作原理以及代码实现有了进一步的认识,真是受益匪浅。
最后,感谢在一起开发Varnish哈希均衡器的兄弟们,感谢我们的指导老师,大二的生活因为你们而变得充实而精彩!

Blog主题更新,新添邮件订阅功能

blog的主题已更新,欢迎大家发送一些大家觉得好看的,好玩的,能反映俱乐部生活的照片到ibmtc的邮件列表中。经过大家筛选后的图片会被用来替换现有的网站头部图片。
此外,新添加了邮件订阅功能,在网站的右上角,只要提交你的email即可。
如果由什么更好的意见或建议请在下面留言…. :lol:

MeeGo试用小结

今天弄了一天INTEL发布的一个Linux版本Moblin(现在和Nokia合并,改名MeeGo)官方网站moblin.org。据说开机可以达到4s作用,但是只能在ATOM系统的cpu上跑起来,一般的pc就不要玩了。
说说感受,试用的是释放到u盘里面的镜像,开机速度没有体验到很快,但是对一些上网本常用的设备支持的还是比较好的,分辨率不太好,很多指令都没有,总体感觉一般,不太适合做开发,普通用户使用还可以,毕竟intel方面是说这个系统对atom做了特殊的优化。
安装的方式,主要有两种,1将镜像释放到优盘,和unetbontin一样,跟livecd效果差不多,这样就可以试用了,(也可以安装)我安装到另一u盘里面了(2g以上,不然装不上)然后启动就卡在开机画面,不能正常启动(杯具)。2在Ubuntu或是Fedora上虚拟出一个开发环境,可以用moblin toolchain,也可用chroot,后者似乎更常用,moblin toolchain只要按着手册做就可以了,没有什么问题,用chroot,会遇到一些麻烦,而且官方的手册上有些是错误的!~
chroot过程(1)按着必要的开发工具:对于Ubuntu,若是用了一段时间,基本的工具都有了,没有就aptitude或是apt-get,下载moblin image creator 2(后来我发现这个也可以apt,再不行还有.deb包)编译安装,可能会发现依赖关系不满足,上网搜了一些,要的那些包多是Fedora有的,恶!所以直接装deb好了。然后就是将.iso的镜像释放到自定义的一个目录下,如果提示该目录存在,就moblin-rm-chroot-dir一下。然后就可以chroot到moblin里了,可以试着编一些小程序,不过若是编写内核驱动或是涉及到相关东西的程序就会发现编译不能通过,因为moblin的内核是chroot之后解压到指定文件夹得,而宿主系统的内核基本不可能与它的内核同一个版本,所以会有问题。总体感觉这个过程像LFS的缩减版,要想玩明白这个步骤推荐自己动手做一下LFS就OK.好了,就这么多了,有什么新发现我会及时补充的!

FoOTOo Group Blog 升级

今天下午在cliff的大力协助下,FoOTOo Group Blog从原来的wordpress 2.0升级到了wordpress 2.9.2.
升级了反垃圾评论插件Akismet,同时新添加了如下插件:
1.All in one SEO
具有标准化titile结构,自动生成关键字,自动生成页面表述等功能,方便网站被搜索引擎收录。
2.Baidu_Sitemap
生成baidu站点地图(http://blog.cs.hit.edu.cn/sitemap.html),并在连接表中添加站点地图,方便baidu爬虫访问。
3.Smilies
添加文章,评论的表情。
4.XML sitemap
生成google站点地图并提交,方便网站在做修改后立即被google收录。

同时在/blog下创建robots.txt,方便提交站点地图:

  1. User-agent: *
  2. Disallow:
  3. Sitemap: http://blog.cs.hit.edu.cn/sitemap.html
  4. Sitemap: http://blog.cs.hit.edu.cn/sitemap.xml

同时为了浏览方便,把每个页面的文章数从15改成了5.

如果大家对FoOTOo Group Blog有什么改进的建议,请在下面的评论中留言,thaks.

《Linux 101 Hacks》中文版发布

好事多磨!去年已经翻译完毕的《Linux 101 Hacks》因为种种原因,直到今天才正式发布。恰逢作者又对原书做了更新,我们又在三月初对更新的章节和内容进行了翻译,目前与英文版本的内容一致。

中文版本中如果有任何问题,请直接与我联系,您可以在blog留言,也可以直接给我发送邮件。

点击下载《Linux 101 Hacks》中文版