有個(gè)常駐進(jìn)程 監(jiān)聽rabbitmq隊(duì)列,如果這個(gè)隊(duì)列有信息進(jìn)來就把這個(gè)信息保存到一個(gè)數(shù)據(jù)庫表中,自打上線后發(fā)現(xiàn)個(gè)規(guī)律只能運(yùn)行一小段兒時(shí)間正常,過一段時(shí)間后就無法保存數(shù)據(jù)庫了,日志報(bào)異常
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
應(yīng)該是數(shù)據(jù)庫連接丟失了,理論上model應(yīng)該有自動(dòng)重連的機(jī)制,這個(gè)需要特殊配置嗎?還是說有其他解決方案?
Model::create(['id'=>'123']); // 主要就這樣保存的
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
"workerman/webman-framework": "~2.1",
"workerman/workerman": "~5.1",
崗?fù)ね綌?shù)據(jù)業(yè)務(wù)數(shù)據(jù)處理異常 {"message":"SQLSTATE[HY000]: General error: 2006 MySQL server has gone away (Connection: mysql, SQL: select * from `vehicle_passage_tickets` where `is_entry` = 1 and `status` <> void and (`available_start_datetime` between 2025-02-13 00:00:00 and 2025-02-13 23:59:59 or `available_end_datetime` between 2025-02-13 00:00:00 and 2025-02-13 23:59:59 or (`available_start_datetime` <= 2025-02-13 00:00:00 and `available_end_datetime` >= 2025-02-13 23:59:59 and `status` = pending_use)))","trace":"#0 /var/www/backend-service/vendor/illuminate/database/Connection.php(979): Illuminate\\Database\\Connection->runQueryCallback()
#1 /var/www/backend-service/vendor/illuminate/database/Connection.php(958): Illuminate\\Database\\Connection->tryAgainIfCausedByLostConnection()
#2 /var/www/backend-service/vendor/illuminate/database/Connection.php(781): Illuminate\\Database\\Connection->handleQueryException()
#3 /var/www/backend-service/vendor/illuminate/database/Connection.php(398): Illuminate\\Database\\Connection->run()
#4 /var/www/backend-service/vendor/illuminate/database/Query/Builder.php(3133): Illuminate\\Database\\Connection->select()
#5 /var/www/backend-service/vendor/illuminate/database/Query/Builder.php(3118): Illuminate\\Database\\Query\\Builder->runSelect()
#6 /var/www/backend-service/vendor/illuminate/database/Query/Builder.php(3706): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()
#7 /var/www/backend-service/vendor/illuminate/database/Query/Builder.php(3117): Illuminate\\Database\\Query\\Builder->onceWithColumns()
#8 /var/www/backend-service/app/service/TollGateSyncDataService.php(97): Illuminate\\Database\\Query\\Builder->get()
#9 /var/www/backend-service/app/service/TollGateSyncDataService.php(47): app\\service\\TollGateSyncDataService->getAvailableTickets()
#10 /var/www/backend-service/app/process/TollGateDataMonitor.php(202): app\\service\\TollGateSyncDataService->getAvailableTollGateData()
#11 /var/www/backend-service/app/process/TollGateDataMonitor.php(170): app\\process\\TollGateDataMonitor->downloadTollGateData()
#12 /var/www/backend-service/app/process/TollGateDataMonitor.php(77): app\\process\\TollGateDataMonitor->processMessage()
#13 [internal function]: app\\process\\TollGateDataMonitor->app\\process\\{closure}()
#14 /var/www/backend-service/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AMQPChannel.php(1063): call_user_func()
#15 [internal function]: PhpAmqpLib\\Channel\\AMQPChannel->basic_deliver()
#16 /var/www/backend-service/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php(221): call_user_func()
#17 /var/www/backend-service/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Channel/AbstractChannel.php(367): PhpAmqpLib\\Channel\\AbstractChannel->dispatch()
#18 /var/www/backend-service/app/process/TollGateDataMonitor.php(130): PhpAmqpLib\\Channel\\AbstractChannel->wait()
#19 /var/www/backend-service/app/process/TollGateDataMonitor.php(59): app\\process\\TollGateDataMonitor->startMonitor()
#20 /var/www/backend-service/vendor/workerman/webman-framework/src/support/helpers.php(512): app\\process\\TollGateDataMonitor->onWorkerStart()
#21 /var/www/backend-service/vendor/workerman/webman-framework/src/support/helpers.php(558): worker_bind()
#22 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(2571): {closure}()
#23 [internal function]: Workerman\\Worker->Workerman\\{closure}()
#24 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(2586): Fiber->start()
#25 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(1740): Workerman\\Worker->run()
#26 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(1544): Workerman\\Worker::forkOneWorkerForLinux()
#27 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(1524): Workerman\\Worker::forkWorkersForLinux()
#28 /var/www/backend-service/vendor/workerman/workerman/src/Worker.php(593): Workerman\\Worker::forkWorkers()
#29 /var/www/backend-service/vendor/workerman/webman-framework/src/support/App.php(143): Workerman\\Worker::runAll()
#30 /var/www/backend-service/start.php(5): support\\App::run()
#31 {main}","data":"{\"cmd\":\"get_toll_gate_all_data\",\"toll_gate_code\":\"1001\",\"sync_datetime\":\"2025-02-14 10:57:20\",\"id\":\"oxcs5vnp1r\"}"} []
php-amqplib 是一個(gè)阻塞組件,阻塞過程中webman內(nèi)核無法拿到進(jìn)程控制權(quán),無法發(fā)送心跳保持?jǐn)?shù)據(jù)庫連接。
哦哦 大概明白了,那如果是這種需求,需要使用 php-amqplib 這個(gè)類庫連接rabbitmq,配合數(shù)據(jù)庫的業(yè)務(wù)該如何做呢?
它是連接空閑一定時(shí)間后斷開的,保證這期間有處理業(yè)務(wù)就可以。
或者你裝下swoole擴(kuò)展,進(jìn)程開啟swoole協(xié)程試下。
也有開發(fā)者嘗試用定時(shí)器去wait(), 參考http://www.wtbis.cn/q/8688
回來報(bào)告一下消息:
按照walkor老大指引的開啟了協(xié)程的方式,數(shù)據(jù)庫開啟了連接池,經(jīng)過一晚的時(shí)間測(cè)試 還是沒能解決問題:
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
配置如下:
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST'),
'port' => env('DB_PORT'),
'database' => env('DB_NAME'),
'username' => env('DB_USER'),
'password' => env('DB_PASSWORD'),
'charset' => env('DB_CHARSET'),
'collation' => env('DB_COLLATION'),
'unix_socket' => '',
'prefix' => '',
'strict' => true,
'engine' => null,
'options' => [
PDO::ATTR_EMULATE_PREPARES => false,
],
'pool' => [ // 連接池配置,僅支持swoole/swow驅(qū)動(dòng)
'max_connections' => (int)env('DB_POOL_MAX_CONNECTIONS'), // 最大連接數(shù)
'min_connections' => (int)env('DB_POOL_MIN_CONNECTIONS'), // 最小連接數(shù)
'wait_timeout' => 3, // 從連接池獲取連接等待的最大時(shí)間,超時(shí)后會(huì)拋出異常
'idle_timeout' => 180, // 連接池中連接最大空閑時(shí)間,超時(shí)后會(huì)關(guān)閉回收,直到連接數(shù)為min_connections
'heartbeat_interval' => 60, // 連接池心跳檢測(cè)時(shí)間,單位秒,不要小于60
],
],
],
];
監(jiān)聽的進(jìn)程配置如下:
'test_pusher' => [
'handler' => TestPusher::class,
'count' => 1,
'eventLoop' => \Workerman\Events\Swoole::class,
],
回來再報(bào)個(gè)信息,更新后今天大部分都正常,但是收到一個(gè)錯(cuò)誤:
PDO::prepare(): Send of 132 bytes failed with errno=110 Connection timed out (Connection: mysql, SQL: insert into push_test (push_url, request_data, push_times, id, updated_at,
回來再報(bào)問題,經(jīng)過這幾天的測(cè)試發(fā)現(xiàn)上面提到的問題還是依然存在,大概現(xiàn)象就是,這個(gè)進(jìn)程大概1天半的時(shí)間沒有與數(shù)據(jù)庫通信是靜默狀態(tài)沒有數(shù)據(jù)推送過來,等到再次有數(shù)據(jù)推送過來的時(shí)候一定會(huì)報(bào)錯(cuò):
"error":"PDO::prepare(): Send of 132 bytes failed with errno=110 Connection timed out
如果接下來繼續(xù)有數(shù)據(jù)推送程序就正常處理,如果再次隔很久才有數(shù)據(jù)推送過來處理入庫還是如上的報(bào)錯(cuò)。
Connection timed out 和 MySQL server has gone away 是不同的錯(cuò)誤類型了。一個(gè)是發(fā)送數(shù)據(jù)超時(shí),一個(gè)是連接斷開。
你們用的什么數(shù)據(jù)庫?云數(shù)據(jù)庫?
可能是你們系統(tǒng)有什么防火墻之類的把不活躍連接清理了,導(dǎo)致超時(shí)了。
剛看了下代碼,PhpAmqpLib的wait()有超時(shí)參數(shù),你們?cè)O(shè)置個(gè)超時(shí),比如50秒。
超時(shí)后執(zhí)行個(gè)SQL,這樣和數(shù)據(jù)庫定時(shí)通訊下,維持下連接。
求問,經(jīng)過這幾天的測(cè)試,還是這個(gè)問題,這種 timeout能否有什么方法手動(dòng)去連接數(shù)據(jù)庫呢?
PDO::prepare(): Send of 132 bytes failed with errno=110 Connection timed out
50秒通訊一次該如何實(shí)現(xiàn)呢? 因?yàn)槔碚撋蟤q的進(jìn)程是阻塞試的,一單這個(gè)進(jìn)程啟動(dòng)他就一直在 wait的狀態(tài)了,這個(gè)狀態(tài)下如何嘗試50秒與數(shù)據(jù)庫通訊一次?
另外我有個(gè)不明白的地方 理論上我啟用的swoole模式下的連接池配置,理論上連接池會(huì)有心跳維持,當(dāng)有數(shù)據(jù)庫操作的時(shí)候不會(huì)出現(xiàn)連接timeout的狀態(tài)因?yàn)檫B接池理論上是肯定有個(gè)min可用連接的,對(duì)吧?難道是連接池在這種自定義進(jìn)程的模式下是不起作用的嗎?
50秒通訊一次就是上面說的利用wait()的超時(shí)參數(shù),超時(shí)后調(diào)用一次數(shù)據(jù)庫。
連接從連接池里獲取后沒歸還前不會(huì)調(diào)用心跳,連接沒歸還說明連接正在被使用,可能正在等待數(shù)據(jù),發(fā)出心跳查詢可能導(dǎo)致數(shù)據(jù)錯(cuò)亂,swoole和swow下會(huì)報(bào)錯(cuò)。