国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

擴展可伸縮 Oracle 與 PHP George Schlossnagle

2024-08-29 13:39:11
字體:
來源:轉載
供稿:網友

  了解一般的技術和設計,用于編寫與 Oracle 數據庫的使用直接相關的可治理、可伸縮的快速 php 代碼。
  
  在過去九年中,PHP 已經從組裝個人網站的小型語言發展到為世界上某些最大和流量最高的網站提供動力。任何高流量網站的三個最重要的設計方面是可伸縮性、性能和可維護性。可伸縮性意味著您的應用程序流量負載可以不斷增長,而不會從根本上破壞其工作方式。性能是快速為單個請求提供服務的能力。 可維護性是能夠在不造成過多負擔的情況下修復、重新調整、擴增或更改應用程序的品質。
  
  利用 PHP 來實現這三個設計目標并不困難,但確實需要預先考慮如何設計和構建您的應用程序。關于編寫可治理、可伸縮的快速 PHP 代碼的論題范圍很廣;針對每個論題都有大量的技術和文章。在本文中,我們將討論那些與使用 Oracle 及 PHP 直接相關的因素。有很多一般(非 Oracle 專用)技術和設計可能非常有用。
  
  我喜歡以一個尖銳的警告作為任何與性能相關的談話或文章的開始:始終要記住,最后總有一天,快速卻不完善的應用程序將毫無價值。性能調整以及對應用程序不利因素的設計提取都很輕易分散您的精力。Web 的性質就是這樣,經常發布版本的方法非常有效。(發布網站“新版本”的成本很低,因為最終用戶始終需要這些代碼。)這就答應您延遲對代碼的重大調整,直到需要這樣做為止。因此,首要目標應該是創建便于重新調整的代碼。
  
  創建和治理連接
  與 Oracle 數據庫最基本的交互之一是連接。要了解連接如何影響您的應用程序的性能和可伸縮性,需要了解連接的生命周期,如圖 1 所示。每個步驟所涉及的工作如下:
  
  客戶創建連接: 客戶創建與 Oracle 監聽器的網絡連接,提供其認證證書,并請求會話。
  
  服務器創建一個新會話:在認證之后,服務器為客戶創建一個新會話。假如您沒有通過 Oracle 多線程服務器(MTS — 它在可伸縮性及性能問題上臭名昭著)使用共享會話,則此步驟包括服務器為會話創建一個專用進程。該進程通常稱為影子進程。創建此進程需要不少工作量。除了創建進程的正常開銷之外,影子進程在其創建期間還必須臨時鎖定某些共享系統資源。
  
  客戶端執行查詢: 既然客戶端已經具有開放的連接,就可以根據需要來執行查詢。
  
  客戶端關閉連接: 當客戶端完成工作后,關閉與服務器的連接。
  
  服務器毀壞會話: 與用戶會話相關的影子進程被毀壞,任何未提交的事務被回滾。
  
 擴展可伸縮 Oracle 與 PHP  George Schlossnagle

  
圖 1:連接的生命周期

  
  由于創建新的影子進程的成本相當大,我們應該在必要時努力避開它。達到此目的的最簡單方法是使用持續連接。PHP 被設計為一種非會話狀態的語言。這意味著在默認情況下,在請求期間創建的任何信息(或例程化的資源)都會在請求結束時被徹底清除并毀壞。對于 Oracle 客戶連接,我們希望避免這種行為。
  
  為了使連接能夠從一個請求保留到下一個請求,您可以使用以下兩種連接變通方法之一:
  
  OCipLogin($username, $passWord [, $tnsname])
  
  或
  
  OCINLogin($username, $password [, $tnsname])
  
  這兩個函數都創建持續的服務器連接,盡管 OCINLogin() 將為每個請求創建一個新會話句柄。假如您的應用程序要使用事務,并且您希望將同時發生的事務分散到多個會話中,則可以使用 OCINLogin()。
  
  使用持續連接的一個副作用是您更輕易出現進程不足的情況。基于專用 Oracle 數據庫運行單個 Apache Web 服務器(子進程的最大默認數量為 256)時,可能從不會碰到問題。但是假如增加到 4 個 Web 服務器,每個服務器運行 256 個具有持續 Oracle 連接的子進程,現在則要創建 1024 個與 Oracle 數據庫的連接,并且很快就會與 Oracle 實例的資源限制發生沖突。
  
  在 Oracle 實例配置文件 (init.ora) 中,有兩個可調整的參數:
  
  sessions = NNNN 和 PRocesses = NNNN。
  
  這兩個參數控制著實例可以支持的最大會話數和最大進程數。假如您需要支持 1024 個同時出現的連接,則需要至少 1024 個會話(因為 OCINLogin() 連接和某些遞歸查詢可能在每個連接中需要多個會話),而需要的進程還會更多(因為我們還需要考慮 Oracle 后臺進程)。不幸的是,不能任意將這些進程設得很高。Oracle 進程消耗不少的專用內存(在多數系統中每個進程需要 2 到 3MB)。從個體來說,這些進程很小,但當把它們作為一組并與服務器系統全局區 (SGA) 所需要的共享內存相結合時,很快就會讓您因為數據庫服務器的物理內存限制而感到煩惱。

  
  來自 MySQL 環境的用戶可能試圖避開持續連接(這是 MySQL 環境中的建議)。由 Oracle 影子進程啟動所導致的栓鎖和文件爭用使得非持續連接的使用效率極低。那么解決方案是什么呢?
  
  應該確定我們的數據庫能夠支持多少個同時發生的會話,并相應地設置其限制。有些文章具體說明了如何完成此工作,但主要是一個計算過程:計算系統中物理內存的總量,并減去內核、支持程序和 Oracle 后臺進程所使用的內存。然后減去所有被配置為 Oracle 共享內存的那些內存(共享池和緩沖區高速緩存)。剩下的內存可以用于影子進程。將該數量除以一個影子進程所使用的專用進程內存的平均數量(應該自己測出該數量,因為它根據您所運行的查詢性質而變化),則我們得到可支持的進程數量。
  
  對我們的 Web 服務器進行配置,以便使其永遠不能創建超過您的進程設置答應數量的連接。其實現方法是將每個 Web 服務器的 MaxChildren 可調參數設置得足夠低,使得所有 Web 服務器總共擁有的子進程數量低于可支持的 Oracle 連接數。這意味著每個 Apache 實例不再支持 256 個子進程。
  
  重新設計我們的應用程序,使其不會遺漏額外的子進程。我們在后文中還會討論這個話題。
  
  這樣有多重要?作為一個老板,我們即使啟用了持續連接,也一直碰到栓鎖問題。任何碰到過嚴重栓鎖爭用的人都能證實,這是一個極為嚴重的問題,服務器在很大程度上不響應,因為它花費過多時間來進行鎖定操作。我們在調查中發現,盡管在終止前有大量進程為數以百計的請求提供服務,但很多進程只服務于單個請求。這一切是由于我們將 Apache 的 MaxSpareServers 設置得太低。我們所使用的負載均衡設備的一些問題導致了“忽然爆發”的行為,此時 Web 服務器被多個同時發生的請求所沖擊,然后閑置數秒時間。在 Apache 內部,這導致要創建額外的子進程,來為高請求等級提供服務;但當它一旦平息時(幾乎立即平息),就會出現大部分目前處于閑置狀態的子進程(終止進程并關閉其 Oracle 連接)。總體看來,這與運行非持續進程的效果相似。將 MaxSpareServers 設得較高就可消除此問題,并消除了栓鎖爭用。
  
  執行 SQL
  任何 Oracle 客戶服務器關系的主要內容是執行查詢。這里沒有篇幅來談論對查詢的調整 — 那是需要整本書來討論的主題。相反,我們將集中討論如何盡可能地使已經調整過的查詢高效運行。
  
  使用 PHP 編寫良好的 Oracle 應用程序代碼的第一步是始終使用綁定 SQL。當我們編寫類似以下的查詢時:
  
  SELECT * FROM USERS WHERE USERNAME = 'george'
  
  Oracle 必須對該查詢進行軟分析,查看以前是否曾編譯過該查詢。在默認情況下,"george" 值被作為文字項,這意味著假如我們使用不同的名字 ('bob') 執行此查詢,則 Oracle 將把它看作完全不同的查詢。Oracle 在其共享池中保留它執行的每個查詢的分析副本,因此假如您使用數千個名字來執行此查詢,則在您的共享池中將有數千個該查詢的不同副本。即使在輕度活躍的網站上,這也會導致嚴重的內存碎片以及 ORA-4031 錯誤增殖。
  
  對這個問題的解決方案是使用綁定 SQL。綁定 SQL 答應我們將 WHERE 子句中的文字值替換為占位符,如下所示:
  
  SELECT * FROM USERS WHERE USERNAME = ':NAME'
  
  在這里,查詢只須被完全分析一次(硬分析);以后所有的分析都是所謂的軟分析,此時引擎只是簡單地從 SGA 中提取已編譯的查詢。此外,將只有一個單次分析的副本被存儲,從而顯著減少了不斷執行的查詢對內存的需求。
  
  現在我們可以執行如下:
  
  <?php
  $db = OCIPLogin('scott', 'tiger', 'testdb');
  $stmt = OCIParse("SELECT * FROM USERS WHERE USERNAME = ':NAME'");
  OCIBindByName($stmt, ":NAME", "george");
  OCIExecute($stmt);
  ?>
  
  在 Oracle8i 之前,我們必須手動綁定查詢;從 8i 開始,通過設置 init.ora 的參數 "cursor_sharing = FORCE",我們可以指示優化器為我們完成這一工作。該設置通知優化器查找可以綁定的文字值,并手動執行綁定。自 9i 起,我們可以使用設置“cursor_sharing = SIMILAR”,該設置指示優化器深入查看基表的統計信息,了解自動綁定文字是否有好處(假如某個字段的分布極不均勻,則可能沒有好處)。盡管應該啟用這些設置(在 8i 中為 FORCE,在 9i 及更高版本中為 SIMILAR),但深入到查詢中分析潛在綁定的這種操作對于優化器而言成本很高,因此在可能的情況下,應該手動綁定您的查詢。
  
  Oracle 客戶服務器在 SQLNet 協議基礎上運行,眾所周知,這種協議的對話很多。例如,假如您執行一個返回 100 行的查詢,則會有分析查詢的對話交換、對每個綁定變量的交換、對執行的查詢以及對每個提取行的查詢。其中每次交換都包括客戶端與服務器之間的網絡數據包交換(稱為一次往返)。減少往返次數可能具有深刻的性能影響。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 淮滨县| 牙克石市| 嘉峪关市| 荔波县| 彰武县| 寿光市| 都江堰市| 扎赉特旗| 邳州市| 吉林市| 湖北省| 松潘县| 烟台市| 岢岚县| 南乐县| 贵德县| 阿巴嘎旗| 安龙县| 客服| 武宁县| 北海市| 沅陵县| 济阳县| 卢龙县| 马关县| 南投县| 定安县| 上犹县| 株洲县| 古浪县| 唐河县| 乐都县| 皋兰县| 余江县| 杨浦区| 南城县| 汽车| 古丈县| 德江县| 安福县| 临沂市|