asp.net 並發處理

來源:互聯網
上載者:User
ASP.NET並發處理

講到並發處理,我們一般會分為兩個方面來說:a)伺服器層級的並發控制; b)程式層級的並發控制。

伺服器層級的並發控制:

Ø  調整伺服器應用程式池中的最大串連數。

對於Web 服務器,dudu在最佳化部落格園的伺服器的時候寫過以下的文章。

dudu 寫過讓Windows Server 2008+IIS 7+ASP.NET支援10萬個同時請求http://www.cnblogs.com/dudu/archive/2009/11/10/1600062.html

1. 調整IIS 7應用程式集區隊列長度

由原來的預設1000改為65535。

IIS Manager > ApplicationPools > Advanced Settings

Queue Length : 65535

2.  調整IIS 7的appConcurrentRequestLimit設定

由原來的預設5000改為100000。

appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000

在%systemroot%\System32\inetsrv\config\applicationHost.config中可以查看到該設定。

3. 調整machine.config中的processModel>requestQueueLimit的設定

由原來的預設5000改為100000。

<configuration>
<system.web>
<processModel requestQueueLimit="100000"/>

4. 修改註冊表,調整IIS 7支援的同時TCPIP串連數

由原來的預設5000改為100000。

reg add HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v MaxConnections /t REG_DWORD /d 1000000 

完成上述4個設定,就可以支援10萬個同時請求

 

Ø  對於DB伺服器同樣也可以調整最大串連數來做最佳化。

      在調整最佳化好最大串連數之後,就只有軟硬體負載平衡了。硬體負載平衡能夠直接通過智能交換器實現,處理能力強,而且與系統無關,但是價格貴,配置困難,不能區分實習系統與應用的狀態。所以硬體負載平衡適用於一大堆裝置,大訪問量,簡單應用。軟體負載平衡是基於系統與應用的,能過更好地根據系統與應用的狀況來分配負載。性價比高。PCL負載平衡軟體,Linux下的LVS軟體。

程式層級的並發控制:

當兩個使用者同時訪問一個頁面,一個使用者可能更新的事另一個使用者已經刪除的記錄。或者,在一個使用者載入頁面跟他點擊刪除按鈕之間的時間裡,另一個使用者修改了這條記錄的內容。

有下面三中並發控制策略可供選擇:

Ø 什麼都不做 –如果並發使用者修改的是同一條記錄,讓最後提交的結果生效(預設的行為)

