程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> WebSphere >> 為WebSphere Application Server Community Edition V2.1構建WADI集群環境

為WebSphere Application Server Community Edition V2.1構建WADI集群環境

編輯:WebSphere

從 WebSphere Application Server Community Edition ( 以下簡稱 WAS CE) 版本 2.1 以來,WAS CE 在 Tomcat native 集群之外,新增了對 WADI 集群的支持。相比於 Tomcat native 集群,WADI 集群同樣提供了集群成員間 Session 復制來避免單點失效並實現災難恢復,同時利用負載平衡來提高應用程序的可用性。另外在一個部署了 Farming 的 WAS CE 集群環境中,如果您在某個節點上進行應用程序部署或者生命周期管理,集群內的所有節點都會同步響應這些請求。Farming 這個特性使得應用程序的管理 ( 如部署、啟動、停止、以及卸載 ) 更加的邏輯化和透明化:通過一次部署 , 便可以將應用部署到 WAS CE 服務器集群中的每個節點;同樣,只需一次操作,便可以管理集群內所有節點上該應用程序的生命周期。這篇文章將從實現機制和示例配置兩方面對 WAS CE WADI 集群和 Farming 插件進行介紹

引言

WebSphere Application Server Community Edition(以下簡稱 WAS CE)是一個完全符合 Java Platform, Enterprise Edition 5(Java EE 5)規范、經認證的應用服務器。也就是說 WAS CE 包含所有支持 Java EE 5 實現的組件:Web 容器、EJB 容器、消息服務、命令行管理等開發和運行 Java EE 應用程序所需的環境。盡管 Java EE 5 的規范中並沒有提供對集群實現的規范要求,但在實際的應用環境中,集群做為提供應用程序的擴展性以及保證其高可用性的常見解決方案,得到了非常廣泛的使用。要實現集群,常見的做法是通過擴展多個服務器節點,使得會話以及節點信息在集群內復制傳遞,以此來保證應用程序的高可靠性。但隨著集群內節點的增多,怎樣保證集群的效率以及應用程序的可用性呢?尤其是在異構的應用服務器環境中,有什麼較理想的解決辦法嗎?另外,為了實現集群中各個節點能夠協調統一,每個節點上面都需要配置相同的應用程序,有什麼比較好的辦法能夠進行批量部署,從而提高集群管理的效率?本文依次通過介紹 WAS CE 服務器中集成的 WADI 模塊和 Farming 模塊,向讀者解答前面提到的問題,並將在文末通過具體實例演示在 WAS CE 服務器環境中如何使用 WADI 和 Farming 模塊搭建 WAS CE 集群。文中所提及的內容為作者的學習總結,僅供讀者參考,以幫助讀者了解相關概念並熟悉部署過程,所述觀點並不代表 IBM 。

WADI 集群的實現機制

WADI 的全稱是 Web Application Distribution Infrastructure, 即 Web 應用程序分布式架構,從它的名字我們可以看出,WADI 這個項目設立的初衷是為了解決集群環境中 Web 層應用程序狀態的管理。隨著項目的逐漸成熟,再加上 WADI 自己獨有的特性和解決方案,它已經演變成一個更加通用的分布式狀態和服務管理框架。由於 WADI 是一個獨立的開源項目,不依賴於任何現有的應用程序容器,因此在一個異構的環境中,WADI 的作用和意義就更為突出。

WAS CE 從版本 V2.1 開始,便將 WADI 集成到了自己的服務器分發包中,這樣,WAS CE 的用戶除了選用原有的 Tomcat 集群以外,還可以考慮選用 WADI 的集群方案。

WADI 簡介及其特性

WADI 的設計目標簡要概括為如下幾點:

為分布式環境中提供可插拔的、棧式的頁面調度(paging)和持久化(persistence)機制;

提供一個伸縮性強、可用性高、自分割(self-partitioning)和自愈合 (self-healing) 的集群基礎;

提供狀態到請求(State to Invocation)或者請求到狀態(Invocation to State)的透明遷移(migration);

提供可插拔的狀態復制機制。

具體到 Web 層則為:保證在應用程序以及容器空間 HTTP 會話的一致性問題;提供 HTTP 請求和 會話遷移、HTTP 會話復制、以及 HTTP 會話序列化策略等。

