.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軟件。
二、對數據庫層面的處理
- 當兩個用戶同時訪問一個頁面,一個用戶可能更新的是另一個用戶已經刪除的記錄。
- 在一個用戶加載頁面與他點擊刪除按鈕之間的時間里,另一個用戶修改了這條記錄的內容。
所以需要考慮數據庫鎖
的問題。
有下面三中並發控制策略可供選擇:
- 什么都不做 – 如果並發用戶修改的是同一條記錄,讓最后提交的結果生效(默認的行為)。
- 開放式並發(Optimistic Concurrency - 假定並發沖突只是偶爾發生,絕大多數的時候並不會出現; 那么,當發生一個沖突時,僅僅簡單的告知用戶,他所作的更改不能保存,因為別的用戶已經修改了同一條記錄。
- 保守式並發(Pessimistic Concurrency) – 假定並發沖突經常發生,並且用戶不能容忍被告知自己的修改不能保存是由於別人的並發行為;那么,當一個用戶開始編輯一條記錄,鎖定該記錄,從而防止其他用戶編輯或刪除該記錄,直到他完成並提交自己的更改。
當多個用戶試圖同時修改數據時,需要建立控制機制來防止一個用戶的修改對同時操作的其他用戶所作的修改產生不利的影響。處理這種情況的系統叫做“並發控制”。
並發控制的類型
通常,管理數據庫中的並發有三種常見的方法:
- 保守式並發控制 - 在從獲取記錄直到記錄在數據庫中更新的這段時間內,該行對用戶不可用。
- 開放式並發控制 - 只有當實際更新數據時,該行才對其他用戶不可用。更新將在數據庫中檢查該行並確定是否進行了任何更改。如果試圖更新已更改的記錄,則將導致並發沖突。
- 最后的更新生效 - 只有當實際更新數據時,該行才對其他用戶不可用。但是,不會將更新與初始記錄進行比較;而只是寫出記錄,這可能就改寫了自上次刷新記錄后其他用戶所進行的更改。
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
)來說,每個命令都有一個參數集合。每個命令都有用於初始值和當前值(或修改值)的參數。
第二類情況的處理:
因為是大並發請求
,也能采用第一種情況的處理方法,
另外,因為是對大數據量
進行檢索,所以需要考慮查詢效率
的問題:
- 對表按查詢條件建立索引
- 對查詢語句進行優化
- 可以考慮對查詢數據使用緩存
第三類情況的處理:
也能采用第一種情況的處理方法,
另外因為是對同一個表進行更新操作,可以考慮使用下面的處理方法:
- 先將數據保存到緩存中,當數據達到一定的數量后,再更新到數據庫中
- 將表按
索引
划分(分表,分區
),如:對於一個存儲全國人民信息的表,這個數據量是很大的,如果按省划分為多個表,在將全國的人民信息按省存儲到相應的表中,然后根據省份對相應的並進行查詢和更新,這樣大並發和大數據量的問題就會減小很多