Ø 開放式並發(Optimistic Concurrency - 假定並發衝突只是偶爾發生,絕大多數的時候並不會出現; 那麼,當發生一個衝突時,僅僅簡單的告知使用者,他所作的更改不能儲存,因為別的使用者已經修改了同一條記錄

Ø 保守式並發(Pessimistic Concurrency – 假定並發衝突經常發生,並且使用者不能容忍被告知自己的修改不能儲存是由於別人的並發行為;那麼,當一個使用者開始編輯一條記錄,鎖定該記錄,從而防止其他使用者編輯或刪除該記錄,直到他完成並提交自己的更改

當多個使用者試圖同時修改資料時,需要建立控制機制來防止一個使用者的修改對同時操作的其他使用者所作的修改產生不利的影響。處理這種情況的系統叫做“並發控制”。

並發控制的類型

通常,管理資料庫中的並發有三種常見的方法:

  • 保守式並發控制 - 在從擷取記錄直到記錄在資料庫中更新的這段時間內,該行對使用者不可用。
  • 開放式並發控制 - 只有當實際更新資料時,該行才對其他使用者不可用。更新將在資料庫中檢查該行並確定是否進行了任何更改。如果試圖更新已更改的記錄,則將導致並發衝突。
  • 最後的更新生效 - 只有當實際更新資料時,該行才對其他使用者不可用。但是,不會將更新與初始記錄進行比較;而只是寫出記錄,這可能就改寫了自上次重新整理記錄後其他使用者所進行的更改。
保守式並發

保守式並發通常用於兩個目的。第一,在某些情況下,存在對相同記錄的大量爭用。在資料上放置鎖所費的成本小於發生並發衝突時復原更改所費的成本。

在事務過程中不宜更改記錄的情況下,保守式並發也非常有用。庫存應用程式便是一個很好的樣本。假定有一個公司代表正在為一名潛在的客戶檢查庫存。您通常要鎖定記錄,直到產生訂單為止,這通常會將該項標記為“已訂購”狀態並將其從可用庫存中移除。如果未產生訂單,則將釋放該鎖,以便其他檢查庫存的使用者得到準確的可用庫存計數。

但是,在斷開的結構中無法進行保守式並發控制。串連開啟的時間只夠讀取資料或更新資料,因此不能長時間地保持鎖。此外,長時間保留鎖的應用程式將無法進行伸縮。

注意    如果基礎資料來源支援事務,則可以通過在事務中更新資料來類比保守式並發。有關更多資訊,請參見 ADO.NET 中的事務。

開放式並發

在開放式並發中,只有在訪問資料庫時才設定並保持鎖。這些鎖將防止其他使用者在同一時間更新記錄。除了進行更新這一確切的時刻之外,資料始終可用。有關更多資訊,請參見開放式並發。

當試圖更新時,已更改行的初始版本將與資料庫中的現有行進行比較。如果兩者不同,更新將失敗,並引發並發錯誤。這時,將由您使用所建立的商務邏輯來協調這兩行。

最後的更新生效

當使用“最後的更新生效”時,不會對初始資料進行檢查,而只是將更新寫入資料庫。很明顯,可能會發生以下情況:

  • 使用者 A 從資料庫擷取一項記錄。
  • 使用者 B 從資料庫擷取相同的記錄,對其進行修改,然後將更新後的記錄寫回資料庫。
  • 使用者 A 修改“舊”記錄並將其寫回資料庫。

在上述情況中,使用者 A 永遠也不會看到使用者 B 作出的更改。如果您計劃使用並發控制的“最後的更新生效”方法,則要確保這種情況是可以接受的。

ADO.NET 和 Visual Studio .NET 中的並發控制

因為資料結構基於斷開的資料,所以 ADO.NET 和 Visual Studio .NET 使用開放式並發。因此,您需要添加商務邏輯,以利用開放式並發解決問題。

如果您選擇使用開放式並發,則可以通過兩種常規的方法來確定是否已發生更改:版本方法(實際版本號碼或日期時間戳記)和儲存所有值方法。

版本號碼方法

在版本號碼方法中,要更新的記錄必須具有一個包含日期時間戳記或版本號碼的列。當讀取該記錄時,日期時間戳記或版本號碼將儲存在用戶端。然後,將對該值進行部分更新。

處理並發的一種方法是僅當 WHERE 子句中的值與記錄上的值匹配時才進行更新。該方法的 SQL 表示形式為:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2WHERE DateTimeStamp = @origDateTimeStamp

或者,可以使用版本號碼進行比較:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2WHERE RowVersion = @origRowVersionValue

如果日期時間戳記或版本號碼匹配,則表明資料存放區區中的記錄未被更改,並且可以安全地使用資料集中的新值對該記錄進行更新。如果不匹配,則將返回錯誤。您可以編寫代碼,在 Visual Studio .NET 中實現這種形式的並發檢查。您還必須編寫代碼來響應任何更新衝突。為了確保日期時間戳記或版本號碼的準確性,您需要在表上設定觸發器,以便在發生對行的更改時,對日期時間戳記或版本號碼進行更新。

儲存所有值方法

使用日期時間戳記或版本號碼的替代方法是在讀取記錄時擷取所有欄位的副本。ADO.NET 中的 DataSet 對象維護每個修改記錄的兩個版本:初始版本(最初從資料來源中讀取的版本)和修改版本(表示使用者更新)。當試圖將記錄寫回資料來源時,資料行中的初始值將與資料來源中的記錄進行比較。如果它們匹配,則表明資料庫記錄在被讀取後尚未經過更改。在這種情況下,資料集中已更改的值將成功地寫入資料庫。

對於資料配接器的四個命令(DELETE、INSERT、SELECT 和 UPDATE)來說,每個命令都有一個參數集合。每個命令都有用於初始值和當前值(或修改值)的參數。

注意    由於不存在初始記錄,添加新記錄(INSERT 命令)只需要當前值;移除記錄(DELETE 命令)只需要使用初始值來定位要刪除的記錄。

以下樣本顯示一個資料集命令的命令文本,該命令更新一個典型的客戶表。該命令是為動態 SQL 和開放式並發而指定的。

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFaxWHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,PostalCode, Phone, FaxFROM Customers WHERE (CustomerID = @currCustomerID)

請注意,九個 SET 語句參數表示將寫入資料庫的當前值,而九個 WHERE 語句參數則表示用於定位初始記錄的初始值。

前九個 SET 語句參數對應於參數集合中的前九個參數。這些參數會將其 SourceVersion 屬性設定為 Current

接著的九個 WHERE 語句參數用於開放式並發。這些預留位置對應於參數集合中接著的九個參數,這些參數的每一個都將其 SourceVersion 屬性設定為 Original

SELECT 語句用於在發生更新後重新整理資料集。它是您在“進階 SQL 產生選項”對話方塊中設定“重新整理資料集”選項時產生的。

注意    上面的 SQL 使用具名引數,而 OleDbDataAdapter 命令則使用問號 (?) 作為參數預留位置。

預設情況下,如果您在“資料配接器設定精靈”中選擇“開放式並發”選項,Visual Studio 將為您建立這些參數。此時將由您根據自己的業務要求來添加錯誤處理代碼。ADO.NET 提供了一個 DBConcurrencyException 對象,它返回違反並發規則的行。有關更多資訊,請參見處理並發錯誤。

講到並發處理,我們一般會分為兩個方面來說:a)伺服器層級的並發控制; b)程式層級的並發控制。