WADI 的分布式會話查找機制使得無論集群中節點的數量是多少,會話的定位(location)、遷移(migration)以及插入(insertion)等操作所消耗的系統資源都保持為常量。另外,WADI 的會話復制機制只為每個會話復制指定數量的會話副本,這也保證了 WADI 集群在會話復制上的開銷只和復制數量成比例,而不受集群節點的影響。WADI 的上述特點使得 WADI 集群具有很強的可擴展性,當業務需要的時候可以增加 WADI 集群的節點而不會為集群管理帶來額外的開銷。

下面我們來簡單了解一下 WADI 在具體實現過程時所涉及到的幾個關鍵概念。

分區(Partition):用來記錄會話的位置。在每個集群的服務空間(Service Space)中,分區的數量在集群的配置期間被指定,在運行時由分區管理器進行動態的管理,被平均地分配到每個節點。當集群的節點數量發生變化(新節點加入集群、或者現有節點退出集群)的時候,分區管理器會重新分配分區在節點上的分布,以確保分區數在集群的各個節點間上是平均的。WADI 中的分布式會話查找機制所利用的正是這一概念。

會話定位:WADI 集群的每個節點可以通過對會話 ID 進行一個簡單的算法運算,從而得到該會話屬於哪個分區;同時每個節點也知道每個分區具體由哪個節點負責管理(關於分區的信息,在每次分區重新分配的時候都通過集群中散發給每個節點)。所以,對於任何會話,任何節點都可以通過它的 ID 很快的找到這個會話的位置信息被保存在集群的哪個節點上。

會話復制:WADI 的會話復制策略決定會話副本的數量,以及由哪些節點來保存這些副本。當每次請求處理完成以後,會話就被更新到它的副本所在節點。另外,當某個節點離開集群的時候,復制策略將重新選擇節點來保存會話副本。因此,它的會話復制策略更像一種“會話冗余”策略,因為會話復制通常是指在集群中的所有節點間復制會話的信息

會話遷移:當節點接收到請求的時候,如果節點擁有該請求所對應的會話,那麼請求立即可以就在當前節點被處理;如果該節點上沒有請求所對應的會話,那麼節點就會請求分區管理器將會話遷移到當前節點,同時更新分區管理器中關於該會話的位置記錄,然後請求在當前節點被處理。

WADI 集群在 WAS CE 中的實現

WAS CE 中集成了 Tomcat 作為 Java EE 應用服務器中的 Web 容器, 在 為 WAS CE 構建集群環境一文中,作者介紹了 WAS CE V1.0.1 中利用集成的 Tomcat V5.0 實現上下文級別 (Context level) 的集群功能。而從 V2.0 開始, WAS CE 所集成的 Tomcat V6.0 本身就提供了一個進行節點管理的模塊 modules/groupcom,叫做 Tribes,以此來實現節點之間的通信;同時還有一個模塊 module/ha 用於提供會話之間的復制,但是隨著節點或者會話數量的增加,用於維護會話或者節點狀態的內存開銷也會越來越大,最終有可能導致整個集群停止工作。

從版本 2.1 開始, WAS CE 將 WADI 做為一個插件集成到服務器中,從而為用戶提供了另一種集群方式。與先前版本中完全利用 Web 容器 Tomcat 所提供的集群功能相比,WADI 集群通過自己的會話管理機制協調 Web 層各個會話的狀態,並同樣可以利用 mod_proxy/mod_jk 的負載平衡功能來提高應用程序的災難恢復能力。

在 WAS CE V2.1 中的 WADI+Tomcat 模式中, Tomcat 僅作為 Web 容器用於 Web 應用程序解析,節點和會話的管理則通過 WADI 自己的機制來實現,通過在固定數目的節點之間維護指定數量的 HTTP 會話副本,系統的開銷不會因為節點或者會話數目的變化而出現較大的起伏,從而可以保證集群的性能能夠穩定持久;由於 WADI 是一個獨立的集群實現框架,它可以完全獨立於 Java EE 容器,實現分布式 Java EE 環境的集群,同時配合使用相應的 EJB 容器,如 WAS CE 中已經集成的 OpenEJB,用戶也可以實現有狀態會話 Bean 的集群。本文中我們將僅介紹 Web 層面的 WADI 集群實現。另外 WAS CE 中特有的 Farming 特性將會使得應用程序的管理變得更加輕松,用戶只需要在集群內的任一節點上使用部署命令,WAS CE 就會在集群中的其他節點上批量部署並啟動應用程序。

