前言
消息队列对于大型的web项目来说是必不可少的一个模块,通过消息队列可以解决大并发和多种语言通信接口等问题。对于大并发的问题,可以将耗时的任务或者不能同时大量并行的任务封装起来传输到消息队列中,由处理程序不断从消息队列中提取消息并进行处理,这样通过消息队列的缓冲可以使得在大并发情况下不再阻塞,如果性能不够用还可以添加多个处理任务从消息队列中获取消息进行处理。比如数据库的操作,当对数据库的读、写操作过多时就会存在锁表等问题,读的问题可以通过缓存等方案解决,写的问题就需要消息队列来解决。而且,在大型的web项目开发中,很多情况下不可能通过一种语言实现,需要发挥不同语言的优势,比如php,虽然在理论意义上它可以做web开发中的所有事情,但是有些问题用它解决效率将会非常低,比如实时socket连接和分布式事务处理等。
使用 laravel 的消息队列处理异步任务,redis 作为队列数据库,supervisor 监控脚本异常中断并自动重启,这是 laravel 处理队列任务的标准流程,但是实际中可能还会出现各种各样的问题,为了保证系统可靠性,还要注意几个问题。
一、执行失败重试次数设置
一定要设置任务执行失败重试次数,避免无限失败重试,超过重试次数 laravel 会默认写到失败任务表中,也可以自己写执行失败后续处理逻辑。
1
|
php artisan queue:work redis --tries=3 |
需要先执行以下命令创建数据表:
1
2
|
php artisan queue:failed-table php artisan migrate |
二、程序异常的处理
有时候程序执行过程会发生异常,比如依赖其他接口,请求 http 接口超时等等,如果不捕捉异常,那么当前这个队列就会中断不能继续运行下去,比如给 10000 个用户推送内容,需要依赖接口推送,如果中间的请求挂了就会影响到后面的推送。
这里的异常是指程序执行过程中发生的异常,不是指常驻进程挂掉,程序异常不一定导致常驻进程中断,况且进程中断有 supervisor 监控并重启。
如捕获异常代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
try { $r = $client ->request( 'post' , '' , [ 'query' => [ 'client_name' => 'filemail' , 'client_version' => '1.0' , 'client_sequence' => 0, 'uid' => 692934013, //119481237 'r' => 1508312484, ], 'body' => \guzzlehttp\json_encode( $body ), ]); $result = $r ->getbody()->getcontents(); $result = json_decode( $result , true); if ( $result [ 'result' ] == 0) { info( "sendmail fail:" . json_encode( $result )); $this ->pushlog( $task [ 'id' ], $task [ 'mail_id' ], implode( ',' , $userids ), json_encode( $result ), 0); } else { log::warning( "sendmail fail:" . json_encode( $result )); $this ->pushlog( $task [ 'id' ], $task [ 'mail_id' ], implode( ',' , $userids ), json_encode( $result ), $result [ 'result' ]); } } catch (requestexception $e ) { log::warning( 'requestexception' . $e ->getmessage()); } catch (exception $e ) { log::emergency( 'exception' . $e ->getmessage()); } |
三、修改代码记得重启 supervisor
最后一点,修改了处理队列的程序,记得要重启 supervisor,否则脚本不会生效。
laravel 往 redis 写队列的数据结构
队列用 list 类型存储,如图:
value 内容如下:
1
2
3
4
5
6
7
8
9
|
{ "job" : "illuminate\\queue\\callqueuedhandler@call" , "data" : { "commandname" : "app\\jobs\\sendfile" , "command" : "o:17:\"app\\jobs\\sendfile\":5:{s:23:\"\u0000app\\jobs\\sendfile\u0000task\";a:8:{s:5:\"title\";s:4:\"1111\";s:4:\"note\";s:2:\"11\";s:6:\"reward\";s:0:\"\";s:7:\"mail_id\";s:5:\"66681\";s:4:\"nums\";i:20;s:8:\"uid_file\";s:33:\"uidfile\/file-66681-1513058185.txt\";s:5:\"gcids\";s:40:\"1b9dd95645aae8119f7da9b9ff738d52bc8a1bd5\";s:2:\"id\";i:29;}s:6:\"\u0000*\u0000job\";n;s:10:\"connection\";n;s:5:\"queue\";s:8:\"sendfile\";s:5:\"delay\";n;}" }, "id" : "l0mjsuthbxm4tgijnuh13km9n8diperk" , "attempts" : 1 } |
包含失败重试次数,队列标识,处理队列的类,以及队列的数据等等。
参考链接
laravel 官方文档 queue 队列:
https://laravel.com/docs/5.5/queues
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://blog.tanteng.me/2017/12/laravel-queue-tips/