PHP 文件锁 flock 负载均衡

最近有个项目,采用单台前端服务器提供Web服务,程序需要实时访问后端服务器。后端一共有几十台服务器,但有压力限制,单台负载不能过高,必须做负载均衡。

最简单的方式是用随机数,前端来请求的时候,随机挑选一台后端服务器,但这并不能保证压力平均分布,很有可能在某一段时间内请求都落到同一台服务器上,很容易导致这台服务器停止服务。

后来想到用文件锁的方式,来标记访问计数,顺序访问后端的每一台服务器,让每一台服务器一个周期只被访问一次。

在进行了多次功能测试和压力测试后,验证了这种想法的可行性,然后写了一个IDService类,封装了整个过程。

我在Google提供的SVN服务器上保存了源码,大家可以在

http://leakon.googlecode.com/svn/trunk/leakon/php/flock/flock.php

这个地址看到源码,或者用SVN工具CheckOut到本地。

核心过程,就是初始化的时候给一个ID范围,默认是从0开始,如果你的server_count是32,那么调用getId()方法的时候,我会顺序给你31至0这32个ID,采用文件锁就是考虑到并发请求之间彼此独立,一个进程读数据文件的时候要加独占锁,解锁前,其他进程无法读取数据文件。

ID分配给你了,每个ID对应哪个服务器,就是你自己做映射的事了,保证了这个模块的无关性和独立性,和其他所有模块保持无耦合。

这是在PHP5的环境下写的,const 定义了3个类常量:

LINE_FEED 是换行符,Windows 下是 \r\n,Linux 下是 \n,只是为了方便测试的时候实时查看数据,可以是任意字符,只要不是数字就OK;

MAX_LOAD 是计数器的最大值,计数器都是从0开始,如果有任何一个ID达到了最大值,则所有ID计数器全部归零,开始新的一轮计数,其实这个设置只要大于0就可以,最好不要太大,因为存储数字也是要占用存储空间的,越小,id_data_file的尺寸就越小,硬盘读取就越快;

DATA_BLOCK 是设置一次读文件的数据大小,硬盘的一个文件至少要占一个簇,一般文件系统一个簇是4K,这个取值要跟ID的总量有关系,如果你的LINE_FEED是\n,MAX_LOAD是99(采用文本方式存储,2字节),那么一个ID占用3个字节,如果你有100个ID,那么数据文件占用空间就是300Byue,因此DATA_BLOCK设置为300是最佳值,需要注意,如果ID范围变大,需要同步更改此值,因此我默认设置了2048字节,小于硬盘的一个簇,相对于300字节来说没有性能损失,因为都在一个簇内,数据存储是连续的,硬盘只需一次寻道和一次读写。

源码里有使用说明,很简单,在实例化对象的时候指定ID范围和数据文件位置即可。

已经经过测试,给一些压力测试数据吧:

在AMD3000+和7200转80G硬盘的台式机环境,可以提供到 1300+次/秒 的速度,此时磁盘IO是瓶颈;
换上Linux服务器,具体配置不太清楚,反正是SCSI硬盘,100多G,只是开发用机,性能并不高,但可以提供 5000+次/秒 的速度。

综合2中环境的测试数据,以目前前端服务器的最高负载(最高也就 200+次/秒),以及项目的实际负载,此代码性能足够满足需要。

1 comment

  1. 为什么不用现成的负载均衡的反向代理软件?
    Apache Lighttpd Nginx等都可以实现,调度的算法也已经比较成熟
    如果要使用Fair的调度方式,Apache haproxy可以限制到每台上游服务器的链接数
    效率应该更高

Leave a Reply

Your email address will not be published.

*