亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

配置 Apache 和 MySQL 為客戶端提供并行且可取消的服務

配置 Apache 和 MySQL 為客戶端提供并行且可取消的服務

PHP
白板的微信 2023-08-19 14:29:35
我們有一個客戶端服務器架構,客戶端使用 Angular,服務器端使用 Apache2 PHP PDO 和 MySQL。服務器端向客戶端公開 API,為客戶端提供要顯示的數據。一些觀察:某些 API 調用可能需要很長時間才能計算并返回響應。服務器端似乎在任何給定時間處理每個客戶端的單個請求(我只看到在 mysql 中執行的一個相應查詢),該限制來自 apache 或來自 mysql,因為前端肯定會并行發送請求。前端取消不再相關的請求(正在獲取的數據將不可見)似乎前端取消的請求不會在服務器端取消并繼續運行,我認為即使它們排隊,它們在輪到時仍然會運行(即使它們在客戶端被取消)需要幫助理解:沒有讓所有請求(或至少 X>1 個請求)并行運行的確切原因是什么?可以改變嗎?我應該在 apache 或 mysql 中更改哪些配置來克服這個問題?有沒有辦法讓 apache 刪除已取消的請求?至少那些仍在排隊且未開始的?謝謝!編輯在@Markus AO評論之后(感謝 Markus!?。。?,這是與會話阻塞相關的...希望我之前知道這一點!
查看完整描述

1 回答

?
繁花如伊

TA貢獻2012條經驗 獲得超12個贊

OP 有許多棘手的問題擺在桌面上。然而,我覺得這些都是值得關注的(我自己也曾與它們斗爭過),所以讓我們把它拆開。為了大正義;主屏開啟:

解決并發請求問題

(L)AMP 堆棧中的并發連接存在多種可能的問題和解決方案。然而,在討論調整 Apache 和 MySQL 之前,讓我先介紹一個常見的“神秘”問題,該問題會導致并發問題;即,一個必要的罪惡稱為“?PHP 會話鎖定”。

PHP 會話阻塞和并發請求

簡而言之:當您在應用程序中使用會話時,調用 后session_start(),PHP 會鎖定存儲在您目錄中的會話文件session.save_path。該文件鎖將保持不變,直到腳本結束或被session_write_close()調用。結果:同一用戶的任何后續調用都將排隊,而不是同時處理,以確保不會損壞會話數據。(想象一下并行腳本寫入相同的內容$_SESSION!)

演示這一點的一個簡單方法是創建一個長時間運行的腳本;然后在瀏覽器中調用它;然后打開一個新選項卡,并再次調用它(或者實際上,調用共享相同會話 cookie/ID 的任何腳本)。您將看到,在第一個調用結束之前,第二個調用不會執行。這是奇怪的 AJAX 延遲的常見原因,尤其是來自單個頁面的并行 AJAX 請求。處理將是連續的而不是并發的。然后,10 個調用,每次調用 0.3 秒,總共需要 3 秒才能結束,依此類推。我們不希望那樣,是嗎!

您可以通過確保以下內容來補救由 PHP 會話鎖定引起的請求阻塞:

  1. 使用會話的腳本應在會話數據存儲完成后調用session_write_close()。會話鎖將立即釋放。

  2. 不需要會話的腳本一開始就不應該啟動會話。

  3. 只需要讀取會話數據的腳本:使用session_start()with['read_and_close' => true]選項將為您提供一個只讀(非持久)$_SESSION變量,而無需會話鎖定。(自 PHP 7 起可用。)

選項 1 和 3 將為您提供對$_SESSION變量的讀取訪問權限并釋放/避免會話鎖定。$_SESSION會話關閉后所做的任何更改都將被默默丟棄;不顯示警告/錯誤。

會話鎖定請求阻塞問題僅對單個用戶(使用同一會話)產生影響。


Apache 和 MySQL 并發請求

曾幾何時,在意識到 PHP 是阻塞/排隊我的并發調用的罪魁禍首之前,我花了一小段時間來調整 Apache 和 MySQL,并想知道會發生什么?

Apache 2.4默認支持150個并發請求;任何進一步的請求都將排隊。MPM/多處理模塊下有多個設置,您可以調整它們以支持所需的并發連接級別。

MySQLmax_connections有(默認 151)和max_user_connections(默認無限制)選項。如果您的應用程序為每個用戶發送大量并發請求,您將需要確保全局最大連接足夠高,以確保少數用戶不會占用整個 DBMS。


取消對 Apache/PHP/MySQL 的請求

就您的應用程序的具體接線而言,我們沒有太多可做的,但我從評論中了解到,就目前情況而言,用戶可以在前端取消請求,但不會采取任何后端操作。(即任何后端響應都會被忽略/丟棄。)

“有沒有辦法讓 Apache 刪除已取消的請求?”?我假設您的前端直接無延遲地將請求發送到 Apache;然后轉到 PHP > MySQL > PHP > Apache。在這種情況下,不,你不能真正讓 Apache 取消它已經收到的請求;或者你可以點擊“停止”,但很可能 PHP 和 MySQL 已經把它吃掉了......

持有“取消窗口”

但是,您可以將“取消窗口”延遲編程到前端,其中請求僅在等待可能的取消的 0.5 秒睡眠后才傳遞到 Apache。這可能會對用戶體驗產生負面影響,也可能不會產生負面影響;如果取消了很大一部分請求,則可能值得實施以節省服務器資源。這假設 UI 帶有 Javascript。如果您直接對 API 進行 HTTP 調用,則可以使用“休眠代理接收器”。

使用“取消控制器”

如何取消 PHP/MySQL 進程?顯然,只有當對 API 的調用導致處理時間較長時,這才是可行的/可行的。如果后端需要 0.28 秒來處理,并且用戶在 0.3 秒后取消,那么就沒有太多可以取消的了,是嗎?

但是,如果您確實有可能運行更長時間的腳本,例如幾秒鐘。您總是可以在代碼中找到相關的斷點,其中有“未取消”檢查或終止/回滾例程?;旧希鷮⒕哂幸韵铝鞒蹋?/p>

  • 前端將帶有唯一ID的請求發送到主腳本

  • PHP 腳本開始構建響應的長征

  • 取消時:前端將 ID 重新發送到輕量級取消控制器

  • 取消控制器將 ID 記錄到臨時文件/數據庫/任何地方

  • PHP 在斷點處檢查當前進程是否有取消請求

  • 取消時,PHP 執行終止/回滾例程而不是進一步處理

這種“取消監視”顯然會產生一些開銷,因此您可能只想將其合并到較重的腳本中,以確保您實際上在整體上節省了一些處理時間。此外,您最多只需要在重要的交匯處設置幾個斷點。對于讀取請求,您可以直接終止該進程;但對于寫入請求,您可能希望進行正?;貪L以確保系統中的數據完整性。

您還可以使用mysqli::?kill 取消/終止已由 PHP 啟動的長時間運行的 MySQL 線程。為了使這一點有意義,您需要將其運行為MYSQLI_ASYNC,這樣 PHP 就可以停止使用了。PDO 似乎沒有針對異步查詢或終止的本機等效項。

PHP 連接處理

作為“從側面”傳遞取消信號的控制器的替代方案,您可以查看PHP 連接處理并使用connection_aborted().?(有關代碼示例,請參閱上面的“MySQL Kill”鏈接。)

CONNECTION_ABORTED如果用戶單擊瀏覽器中的“停止”按鈕,則會出現一種狀態。PHP 有一個ignore_user_abort()設置,默認為“Off”,它應該在用戶中止時中止腳本。(不過,根據我的經驗,如果我有一個流氓腳本并且會話鎖定處于打開狀態,那么即使我在瀏覽器中點擊“停止”,我也無法執行任何操作,直到超時。想想看。)

如果您將“忽略用戶中止”設置為 false,即。PHP 腳本在用戶中止時終止,請注意,這將是完全不受控制的終止,除非您已register_shutdown_function()實現。即便如此,您也必須在代碼中標記檢查點,以便關閉函數能夠從終止點向前“倒回時鐘”。另請注意此警告:

在嘗試向客戶端發送信息之前,PHP 不會檢測到用戶已中止連接。

我沒有通過 AJAX/JS 實現“用戶中止”的經驗。


查看完整回答
反對 回復 2023-08-19
  • 1 回答
  • 0 關注
  • 111 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號