ORM編寫目的
php換姿勢curd的老話題不斷, 本orm是基於最近流行的swoole擴展而提出的解決方案, 韓天峰的swoole帶給phper全新的編程思路, 原來php還可以常駐内存踢掉php-fpm支配環節, 甚至可以忽略nginx中間件搞起微服務。在nginx+php-fpm業務流程下, 正常的涉及php計算的用戶訪問處理流程是這樣的:
nginx的master進程發現用戶訪問並將請求信息移交給worker進程
worker進程路由到index.php(如果你配置寫的完全正確的情況下)
location裡面會命令nginx加載到nginx所夾帶的fast-cgi模塊
fast-cgi告訴nginx我要監聽本機9000耑口, 有事情就轉發到9000耑口
剛剛好php-fpm也在監聽9000耑口
php-fpm拿到傳入的請求信號, 調起它自己的worker來處理
php-fpm調來的worker處理完畢, 丟還給nginx
nginx回傳給訪問用戶。
swoole創始團認爲, 要不要搞這麽麻煩? 干脆省下一堆, 都一次性“預熱”到内存裡面來, 也不要php-fpm來調來調去, 如此, 就産生了常駐内存的php進程(或是一組master+worker)來處理特定的數據請求, 諸如此類的微服務模式。
關於斷線重連
接著問題來了,常駐内存雖然看起來很美麗,可是Mysql的連接並不穩定, 韓天峰先生在swoole連接池、異步、斷線重連(https://wiki.swoole.com/wiki/page/350.html) 這篇文章當中就有提到過MySQL連接不穩定的幾個因素:
1、MySQL服務器一定時間内自動切斷連接;
2、那種長期無查詢佔茅坑不拉屎的TCP連接會被MySQL切斷回收;
3、主動用命令kill process殺死連接, 或者MySQL服務器重新啓動
筆者隔一段時間會捕獲到類似下面的錯誤
Error while sending STMT_PREPARE packet. PID=xxxxx # 實際就是下方這個報錯導致的, PDOException錯誤代碼爲HY000 server has gone away
phper需要發明出一套名叫“斷線重連”的輪子, 或者想出一套路子維持連接生命周期, 來解決這個問題。有人說搞連接池來解決,還是沒有解決到點子上, 連接池裡面的連接也是一樣觸發數據庫的周期斷線機制好伐……
關於Hprose拋出異常崩掉業務流程之坑
MySQL配置文档my.cnf裡面的interactive_timeout和wait_timeout(特別是wait_timeout)選項, 改到3600, 也就是1小時, 你網站不至於連續1個小時都沒人看吧? 做個網頁爬蟲1小時之内主動爬一下你的頁面, 比如你開了2個worker, 那麽1小時以内你要連續點兩次頁面來重置訪問連接計數器, 不要改太長時間, 容易産生大量僵屍連接。
interactive_timeout和wait_timeout默認值爲8小時。
嘮叨一下報錯填坑過程:
筆者參考laravel 5最新的orm, 扒了一套方法is_break外加pdo精美的捕獲, 做了斷線重連, 但是會報Warning錯誤;
網上thinkphp5.x非正式版本也遇到過這方面問題, 運用了和laravel類似的解決方式, 同樣, 用swoole在内存中持續使用的時候, Warning隔三差五該出的還是會遇到的。
以上問題, 得出結論, 只能選擇發呆忽略。接下來的問題筆者項目用到yaf, 其定制的異常處理機制會捕獲到hprose客戶耑拋出的io異常(EXCEPTION/FATAL ERROR)錯誤, 需要設法跳開這個錯誤, 否則yaf會把業務流程引向error處理機制上
曾嘗試過在實例化pdo時將\PDO::ATTR_ERRMODE這個選項改成\PDO::ERRMODE_SILENT, 發現pdo實例調用prepare方法時, Warning會被包裹著hrpose的swoole發送到hporse客戶耑, 而客戶耑將Warning錯誤升級爲異常級別拋出, 此時:
服務耑改用捕獲pdo實例中的errorInfo方法取得數組或者errorCode方法來拿錯誤代碼判斷是否閃斷;
使用try catch捕獲異常(顯然沒門);
用@符號掩蓋掉prepare這一句的Warning錯誤
以上都會觸發Warning的前提下,在hprose調用swoole服務耑的時候隨後跟上一句修改報錯等級, 以下是實際代碼:
$server = new Server('tcp://0.0.0.0:1314'); // 將E_WARNING屏蔽 $server->setErrorTypes(E_ERROR);
實測發現加或者不加這行配置, 結果都是一樣的, 現有的Hprose還是拋異常。
以我半小時都沒人點一下的小部落格而言, 測試結果爲: swoole自帶的set方法有個提高worker數量, 可以用, 但Reactor必須等於1, 就解決報錯的問題了。本人底層學的很菜, 原因未知, 稀裡糊塗, 相關的參考文档 https://wiki.swoole.com/wiki/page/163.html
另外,仔細翻了下文档, 其中說到dns攜帶的參數裡可以指定ATTR_PERSISTENT和ATTR_TIMEOUT兩個屬性, 經過實測, 未果, 該報警告還是報警告。另外, 據某些部落格說ATTR_PERSISTENT在敺動層已經集成了連接池, 這可是個不錯的消息(實際對這個問題還是沒用)。
代碼地址
http://www.wkwkk.com/article/aee0450ce1aff796f87af84777cf8683.html
使用說明
針對該ORM的使用文档請移步地址: http://www.wkwkk.com/article/258078a0ef7a23f89655ac669a52f8a9.html
可實例化pdo操作類的基礎模型類
如此一來, 再寫一個BasicModel實例化這個pdo操作類就可以當基礎模型來用了, 這個地址 http://wkwkk.com/article/98a742396c78db8ed15c32649c70e9c4.html 是一個在Yaf中讀寫分離的代碼例子:
解決爬蟲類腳本内存不斷上升不釋放的問題
對於小内存主機來說,如果你不去切割爬蟲腳本的工作, 當然在php單任務生命周期内, 内存的升高問題是很難得到緩解的。
如果你偏偏就是不喜歡切割任務,那麽看pdo操作類裡面有一句:
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
將true改爲false
關掉pdo緩沖操作來節省内存。