伺服器層級的並發控制:

Ø  調整伺服器應用程式池中的最大串連數。

對於Web 服務器,dudu在最佳化部落格園的伺服器的時候寫過以下的文章。

dudu 寫過讓Windows Server 2008+IIS 7+ASP.NET支援10萬個同時請求http://www.cnblogs.com/dudu/archive/2009/11/10/1600062.html

1. 調整IIS 7應用程式集區隊列長度

由原來的預設1000改為65535。

IIS Manager > ApplicationPools > Advanced Settings

Queue Length : 65535

2.  調整IIS 7的appConcurrentRequestLimit設定

由原來的預設5000改為100000。

appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000

在%systemroot%\System32\inetsrv\config\applicationHost.config中可以查看到該設定。

3. 調整machine.config中的processModel>requestQueueLimit的設定

由原來的預設5000改為100000。

<configuration>
<system.web>
<processModel requestQueueLimit="100000"/>

4. 修改註冊表,調整IIS 7支援的同時TCPIP串連數

由原來的預設5000改為100000。

reg add HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v MaxConnections /t REG_DWORD /d 1000000 

完成上述4個設定,就可以支援10萬個同時請求

 

Ø  對於DB伺服器同樣也可以調整最大串連數來做最佳化。

      在調整最佳化好最大串連數之後,就只有軟硬體負載平衡了。硬體負載平衡能夠直接通過智能交換器實現,處理能力強,而且與系統無關,但是價格貴,配置困難,不能區分實習系統與應用的狀態。所以硬體負載平衡適用於一大堆裝置,大訪問量,簡單應用。軟體負載平衡是基於系統與應用的,能過更好地根據系統與應用的狀況來分配負載。性價比高。PCL負載平衡軟體,Linux下的LVS軟體。

程式層級的並發控制:

當兩個使用者同時訪問一個頁面,一個使用者可能更新的事另一個使用者已經刪除的記錄。或者,在一個使用者載入頁面跟他點擊刪除按鈕之間的時間裡,另一個使用者修改了這條記錄的內容。

有下面三中並發控制策略可供選擇:

Ø 什麼都不做 –如果並發使用者修改的是同一條記錄,讓最後提交的結果生效(預設的行為)

Ø 開放式並發(Optimistic Concurrency - 假定並發衝突只是偶爾發生,絕大多數的時候並不會出現; 那麼,當發生一個衝突時,僅僅簡單的告知使用者,他所作的更改不能儲存,因為別的使用者已經修改了同一條記錄

Ø 保守式並發(Pessimistic Concurrency – 假定並發衝突經常發生,並且使用者不能容忍被告知自己的修改不能儲存是由於別人的並發行為;那麼,當一個使用者開始編輯一條記錄,鎖定該記錄,從而防止其他使用者編輯或刪除該記錄,直到他完成並提交自己的更改

當多個使用者試圖同時修改資料時,需要建立控制機制來防止一個使用者的修改對同時操作的其他使用者所作的修改產生不利的影響。處理這種情況的系統叫做“並發控制”。

並發控制的類型

通常,管理資料庫中的並發有三種常見的方法:

  • 保守式並發控制 - 在從擷取記錄直到記錄在資料庫中更新的這段時間內,該行對使用者不可用。
  • 開放式並發控制 - 只有當實際更新資料時,該行才對其他使用者不可用。更新將在資料庫中檢查該行並確定是否進行了任何更改。如果試圖更新已更改的記錄,則將導致並發衝突。
  • 最後的更新生效 - 只有當實際更新資料時,該行才對其他使用者不可用。但是,不會將更新與初始記錄進行比較;而只是寫出記錄,這可能就改寫了自上次重新整理記錄後其他使用者所進行的更改。
保守式並發

保守式並發通常用於兩個目的。第一,在某些情況下,存在對相同記錄的大量爭用。在資料上放置鎖所費的成本小於發生並發衝突時復原更改所費的成本。

在事務過程中不宜更改記錄的情況下,保守式並發也非常有用。庫存應用程式便是一個很好的樣本。假定有一個公司代表正在為一名潛在的客戶檢查庫存。您通常要鎖定記錄,直到產生訂單為止,這通常會將該項標記為“已訂購”狀態並將其從可用庫存中移除。如果未產生訂單,則將釋放該鎖,以便其他檢查庫存的使用者得到準確的可用庫存計數。

但是,在斷開的結構中無法進行保守式並發控制。串連開啟的時間只夠讀取資料或更新資料,因此不能長時間地保持鎖。此外,長時間保留鎖的應用程式將無法進行伸縮。

注意    如果基礎資料來源支援事務,則可以通過在事務中更新資料來類比保守式並發。有關更多資訊,請參見 ADO.NET 中的事務。

開放式並發

在開放式並發中,只有在訪問資料庫時才設定並保持鎖。這些鎖將防止其他使用者在同一時間更新記錄。除了進行更新這一確切的時刻之外,資料始終可用。有關更多資訊,請參見開放式並發。

當試圖更新時,已更改行的初始版本將與資料庫中的現有行進行比較。如果兩者不同,更新將失敗,並引發並發錯誤。這時,將由您使用所建立的商務邏輯來協調這兩行。

最後的更新生效

當使用“最後的更新生效”時,不會對初始資料進行檢查,而只是將更新寫入資料庫。很明顯,可能會發生以下情況:

  • 使用者 A 從資料庫擷取一項記錄。
  • 使用者 B 從資料庫擷取相同的記錄,對其進行修改,然後將更新後的記錄寫回資料庫。
  • 使用者 A 修改“舊”記錄並將其寫回資料庫。

在上述情況中,使用者 A 永遠也不會看到使用者 B 作出的更改。如果您計劃使用並發控制的“最後的更新生效”方法,則要確保這種情況是可以接受的。

ADO.NET 和 Visual Studio .NET 中的並發控制

因為資料結構基於斷開的資料,所以 ADO.NET 和 Visual Studio .NET 使用開放式並發。因此,您需要添加商務邏輯,以利用開放式並發解決問題。

如果您選擇使用開放式並發,則可以通過兩種常規的方法來確定是否已發生更改:版本方法(實際版本號碼或日期時間戳記)和儲存所有值方法。

版本號碼方法

在版本號碼方法中,要更新的記錄必須具有一個包含日期時間戳記或版本號碼的列。當讀取該記錄時,日期時間戳記或版本號碼將儲存在用戶端。然後,將對該值進行部分更新。

處理並發的一種方法是僅當 WHERE 子句中的值與記錄上的值匹配時才進行更新。該方法的 SQL 表示形式為:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2WHERE DateTimeStamp = @origDateTimeStamp

或者,可以使用版本號碼進行比較:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2WHERE RowVersion = @origRowVersionValue

如果日期時間戳記或版本號碼匹配,則表明資料存放區區中的記錄未被更改,並且可以安全地使用資料集中的新值對該記錄進行更新。如果不匹配,則將返回錯誤。您可以編寫代碼,在 Visual Studio .NET 中實現這種形式的並發檢查。您還必須編寫代碼來響應任何更新衝突。為了確保日期時間戳記或版本號碼的準確性,您需要在表上設定觸發器,以便在發生對行的更改時,對日期時間戳記或版本號碼進行更新。

儲存所有值方法

使用日期時間戳記或版本號碼的替代方法是在讀取記錄時擷取所有欄位的副本。ADO.NET 中的 DataSet 對象維護每個修改記錄的兩個版本:初始版本(最初從資料來源中讀取的版本)和修改版本(表示使用者更新)。當試圖將記錄寫回資料來源時,資料行中的初始值將與資料來源中的記錄進行比較。如果它們匹配,則表明資料庫記錄在被讀取後尚未經過更改。在這種情況下,資料集中已更改的值將成功地寫入資料庫。

對於資料配接器的四個命令(DELETE、INSERT、SELECT 和 UPDATE)來說,每個命令都有一個參數集合。每個命令都有用於初始值和當前值(或修改值)的參數。

注意    由於不存在初始記錄,添加新記錄(INSERT 命令)只需要當前值;移除記錄(DELETE 命令)只需要使用初始值來定位要刪除的記錄。

以下樣本顯示一個資料集命令的命令文本,該命令更新一個典型的客戶表。該命令是為動態 SQL 和開放式並發而指定的。

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFaxWHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,PostalCode, Phone, FaxFROM Customers WHERE (CustomerID = @currCustomerID)

請注意,九個 SET 語句參數表示將寫入資料庫的當前值,而九個 WHERE 語句參數則表示用於定位初始記錄的初始值。

前九個 SET 語句參數對應於參數集合中的前九個參數。這些參數會將其 SourceVersion 屬性設定為 Current

接著的九個 WHERE 語句參數用於開放式並發。這些預留位置對應於參數集合中接著的九個參數,這些參數的每一個都將其 SourceVersion 屬性設定為 Original

SELECT 語句用於在發生更新後重新整理資料集。它是您在“進階 SQL 產生選項”對話方塊中設定“重新整理資料集”選項時產生的。

注意    上面的 SQL 使用具名引數,而 OleDbDataAdapter 命令則使用問號 (?) 作為參數預留位置。

預設情況下,如果您在“資料配接器設定精靈”中選擇“開放式並發”選項,Visual Studio 將為您建立這些參數。此時將由您根據自己的業務要求來添加錯誤處理代碼。ADO.NET 提供了一個 DBConcurrencyException 對象,它返回違反並發規則的行。有關更多資訊,請參見處理並發錯誤。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.