在 WAS CE 中,WADI 和 Tomcat 都是以插件的形式存在的,因此我們來認識一下相關的插件:

表 1. WADI 在 WAS CE 中的對應插件 插件名稱 對應的功能 Geronimo Plugins, Clustering :: WADI 提供了 Geronimo 和 WADI 的集成。 Geronimo Plugins, Clustering :: Clustering 提供了基本的 WADI 集群支持。 Geronimo Plugins, Tomcat :: Clustering Builder for WADI 提供了 WADI 集群在 Tomcat 6 上的部署支持。 Geronimo Plugins, Tomcat :: Clustering over WADI 提供了 WADI 和 Tomcat 的集成。

在上文我們提到 WADI 提供各種參數使得用戶可以根據自己的業務需求靈活配置,在 WAS CE 中,這些可配置的參數直接作為 GBean 的屬性值提供給用戶。

由於 GBean 是 WAS CE 所使用的 Geronimo 架構中的最小可管理單元,服務器中的每個模塊或者系統服務都對應到一組 GBean;為了向服務器中加入新的功能或者服務,需要相應的實現一組 GBean,並部署到 WAS CE 運行環境中。因此,要配置這些屬性,需要知道相應的 GBean 名稱和其含義:

表 2. WADI 在 WAS CE 中的 GBean 實現 Gbean類名 對應的功能 org.apache.geronimo.clustering.wadi.RoundRobinBackingStrategyFactoryGBean 實現與指定數目節點之間的會話的復制,默認為 2 org.apache.geornimo.clustering.wadi.TribesDispatchHolder 用於讀取和設置 WADI 集群的名稱、監聽端口、是否采用廣播還是靜態成員模式等。. 默認采用廣播模式監聽集群內節點的變化。 org.apache.geornimo.clustering.wadi.BasicWADICluster 用於讀取和設置 WADI 節點的信息以及監聽策略,默認值為 NODE。 org.apache.geornimo.clustering.wadi.WadiStaticMember 用於設置節點作為為靜態成員的配置信息 org.apache.geornimo.clustering.wadi.BasicWADISessionManager 用於讀取和設置 WADI 會話管理器信息,如 Partition 的數目、SessionTimeOut、WadiSweepInterval 等

從 WAS CE 所提供的 GBean 信息可以看出,WADI 在 WAS CE 中的集群實現同樣可以采用廣播或者靜態指定集群成員的方式,通常在單個節點的 WAS CE 環境中,用戶只需要啟動相應的模塊就可以啟動 WADI 集群功能,默認的廣播模式和會話管理策略即可滿足用戶的需求。節點(clusterNodeName)以及集群名稱 (clusterName) 會由 WADI 插件自動從 WAS CE 安裝目錄下的 var\config\config-substitions.properties 配置文件中讀取。同樣,如果用戶需要更改 WAS CE 節點上的 WADI 配置,只需要找到這個文件,然後更改以下參數即可:

DefaultWadiSweepInterval=36000
 WebConnectorConTimeout=20000
 DefaultWadiNumPartitions=24 
 ReplicaCount=2

Farming 的實現機制

Farming 也可以叫做“數據中心”或者“服務器農場”,用於批量化管理服務器上的資源或者應用程序。在 WAS CE 中,實現批量化管理的 Farming 模塊也是以插件的形式集成到 WAS CE 服務器中。在同一個“農場”中的各個 WAS CE 服務器之間通過 JMX 連接器進行通訊,整個“農場”中所有的應用程序或者資源的部署和生命周期管理操作只需要在其中一台 WAS CE 服務器上進行。

在 WAS CE 中提供 Farming 功能的插件如下:

表 3. Farming 在 WAS CE 中的對應插件 插件名稱 對應的功能 Geronimo Plugins, Clustering :: Farming 提供了對 Farming 的支持。

同樣,用戶也可以通過 Gbean 配置單個節點的屬性:

