如今項目中大多都會使用MQ(消息隊列)用來解耦和提高服務穩定性,而後都會面臨一個問題,就是消息積壓,解決這個問題除了提高處理消息的速度之外,另外就是多開些消費者進程,併發的消費數據。php
若是是其餘語言能夠多開些線程或協程消費數據,可是這些東西,在 php 裏並無很好地支持,因此你們多采用多進程的方式來增長消費者,而後這裏又有了兩種方式,父子多進程和普通多進程。redis
而後這裏就有了一個有趣的坑人方法,小小一技就能把人坑的想打你,那就是使用父子進程。架構
這是 php 使用父子進程的一個僞代碼併發
$pid = pcntl_fork(); //父進程和子進程都會執行下面代碼 if ($pid == -1) { //錯誤處理:建立子進程失敗時返回-1. die('could not fork'); } else if ($pid) { //父進程會獲得子進程號,因此這裏是父進程執行的邏輯 pcntl_wait($status); //等待子進程中斷,防止子進程成爲殭屍進程。 } else { //子進程獲得的$pid爲0, 因此這裏是子進程執行的邏輯。 }
那麼怎麼坑人呢?函數
坑人第一步,監聽 signal測試
//使用ticks須要PHP 4.3.0以上版本 declare(ticks = 1); //信號處理函數 function sig_handler($signo) { switch ($signo) { case SIGTERM: // 我不想被 kill break; case SIGINT: // 我不想被 kill break; default: // 處理全部其餘信號 } }
只須要監聽兩個,一個是監聽的 ctrl+c 的 SIGINT ,另一個是 kill 的默認 signal (不帶任何參數就是使用的這個) SIGTERM,通常人都是用這裏倆方法 kill 進程,只要監聽這倆信號不讓進程退出,而後其餘人想要像重啓進程產生的第一個想法就是 kill -9,kill -9 子進程不會被幹掉,贊,這樣就進了咱們的套。線程
坑人第二步,修改子進程的名字,隨便修改爲一個相關不太相關的都行,可是不能和父進程有一樣的關鍵詞,本身能看懂就行,坑別人的同時也得給本身留條路不是,總之就是不要讓別人使用 ps grep 的時候發現這是子進程,這是 php 設置進程名的一個函數code
setproctitle("myscript");
若是 php version >= 5.5.0 能夠用這個協程
cli_set_process_title("myscript")
假如使用這種方式在測試環境消費MQ數據,其餘人在修了代碼並重啓進程,就會發現本身的數據老是莫名其妙的消失,並且還找不到是誰消費的,若是是kafka或者nsq之流還能夠經過新增group或channel的方式繼續開發,可是若是是 redis 的 list 作 MQ ,嘿嘿……隊列
坑人的同時也得防止被坑不是,咱們須要處理這種事情的時候,先找到主進程 pid ,而後使用這個命令
ps --ppid 父進程的pid
我懂得,你確定想噴我,你這人這麼怎麼缺德,呵呵呵,我就是被人這麼坑了一會,才這麼印象深入,難受。
更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師