1. 程式人生 > >.NET 大資料量併發解決方案

.NET 大資料量併發解決方案

大併發大資料量請求一般會分為幾種情況:

大量的使用者同時對系統的不同功能頁面進行查詢、更新操作
大量的使用者同時對系統的同一個頁面,同一個表的大資料量進行查詢操作

大量的使用者同時對系統的同一個頁面,同一個表進行更新操作

第一類情況 :大量的使用者同時對系統的不同功能頁面進行查詢、更新操作

一、對伺服器層面的處理

1. 調整IIS 7應用程式池佇列長度

由原來的預設1000改為65535。

IIS Manager > ApplicationPools > Advanced Settings
Queue Length : 65535

2. 調整IIS 7的appConcurrentRequestLimit設定

由原來的預設5000改為100000。
c:\windows\system32\inetsrv\appcmd.exe set config /section:serverRuntime /appConcurrentRequestLimit:100000
%systemroot%\System32\inetsrv\config\applicationHost.config中可以檢視到該設定:<serverRuntime appConcurrentRequestLimit="100000" />

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\Parameteris /v MaxConnections /t REG_DWORD /d 100000

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

如果訪問量達到10萬以上,就可以考慮將程式 和資料庫 按功能模組劃分,部署到多個伺服器分擔訪問壓力


另外可以考慮軟硬體負載均衡 。

  • 硬體負載均衡 能夠直接通過智慧交換機 實現,處理能力強,而且與系統無關,但是價格貴,配置困難,不能區分實習系統與應用的狀態。所以硬體負載均衡適用於一大堆裝置,大訪問量,簡單應用 。
  • 軟體負載均衡 是基於系統與應用的,能過更好地根據系統與應用的狀況來分配負載。價效比高。PCL負載均衡軟體,Linux下的LVS軟體。

二、對資料庫層面的處理

  1. 當兩個使用者同時訪問一個頁面,一個使用者可能更新的是另一個使用者已經刪除的記錄。
  2. 在一個使用者載入頁面與他點選刪除按鈕之間的時間裡,另一個使用者修改了這條記錄的內容。
    所以需要考慮資料庫鎖的問題

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

  • 什麼都不做 – 如果併發使用者修改的是同一條記錄,讓最後提交的結果生效(預設的行為)。
  • 開放式併發(Optimistic Concurrency - 假定併發衝突只是偶爾發生,絕大多數的時候並不會出現; 那麼,當發生一個衝突時,僅僅簡單的告知使用者,他所作的更改不能儲存,因為別的使用者已經修改了同一條記錄。
  • 保守式併發(Pessimistic Concurrency) – 假定併發衝突經常發生,並且使用者不能容忍被告知自己的修改不能儲存是由於別人的併發行為;那麼,當一個使用者開始編輯一條記錄,鎖定該記錄,從而防止其他使用者編輯或刪除該記錄,直到他完成並提交自己的更改。

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

併發控制的型別

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

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

1. 保守式併發

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

事務過程中不宜更改記錄的情況下,保守式併發也非常有用。庫存應用程式便是一個很好的示例。

假定有一個公司代表正在為一名潛在的客戶檢查庫存。
您通常要鎖定記錄,直到生成訂單為止,這通常會將該項標記為“已訂購”狀態並將其從可用庫存中移除。
如果未生成訂單,則將釋放該鎖,以便其他檢查庫存的使用者得到準確的可用庫存計數。

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

2. 開放式併發

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

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

3. 最後的更新生效

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

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

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

三、ADO.NET 和 Visual Studio .NET 中的併發控制

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

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

1. 版本號方法

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

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

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE DateTimeStamp = @origDateTimeStamp

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

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE RowVersion = @origRowVersionValue

如果日期時間戳或版本號匹配,則表明資料儲存區中的記錄未被更改,並且可以安全地使用資料集中的新值對該記錄進行更新;
如果不匹配,則將返回錯誤。

您可以編寫程式碼,在 Visual Studio .NET 中實現這種形式的併發檢查。您還必須編寫程式碼來響應任何更新衝突。
為了確保日期時間戳或版本號的準確性,您需要在上設定觸發器,以便在發生對行的更改時,對日期時間戳或版本號進行更新。

2. 儲存所有值方法

使用日期時間戳或版本號的替代方法是,在讀取記錄時獲取所有欄位的副本
ADO.NET 中的 DataSet 物件維護每個修改記錄的兩個版本:

初始版本(最初從資料來源中讀取的版本)和修改版本(表示使用者更新)。

當試圖將記錄寫回資料來源時,資料行中的初始值將與資料來源中的記錄進行比較。
如果它們匹配,則表明資料庫記錄在被讀取後尚未經過更改
在這種情況下,資料集中已更改的值將成功地寫入資料庫。
對於資料介面卡的四個命令(DELETE、INSERT、SELECT 和 UPDATE)來說,每個命令都有一個引數集合。每個命令都有用於初始值和當前值(或修改值)的引數。

第二類情況的處理:

因為是大併發請求,也能採用第一種情況的處理方法,
另外,因為是對大資料量進行檢索,所以需要考慮查詢效率的問題:

  1. 對錶按查詢條件建立索引
  2. 對查詢語句進行優化
  3. 可以考慮對查詢資料使用快取

第三類情況的處理:

也能採用第一種情況的處理方法,
另外因為是對同一個表進行更新操作,可以考慮使用下面的處理方法:

  1. 先將資料儲存到快取中,當資料達到一定的數量後,再更新到資料庫中
  2. 將表按索引劃分(分表,分割槽),如:對於一個儲存全國人民資訊的表,這個資料量是很大的,如果按省劃分為多個表,在將全國的人民資訊按省儲存到相應的表中,然後根據省份對相應的並進行查詢和更新,這樣大併發和大資料量的問題就會減小很多