表 4. Farming 在 WAS CE 中的 Gbean 實現 GBean名稱 對應的功能 org.apache.geronimo.farm.config.BasicNodeInfo 用於讀取和設置 Farming 環境中的節點信息 org.apache.geronimo.farm.config.BasicClusterInfo 用於讀取和設置 Farming 環境中的集群信息 org.apache.geronimo.farm.deployment.MasterConfigurationStore 用於指定應用程序的目標部署位置,默認值為 <WAS CE_HOME>/master-repository org.apache.geronimo.farm.deployment.BasicClusterConfigurationStore 用於指定應用程序的目標部署位置,默認值為 <WAS CE_HOME>/cluster-repository

為實現當前節點能夠響應集群中其他節點所發起的部署命令,用戶必須用當前節點的主機名或者 IP 地址指定在 config-substitions.properties 文件中的 RemoteDeployHostname參數。

圖 1. WADI 和 Farming 在 WAS CE 集群環境中的邏輯

WAS CE 中 WADI 集群和 Farming 的示例配置

示例說明

本文章下載區提供了示例程序包(wadi-webapp.zip)可供用戶下載,在這個示例程序包中有一個用於演示集群環境的 wadi-cluster 的示例。通過此示例應用程序,我們將對 WAS CE WADI 集群的實現機制有更加清晰的理解,對配置過程有更加具體的掌握。在這個示例中,我們將構建運行在兩台不同機器上的 WAS CE 服務器組成的集群。

示例程序包含以下幾個文件:

wadi-webapp-2.0.war

plan.xml( 支持 wadi cluster)

應用程序如果支持 WADI 集群,必須更新標准部署文件和 WAS CE 部署文件。

配置標准部署文件,比如 web.xml, Web 應用程序必須標記為 <distributable>,表示在分布式環境中,當前節點上所有的會話信息,無論是新加入的還是對已有會話信息的更改,都將依照會話復制管理器的安排,復制到集群中的其他節點上。<web-app>
 .....
    <distributable/>
 .....
 </web-app>

WAS CE 部署文件,比如 geronimo-web.xml, 在本文章的實例中該文件為 plan.mxl, 必須使用 <tomcat-clustering-wadi> 屬性值,它是由 geronimo-tomcat-clustering-wadi-X.xsd 定義的,在 WAS CE 安裝目錄的 schema 目錄下,表示使用 WAS CE 中集成的 WADI+Tomcat 會話管理器。如下例所示:

清單 1 . 部署計劃文件配置示例

<?xml version="1.0" encoding="UTF-8"?>
 <web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web/tomcat-2.0.1">
  <environment>
    <moduleId>
      <groupId>yourGroupId</groupId>
      <artifactId>yourArtifactId</artifactId>
      <version>YourVersion</version>
      <type>war</type>
    </moduleId>
  </environment>
  <context-root>/yourPath</context-root>
  <tomcat-clustering-wadi />
 </web-app>

實驗環境說明

1)所有機器必須處於同一子網(subnet)中,並且支持廣播(multicast)。

2)所有集群成員必須盡可能保證系統時間一致,較大的系統時間差異可能會出現問題。

3)本示例程序已在以下操作系統上進行了驗證:

Linux IA32 – RHEL5.2, Suse10Sp2
Linux PPC64 – SuSe10Sp2
Windows IA32 - Windows 2003 Server SP1, Windows XP SP2

各節點配置說明

1)在 server 1 上更新 WAS CE 服務器配置,啟動 farming 部署功能以及 WADI 集群功能

需要在 WAS CE 服務器停止的狀態下,修改成員服務器 server1 安裝目錄下。

如下修改 server1 配置文件 var\config\config-substitutions.properties:

clusterNodeName=NODE1
 RemoteDeployHostname=NODE1_IP

如下修改 server1 的配置文件 var\config\config.xml,啟動並添加 Gbean 至 farming 模塊:

清單 2.farming 部署模塊配置

