同事報案,有個 ASP.NET 網站「偶爾」會出現提供者與 Oracle 從屬版本不相容錯誤。這是 Unmanaged ODP.NET 的經典茶包, 舉凡 Oracle Client 沒裝好、存取權限跑掉多版本並存都很容易踩到雷。(由衷建議大家改用 Managed ODP.NET,能有效改善生活品質)

但這次跟以前遇到的狀況不太一樣,不定期發生,出錯後 IISRESET 可恢復,若單純只是 Oracle Client 安裝或設定問題,不該時好時壞,看起來是枚變種茶包。

由同事提供資訊我找到一處可疑:該台 IIS 有多個 WebApplication,且部分 WebApplication 共用 AppPool。於是我大膽假設:會不會是共用 AppPool 的 WebApplication 使用不同版本 Oracle 彼此干擾?而啟動順序又決定是否出錯,例如:WebAP1 先啟動再跑 WebAP2 沒事;若 WebAP2 先起來則會讓 WebAP1 壞掉。

此推論若能成立,「不定期發生」跟「IISRESET 後正常」便可得到合理解釋。

我設計了一個實驗驗證假設,在 IIS 建立兩個 WebApplication - OraAP12 及 OraAP19,放入同一隻程式 default.aspx:

<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	var cs = "Data Source=MYORA;User ID=*****;Password=****;";
	var codeBase = typeof(Oracle.DataAccess.Client.OracleConnection).Assembly.CodeBase;
	Response.ContentType = "text/plain";
	try {
		using (var cn = new Oracle.DataAccess.Client.OracleConnection(cs))
		{
			cn.Open();
			var cmd = cn.CreateCommand();
			cmd.CommandText = "SELECT 'HELLO' AS t FROM DUAL";
			var dr = cmd.ExecuteReader();
			dr.Read();
			Response.Write(dr["t"] + "\n" + codeBase);
		}
	}
	catch (System.ApplicationException ex) 
	{
		Response.Write("ERROR-" + ex.Message);
		if (ex.InnerException != null) 
		{
			Response.Write("\n" + ex.InnerException.Message);
		}
	}
}
</script>

兩個資料夾只差在 bin\Oracle.DataAccess.dll 版本不同,OraAP12 是 2.122.1,OraAP19 則是 2.122.19,二者共用同一個 AppPool。

正常執行的話應要看到 HELLO 及 ODP.NET 版號:(遇有一個現象值得注意,Inline ASPX 採現場編譯,bin\Oracle.DataAccess.dll 會決定參照版本,但因 GAC 已註冊,實際用的是 GAC 版本。延伸閱讀:ASP.NET /bin 組件載入跟你想的不一樣)

來看看先啟動 OraAP12 或先啟動 OraAP19 結果會不會不一樣? 這種情境,Windows Terminal 的分割窗格特別好用,在 IISRESET 之後先啟用 OraAP19 再啟用 OraAP12 (下圖上方),兩個 WebApplication 都正常; 若 IISRESET 後先啟用 OraAP12 再啟用 OraAP19,則 OraAP19 會發生 'Oracle.DataAccess.Client.OracleConnection' 的類型初始設定式發生例外狀況。無法載入 DLL 'OraOps19.dll': 找不到指定的程序。 (發生例外狀況於 HRESULT: 0x8007007F) 錯誤。

由實驗結果可知- 若 WebApplication 共用 AppPool 又使用不同版本 Unmanaged ODP.NET,二者可能互相干擾,且出錯與否由 WebApplication 啟動順序決定。

因此,實務上應避免共用 AppPool,除了避免互相干擾,網站發生問題時能從工作管理員確認各 WebApplication 使用的 CPU、記憶體,有利於釐清問題。

最後不免推一把 - 多想兩分鐘,你可以不要用 Unmanaged ODP.NET,改用 Managed ODP.NET 人生更快活。

A issue of Oracle client version conflict between two web apllication sharing one AppPoool.


Comments

# by Huang

IIS集區分開是好習慣,雖然會有多個connection

# by Jackson245

廠商跟我說,網站設計一定要 SQL server,但當初規劃時沒列入這個項目。 目前只能用 SQL express 暫頂一下,資料量小於 100萬筆 但又說不贏廠商,請問這是真的嗎?

# by Jeffrey

to Jackson245,SQL Express 有性能及管理能力上的限制,細節可參考這篇 https://blog.darkthread.net/blog/sql-oracle-free-editions/,如果流量不大,是可以在發展初期先頂著,待不夠用時再無痛升級 Standard。(搬資料庫要花功夫就是了)

Post a comment


49 - 44 =