文档章节

PHP用swoole实现爬虫(二)

o0无忧亦无怖
 o0无忧亦无怖
发布于 2017/08/19 22:07
字数 1122
阅读 223
收藏 0

本文大部分代码为伪代码,具体实现:一个简单的swoole服务器

如何解决worker锁住问题

按照epoll模型,master和manager只分配任务,实际执行交给worker。但是爬虫是一个超级耗时的任务,IO和CPU虽然不太损耗, 主要损耗都存在网络上(也是IO),明显受制于网络情况的变化。如(一)中所说,假设我只有2个CPU,我分配4个worker,这个时候服务器就无法处理新的请求了,这会造成资源的浪费。

所以我要寻找解决方案,首先我想到的用swoole的task解决,官方定义:

投递一个异步任务到task_worker池中。此函数是非阻塞的,执行完毕会立即返回。Worker进程可以继续处理新的请求。使用Task功能,必须先设置 task_worker_num,并且必须设置Server的onTask和onFinish事件回调函数。

int swoole_server::task(mixed $data, int $dst_worker_id = -1) 
$task_id = $serv->task("some data");
//swoole-1.8.6或更高版本
$serv->task("taskcallback", -1, function (swoole_server $serv, $task_id, $data) {
    echo "Task Callback: ";
    var_dump($task_id, $data);
});

task的问题

首先我们在request事件中将任务转发到task:

$server->on('requset'. function(\swoole_request $request, \swoole_response $response) use($server){
    $data=json_decode($request->rawContent());
    $server->task($data);  //将任务投递到task
});
$server->on('task',function(\swoole_server $serv, $task_id, $data){
    while(true){
        //执行爬虫操作
            
        }
$server->finish();
});

这样的确解决的耗时异步任务的投递方式。但是因为需求会出现一个新问题,爬虫任务是一直在执行的,我们要手动使其退出,需要从服务器外部发起请求关闭task。但是,task的finish并不能关闭指定的taskId。

如何关闭taskId呢?我尝试过用swoole的sendMessage来解决:

$server->on('task',function($server.$taskId,$data){
    //用外部cache记录taskId
});
$server->on('request',function($req,$res){
    //假设遇到关闭信号 关闭指定TASKiD
    $server->sendMessage($data,$taskId);
});

但是实际上是无法关闭的,原因有二:

  1. 和上面一样,while(true)不会释放控制权
  2. task是一种特殊的worker_id,但是他和worker的ID一样,是从1开始,会导致系统复杂难以维护(虽然可以用$server->isTask判断)

之后我发现了一个神器:swoole_process

swoole_process 解决方案

swoole_process提供了如下特性:

  1. swoole_process提供了基于unixsock的进程间通信,使用很简单只需调用write/read或者push/pop即可
  1. swoole_process支持重定向标准输入和输出,在子进程内echo不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据
  2. 配合swoole_event模块,创建的PHP子进程可以异步的事件驱动模式
  3. swoole_process提供了exec接口,创建的进程可以执行其他程序,与原PHP父进程之间可以方便的通信

具体实现伪代码如下:

$server->on('request',function($req,$res){
    if request is crawler 
        then 
            if start
                new swoole_process(function() use(data){ 
                      do crawler
                }) ;
                cache log processId
            if stop
                cache get processId
                kill processId
            if reload
                goto stop  
                goto start 
    else
        do other
});    

可以很好的解决上述问题,不需要维护负载的定时器,task任务等等。新增的需求是自己维护一个process map['taskname':[processId:int,stop:int]]

优化

前期我使用的是redis记录,会出现一定不稳定的情况(频繁读写redis,需要维护长连接等等)。 后期改用swoole_table进行维护,还可以保证任务最大数(swoole_table在使用的时候就需要初始化内存,多余的数据无法写入),swoole table的坑:

  1. 需要在server->start之前初始化
  2. 需要指定详细的数据类型
  3. 假如在worker中使用了create,会使其在之前的create无效并且无法在进程中共享

给个例子,避免大家走入更多的坑

   $table = new swoole_table(20);
    $table->column('t',swoole_table::TYPE_INT);
    $table->column('x',swoole_table::TYPE_INT);
    $table->create();
    $server = new swoole_http_server('0.0.0.0',9999);
    $server->table = $table; 

