设为首页 收藏本站
查看: 590|回复: 0

[经验分享] PHP处理海量数据实战

[复制链接]

尚未签到

发表于 2017-3-28 11:51:32 | 显示全部楼层 |阅读模式
  看了July的一些关于Java处理海量数据的问题研究,他的想法独到深刻,很值得我们学习http://blog.csdn.net/v_july_v/article/details/6685962
  wally_yu选择了其中的一道题验证,具体题目如下:
  

海量日志数据,提取出某日访问百度次数最多的那个IP。
  July给出的解决方法如下:
  

方案1:首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有2^32个IP。同样可以采用映射的方法,比如模1000,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率最大的几个)及相应的频率。然后再在这1000个最大的IP中,找出那个频率最大的IP,即为所求。
  wally_yu使用python模拟了July的想法,写的很详细具体,由于他在分割大文件的时候出现了一点点的BUG,所以最后他并没有采用分割大文件的方法。http://blog.csdn.net/quicktest/article/details/7453189#comments
  我借鉴了他的做法和博客的评论,使用PHP重新验证了July的思想。
  废话不多说,下手。

生成数据
  我构造了10万条IP,每一条ip以‘10.192’开头,并把这些数据保存到一个文本中,命名为file.txt.
  

function generageMassiveIPAddr($fileLaction, $numberOfLines)
{
// 打开此文件
$handle = fopen($fileLaction, 'a+');
$ip = '';
while ($numberOfLines) {
$ip .= '10.192.' . rand(0, 255) . '.' . rand(0, 255) . "\r\n";
$numberOfLines--;
}
fwrite($handle, $ip);
fclose($handle);
unset($handle);
}
// 生成了148KB的文件
generageMassiveIPAddr('./file.txt', 100000);


注意:生成数据的时候,每天记录必须换行,方便以后逐行读取。  我只生成了10万条数据,如果需要更多,可以自行修改。

处理思路

july提供的方法是“分而治之”,简单来说,就是使用一个HASH算法,把一个大文件拆分成若干个小文件,分割时需要考虑到内存的大小,因为我的生成的数据不大,所以也没有详细的计算,我就直接把这个大文件拆分了10个小文件。

wally_yu使用的HASH算法是,根据文件的大小来分割,这样会出现一个问题:每个ip可能在不同文件中都有记录,也许这个倒霉的ip是第一个文件的第二名,在第二个文件也是第二名,你用最大值进行比较,就会把这个倒霉的ip忽略掉,但其实这个ip才是真正的最大值。这就是wally_yu采用文件大小分割出现的bug.




我的做法如下:




1)分割大文件,我的HASH算法是:逐行读取大文件,把获取的IP转化成整形,取模10(这个数字是我随意定义的),根据取模10结果把ip存储到不同的文件中,这样就会保证ip不会出现在两个不同的文件中。

2)对小文件遍历,获取文件中出现频率次数最高的IP, 这样遍历10个小文件后,就可以获取到10这样IP,保存到一个数组里面,形式为:ip的具体值 => ip的出现次数。

3)对生成的数组排序,既可以获取到出现次数最大的IP

// 拆分文件, 根据ip hash拆分文件
function fileSplit($fileLaction, $num)
{
$handle = fopen($fileLaction, 'r');
if ($handle) {
while(! feof($handle)) {
// 去掉最后的换行符
$buffer = trim(fgets($handle));
$ip = ip2long($buffer);
// 分成num个文件
$i = $ip % $num;
$childHandle = fopen('child_' . $i . '.txt', 'a');
$buffer = $buffer . "\r\n";
fwrite($childHandle, $buffer);
fclose($childHandle);
}
}
fclose($handle);
unset($handle);
}



注意:这里的实现方式其实不大好,因为我每读取到一个IP,就写到文件,如果数据过大过多,这样硬盘的压力会比较大,有一个简单的做法,就是创建一个数组,下标为IP取模的值,保存将要写入文件的IP,当数组的长度大于一个值时,把数组的内容根据下标写入到不同的文件中。




对于PHP来说,操作文件后,注意销毁操作文件的资源。




遍历文件

以上步骤进行过后,会生成10个文件,需要遍历这些文件。 生成这些文件在同一个文件夹内,我们可以遍历这个文件夹,既可遍历所有的文件,假设 文件夹名为./web

代码如下:

function myGlob($targetFolder)
{
$filePath = $targetFolder . '/*.txt';
$files    = glob($filePath);
return $files;
}

获取小文件中ip出现次数最多一个



思路为:

1)初始化一个$ipValue 记录小文件中ip次数出现最多的那个IP的值 $ipMax 表示IP出现的次数。

2)构建名为“ip”的Dictionary,“key”为IP地址,“value”为该IP地址出现的次数,用来记录每一个小文件的所有IP地址

3)遍历文件的时候,同时,把$ipValue,$ipMax 更新为IP出现的次数最多的那个IP

4)构建名为“result”的Dictionary,“key”为IP地址,“value”为该IP地址出现的次数,用来记录11个文件每一个的最多出现的IP

5) 遍历result,即可以获取到IP

// 打开一个文件夹,遍历文件里面的各种子文件的内容
function findIp($targetFolder)
{
// 遍历文件夹
$files = myGlob($targetFolder);
// 用来统计每个子文件中出现次数最多的IP
$result = array();
foreach ($files as $file) {
// 用来统计每个文件的中各个IP出现的个数
$ip = array();
// 标识最大出现次数的ip的值
$ipValue = '';
// 标识这个iP出现的次数
$ipMax  = 0;
$handle = fopen($file, 'r');
if ($handle) {
while(! feof($handle)) {
// 去掉换行,这里需要特别注意
$buffer = trim(fgets($handle));
if (isset($ip[$buffer])) {
$ip[$buffer] = $ip[$buffer] + 1;
} else {
$ip[$buffer] = 1;
}
if ($ip[$buffer] > $ipMax) {
$ipMax = $ip[$buffer];
$ipValue = $buffer;
}
}
}
fclose($handle);
$result[] =  array($ipValue => $ipMax);
}
}



在php中,对数组排序很简单:

asort($result);
array_pop($result);根据数组的Value值排序,升序,然后弹出最后一个元素。




总结:

1)这里这是实现了july的想法,没有在大数据下模拟,如果读者有兴趣可以自己模拟一下。

2)以前在写代码时,特别是使用数组的时候,完全不考虑这个数组的大小,在代码运行时,数组的内容全部载入内存,这样会损耗性能。

3)关于hash算法,我们常用的是模/n 还有一个比较常用的就是md5, 取首字母,这样的结果会有16个 (0-F)



  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-356435-1-1.html 上篇帖子: Php图像处理类 下篇帖子: php AutoSave 自动保存
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表