<module name="org.apache.geronimo.configs/farming/2.1.4/car" load=”true”>
 <gbean
 name="org.apache.geronimo.configs/farming/2.1.4/car?ServiceModule=\
 org.apache.geronimo.configs/farming/2.1.4car,
 j2eeType=NodeInfo,name=NodeInfo2" gbeanInfo=\
"org.apache.geronimo.farm.config.BasicNodeInfo">
 <attribute name="name">NODE2</attribute>
 <attribute
 propertyEditor="org.apache.geronimo.farm.config.BasicExtendedJMXConnectorInfoEditor"
 name="extendedJMXConnectorInfo">
 <ns:javabean
 class="org.apache.geronimo.farm.config.BasicExtendedJMXConnectorInfo"
 xmlns:ns4="http://geronimo.apache.org/xml/ns/attributes-1.2"
 xmlns:ns="http://geronimo.apache.org/xml/ns/deployment/javabean-1.0" xmlns="">
 <ns:property name="username">system</ns:property>
 <ns:property name="password">manager</ns:property>
 <ns:property name="protocol">rmi</ns:property>
 <ns:property name="host">Node2_IP</ns:property>
 <ns:property name="port">1099</ns:property>
 <ns:property name="urlPath">JMXConnector</ns:property>
 <ns:property name="local">false</ns:property>
 </ns:javabean></attribute>
 </gbean>

 <gbean name="NodeInfo">
 <attribute name="name">${clusterNodeName}</attribute>
    </gbean>
    <gbean name="ClusterInfo">
      <attribute name="name">${clusterName}</attribute>
    </gbean>
  </module>
 .....
 <module name="org.apache.geronimo.configs/wadi-clustering/2.1.4/car" load="true">
 <module name="org.apache.geronimo.configs/tomcat6-clustering-wadi/2.1.4/car"
 load="true"/>

其中

org.apache.geronimo.configs/farming/2.1.4/car模塊實現了 farm 部署功能,用戶可以批量將應用程序部署到各個節點,而不需要逐節點部署;

org.apache.geronimo.configs/tomcat6-clustering-wadi/2.1.4/car和 org.apache.geronimo.configs/wadi-clustering/2.1.4/car模塊實現了 WADI 集群功能,啟動模塊後,server1 將會自動檢測網絡上的其他節點,將他們加到該集群中,如果其中一個節點出現意外情況關閉,那麼其他組員也會檢測到該節點退出集群。

2)在 server 2 上更新 WAS CE 服務器配置,啟動 farming 部署功能以及 WADI 集群功能

需要在 WAS CE 服務器停止的狀態下,修改成員服務器 server2 安裝目錄下

如下修改 server2 配置文件 var\config\config-substitutions.properties:

clusterNodeName=NODE2

RemoteDeployHostname=NODE2_IP

如下修改 server2 的配置文件 var\config\config.xml,同 server 1 配置文件比較,注意以下區別:

<ns:property name="host">NODE1_IP</ns:property>

3)啟動各節點:

在 GShell 中啟動 server1, 該命令將從後台運行 WAS CE 服務器 r,並設置系統屬性 node.name 為黃色,代表當前節點為節點 1,這個屬性將被示例程序讀取,用黃色方塊標示在應用程序運行過程中節點 1 所響應的 HTTP 會話請求。

geronimo/start-server -D node.name=yellow – b

在 GShell 中啟動 server2,即節點 2,並設置系統屬性 node.name 為紅色,所相應的會話請求標示為紅色方塊

geronimo/start-server -D node.name=red -b

使用 Farming 部署應用程序

在 server1 上通過如下命令行使用 farming 部署應用程序至 server1 和 server2

清單 3. 部署命令

deploy.bat/sh --user system --password manager \
 deploy --targets
 org.apache.geronimo.configs/farming/2.1.4/car?ServiceModule=\
 org.apache.geronimo.configs/farming/2.1.4/car,
 j2eeType=ConfigurationStore,name=MasterConfigurationStore
 SAMPLE_HOME\wadi-webapp-2.0.war $SAMPLE_HOME\plan.xml

注:通過 farming 模塊統一部署、啟動,卸載應用程序必須使用命令行方式,如下所示:

deploy.bat/sh --user system --password manager stop
  org.codehaus.wadi/wadi-webapp//war
 deploy.bat/sh --user system --password manager start
  org.codehaus.wadi/wadi-webapp//war
 deploy.bat/sh --user system --password manager undeploy
  org.codehaus.wadi/wadi-webapp//war