$server->on('Request', function($request, $response) use($server){
        if($request->server['request_uri'] == '/favicon.ico') {
                $response->end();
                return;
        }
$uri = ltrim($request->server['request_uri'],'/');
         $server->table->set($uri, [
                    't'     =>      1,
		    'x'     =>      1
        ]);
        $response->end('');
});

总结

由于是试验阶段,具体细节已经忘了很多,所以文中记录不太详细,有需要咨询详情的可以给我留言,也可以加我q:285753421

© 著作权归作者所有

o0无忧亦无怖
粉丝 43
博文 105
码字总数 88584
作品 1
海淀
程序员
私信 提问
加载中

评论(1)

p
phper08
用协程啊,go()一下
PHP分布式dht爬虫--phpDhtSpider

php实现的dht (BT种子)分布式爬虫 24小时采集 bt种子磁力链接信息 区别于传统爬虫 不会被封ip 采集效率 vultr 1核1G机器 每日大概8~10w条记录 github地址:https://github.com/cuijun123/php...

灯火阑珊cj
2017/04/25
2.9K
2
PHP用Swoole实现爬虫(一)

基本概念 网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名...

o0无忧亦无怖
2017/08/12
442
0
liufee/yii2-swoole

yii2 swoole 让yii2运行在swoole上。如果您在使用中遇到问题或者想学习yii2结合swoole可以加qq群258780872一起讨论 性能 运行在swoole上的yii2是运行在php-fpm上yii2的5倍以上,而且一句代码...

liufee
2017/12/26
0
0
php pdo防sql注入原理 php连接池

pdo防sql注入原理 PdoTest.php 访问: 状态:方式一、方式二都正常 访问: 状态:方式一返回false,方式二返回user表所有数据 问题来了,为什么pdo预处理能正确处理sql注入呢? mysql预处理语...

tomener
09/29
0
0
PHP的异步并行扩展Swoole已收录到PHP官方扩展库

PHP的异步并行扩展Swoole已收录到PHP官网扩展库pecl.php.net。最新的版本是swoole-1.6.9。国内程序员组织的开源PHP扩展项目,能够添加到pecl中的并不多,目前仅有yaf,yar,yac,swoole等数个。...

matyhtf
2014/01/17
12.6K
14

没有更多内容

加载失败,请刷新页面

加载更多

parseint和isNaN用法

本文转载于:专业的前端网站➭parseint和isNaN用法 <!doctype html><html><head><meta charset="utf-8"><title>无标题文档</title></head><body><script> var a='12'; alert......

前端老手
13分钟前
2
0
Kylin 精确去重在用户行为分析中的妙用

作者:史少锋,Apache Kylin committer & PMC,2019/10/11 在上次文章《如何在 1 秒内做到大数据精准去重》中,我们介绍了 Apache Kylin 为什么要支持大数据集上的精确去重,以及基于 Bitmap...

ApacheKylin
24分钟前
1
0
学习记录(二) es6基本语法(rest参数,模板化,axios模块,拦截器)

日常学习记录 模块化:把一个大文件分成多个小文件,按照一定规范进行拼接 es5写法: 导出:module.exports = 数据 导入:require("路径") /路径未添加后缀名时 //默认添加.js //把路径作为文件名...

Pole丶逐
28分钟前
2
0
以程序员的角度怎么购买一台「性价比高的电视」

前俩天有小伙伴在我的文章下留言,说能否把 【国内电视机都介绍一下】,今天我已在TV端开发多年的程序员的角度。谈谈已程序员的角度如何购买一台性价比高的电视。 国内大的电视机品牌介绍 长...

我们都很努力着
31分钟前
1
0
PhotoShop 色调:理解直方图/RGB通道信息

一、直方图:图表的形式,展示图像像素分布的情况 1.平均值:表示平均亮度 2.标准偏差值:表示亮度值范围内的中间值 3.像素: 表示用于计算直方图的像素总数 4.色阶:显示指针下面的区域亮度...

东方墨天
37分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部