訪問 server1:http://<server1_hostname_or_IP>:8080/wadi-webapp/

圖 2. 訪問節點 NODE1 上示例程序

圖 2 中黃色計數值 1 表明當前會話由黃色節點上的 WAS CE 服務器進程響應 .

訪問 server2: http://<server2_hostname_or_IP>:8080/wadi-webapp/

圖 3. 訪問節點 NODE2 上示例程序

圖 3 中紅色計數值 1 表明當前會話由紅色節點上的 WAS CE 服務器進程響應。

下面我們將兩個集群節點放至 Apache Web 服務器後進行負載均衡配置。

使用 mod_jk 配置 Apache http server

與上一系列中的應用示例相似,我們通過配置 Apache HTTP Server 作為我們的 LoadBalancer,實現 HTTP 請求的分發。略微不同的是,我們在這裡使用 mod_jk 模塊。下載 mod_jk.so放置 http 安裝目錄下的 modules 目錄中,在安裝路徑下的 cofig 目錄中 添加如下內容至文件 httpd.conf:

清單 4 .httpd.conf 文件配置示例

LoadModule jk_module modules/mod_jk.so
 # Loads the Jakarta Tomcat Connector module

 JkWorkersFile Install_Dir/conf/workers.properties
 # Tells the module the location of the workers.properties file

 JkLogFile   Install_Dir/logs/mod_jk.log
 # Specifies the location for this module's specific log file

 JkLogLevel  debug
 # Sets the module's log level to info

 JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
 # Sets the module's log time stamp format

 JkAutoAlias Install_Dir/config-store
 # Automatically Alias webapp context directories into the Apache document space.

 JkMount /wadi-webapp/* loadbalancer

在 config 目錄下創建文件 workers.properties,文件內容如下:

清單 5 .workers.properties 文件配置示例

worker.list=loadbalancer
 worker.node1.port=8009
 worker.node1.host=<ip of node1>
 worker.node1.type=ajp13
 worker.node1.lbfactor=1

 worker.node2.port=8009
 worker.node2.host=<ip of node2>
 worker.node2.type=ajp13
 worker.node2.lbfactor=1

 worker.loadbalancer.type=lb
 worker.loadbalancer.balance_workers=node1,node2
 worker.loadbalancer.sticky_session=1
 worker.status.type=status

訪問應用程序 http://your_http_server_host/wadi-webapp/

首次打開頁面,初始計數加一

圖 4. 通過 Web 服務器訪問示例

對頁面刷新四次,計數為 4。幀背景顏色紅黃混合表明會話在紅色和黃色節點間遷移,這個取決於 Apache mod_jk 對每個幀運行的目標服務器的選擇。

圖 5. 會話保存狀態示例

在頁面上有 9 個幀,9 個幀均指向 session.jsp 頁面,每刷新頁面一次,歷史紀錄將保留,計數同步增加 1,每個數字單元背景顏色表示當前會話所在的節點。黃色代表節點 1,紅色代表節點 2。數字顏色變換表示當前會話內容在不同節點間轉移。

驗證會話復制功能

在 Tomcat 集群中,通過 shutdown 命令關閉一個集群成員時,會話復制就會被激活並啟用,然而在 WADI 集群中,要激活會話復制功能,必須使 WADI 集群中的某個節點非正常關閉,因此不能使用 shutdown 命令關閉集群成員,用戶可以使用 Ctrl+C 或者 Kill 命令模擬 WAS CE 服務器進程的非正常關閉。

使用 Ctrl+C 停止 server1, 即黃色節點上運行的 WAS CE 進程 , 刷新頁面後,會發現歷史數據依然保留,並且計數仍然持續增加,背景顏色全部為紅,表明當前會話被復制至紅色節點。如果集群中有 3 個以上成員,可以通過

var/config/config-substitutions.properties 文件中的 ReplicaCount 參數設置復制會話的份數,默認值為 2。

圖 6. 會話復制示例

總結語

本文介紹了利用 WAS CE 中的 WADI 和 Tomcat 構建 Web 集群環境,使用 WAS CE 獨有的 Farming 插件實現 Web 應用程序批量部署的原理、方法和步驟,並通過具體示例演示了如何配置應用程序和實際的生產環境。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved