2015-09-27 24 views
5

Chúng tôi có dịch vụ web C# WCF được lưu trữ trên Windows 2008 SP2/IIS 7 truy cập cơ sở dữ liệu Oracle. Thường truy cập dữ liệu hoạt động tốt nhưng trong quá trình thử tải, nó thường lần ra ngoài và các bản ghi và ngoại lệ nói:Nhà cung cấp dữ liệu Oracle cho .NET: Yêu cầu kết nối đã hết thời gian

Error occurred when processing XXXXXXXX Web Service 
Oracle.DataAccess.Client.OracleException Connection request timed out at Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck) 
    at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, Object src) 
    at Oracle.DataAccess.Client.OracleConnection.Open() 
    at MyWorkspace.WorkForceDataAccess.CheckStaffIdInRSW() 
    at MyWorkspace.MyClass.MyFunction(MyDataType MyData) 

Để truy vấn cơ sở dữ liệu, chúng tôi sử dụng một cái gì đó như thế này:

OracleConnection orConn = new OracleConnection(); 
orConn.ConnectionString = "user id=xxx; password=xxx; Connection Timeout=600; Max Pool Size=150; data source= (DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST.MYDOMAIN.com)(PORT = 1771)) (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = MYSERVICE.MYDOMAIN.com)))"; 
orConn.Open(); 

using (var cmd = new OracleCommand("MY_UTIL.check_StaffIdInRSW", orConn) { CommandType = CommandType.StoredProcedure }) 
{ 
    cmd.Parameters.Add("P_Staff_Id", OracleDbType.Int32); 
    cmd.Parameters["P_Staff_Id"].Direction = ParameterDirection.Input; 
    cmd.Parameters["P_Staff_Id"].Value = Convert.ToInt32(MyDataObject.StaffId); 

    cmd.Parameters.Add("P_retvalue", OracleDbType.Int32); 
    cmd.Parameters["P_retvalue"].Direction = ParameterDirection.Output; 

    cmd.ExecuteNonQuery(); // Execute the function 

    //obtain result 
    returnVal = int.Parse(cmd.Parameters["P_retvalue"].Value.ToString()); 
} 

Tôi khá tự tin rằng thủ tục được lưu trữ đang được gọi không phải lúc nào cũng được thực hiện. Đó là một thủ tục khá đơn giản để kiểm tra nhanh nếu P_Staff_Id tồn tại trong bảng và trả về kết quả.

Ngoài ra, điều này chỉ xảy ra trong khi kiểm tra tải. Trong quá trình hoạt động bình thường, mọi thứ vẫn ổn nhưng trong quá trình tải nặng với 1 tin nhắn mỗi giây, điều này xảy ra sau khi chạy trơn tru trong một thời gian.

Là một workaround, tôi đã thêm "Connection Timeout = 600; Max Pool Size = 150“ vào chuỗi kết nối, nhưng điều đó không khắc phục được vấn đề này

Chúng tôi đã cùng một ứng dụng đang chạy trên một máy chủ phát triển. và nó hoạt động tốt. Chúng tôi không bao giờ gặp phải vấn đề này ở đó.

Bất kỳ lời đề nghị như những gì để cố gắng sẽ được đánh giá. Dường như tôi đang chạy ra các tùy chọn.

+0

Các stacktrace gợi ý rằng các thủ tục không phải là vấn đề. Ngoại lệ được nâng lên trước khi thực thi trong Connection.Open, vì vậy có vẻ như máy cơ sở dữ liệu bị quá tải nên nó không thể đáp ứng với máy khách trong khoảng thời gian chờ. Nó không nên liên quan đến kích thước hồ bơi hoặc các quy trình hạn chế trong Oracle, các trường hợp ngoại lệ ném khác nhau. Ngoài ra tôi sẽ nghi ngờ về kích thước hồ bơi đó bởi vì nó sẽ không có ý nghĩa để có hồ bơi lớn hơn đáng kể so với số lượng cơ sở dữ liệu lõi có thể sử dụng. Hoặc bạn có rò rỉ kết nối ở đâu đó. – Husqvik

+0

Tôi đã thêm Thời gian chờ kết nối và Kích thước nhóm tối đa cho chuỗi kết nối sau khi vấn đề này xuất hiện - nhưng nó không giúp ích gì. Dịch vụ web đã hoạt động tốt trong môi trường DEV mà không có các dịch vụ này. Bằng cách rò rỉ kết nối, bạn có đề nghị đóng và xử lý đối tượng OracleConnection một cách rõ ràng sau khi nó được sử dụng không? – DjD

+0

Kết nối quảng cáo bị rò rỉ - nếu đối tượng kết nối chỉ ngắn ngủi trong một hàm duy nhất thì sử dụng (var connection = ...) {...} chắc chắn là an toàn hơn. Nhưng tôi không nghĩ đây là vấn đề. Bạn sẽ nhận được ngoại lệ khác nhau khi hồ bơi được sử dụng đầy đủ. Thử nghiệm tải quảng cáo - Tôi hy vọng bạn chạy nhiều phiên bản của ứng dụng hoặc chức năng song song. Cũng hy vọng rằng bạn sử dụng kết nối chuyên dụng, không phải máy chủ được chia sẻ như cài đặt Oracle. Bạn có thể kiểm tra xem các phiên xem xét trong cơ sở dữ liệu trong quá trình thử nghiệm để xem có bao nhiêu phiên và có bao nhiêu phiên hoạt động thực sự có. – Husqvik

Trả lời

4

Chúng tôi đã có một vấn đề tương tự, và phải mất một thời gian để gỡ lỗi này và sửa lỗi này. Mã của chúng tôi về việc bị nhấn mạnh với nhiều tệp đầu vào và nhiều luồng xử lý, mỗi luồng d bằng cách sử dụng khung Entity và mở kết nối Oracle db, và thực hiện một loạt các truy vấn db và chèn, được sử dụng để thỉnh thoảng tệp. Nhưng hoạt động hầu hết thời gian.

Tôi đã sửa đổi hàm khởi tạo DbContext để mở OracleConnection một cách rõ ràng. Tôi đã thêm một số mã như thế này

for (i = 0; i < 5; i++) 
    try { 
     oracleConnection.Open(); 
    } catch (OracleException) { 
    Sleep for 15 ms and retry. 
    On last attempt I also do OracleConnection.ClearAllPools() 
    } 

Nó được cải thiện nhưng vẫn chưa giải quyết hoàn toàn. Tôi đã phá vỡ trong bắt từ trình gỡ rối, và thấy rằng nhiều chủ đề đang cố gắng để mở và vài chủ đề đang xử lý đi. Mở Mở trong ngăn xếp Oracle, Oracle cho mục đích nội bộ của nó là ThreadPool.QueueUserWorkItem và chờ hoàn thành. Tôi có thể nhìn thấy trên đỉnh của chồng chờ đợi của nó. Ở đây rất nhiều kết nối gộp lại có sẵn (mặc định là 100), tôi hầu như không sử dụng 10. Vì vậy, nó không phải là ra khỏi tài nguyên.

Nhưng vấn đề là trong mã của chúng tôi, chúng tôi cũng sử dụng ThreadPool.QueueUserWorkItem mà không cần điều chỉnh thêm. Tôi nghĩ rằng đó là mát mẻ để chỉ xếp hàng tất cả các công việc chúng ta cần phải làm, bao nhiêu chúng ta cần đến này, và để cho. NET chăm sóc này. Nhưng điều này có vấn đề tinh tế. Tất cả các công việc của chúng tôi đã tiêu thụ toàn bộ số lượng hàng đợi. Khi OracleConnection muốn nhận một kết nối gộp từ nhóm, nó cũng xếp hàng vào nhóm luồng. Nhưng nó sẽ không bao giờ hoàn thành. Các công việc của chúng tôi đang chờ đợi cho OracleConnection.Open, và nó sẽ được xếp hàng đợi. Vì vậy, cuối cùng chờ đợi sẽ thoát theo thời gian chờ. Thật đáng tiếc là mặc dù có rất nhiều kết nối gộp lại có sẵn, chúng tôi đã tiêu thụ tất cả proc ThreadPool, và threadpool của Oracle thậm chí không có cơ hội. Ở đây thiết lập ThreadPool.SetMaxThreads cũng sẽ không giúp ích gì. Vấn đề vẫn như cũ. Chúng tôi hog tất cả các nguồn tài nguyên hồ bơi thread, và Orcale sẽ không tìm thấy một và vẫn sẽ được xếp hàng.

Việc khắc phục không chỉ dựa vào ThreadPool mà còn thêm điều chỉnh riêng của chúng tôi. Tôi đã sử dụng BlockingCollection và sempahores và chỉ thêm một số giới hạn số lượng công việc đồng thời trong ThreadPool, nói 5. Bằng cách này OracleConnection sẽ luôn luôn tìm thấy một ThreadPool thread có sẵn, và sẽ không thất bại.

1

thử thêm connection.close() ở cuối. Tôi không thấy phát hành các kết nối trong mã của bạn và trả lại chúng cho kết nối một cách rõ ràng. Vì vậy, kết nối chỉ được trả về hồ bơi kết nối khi bắt đầu GC.

+0

Chúng tôi đã triển khai một kết nối như thế này. đóng() để đóng các kết nối một cách rõ ràng và dường như hoạt động. Cảm ơn mọi sự giúp đỡ của bạn. – DjD

1

Thậm chí tôi đã sử dụng để có được vấn đề này thường gặp hơn, ngay cả sau khi sử dụng connection.close()

Sau một phân tích từ lâu tôi đã học được vài điều như đã đề cập dưới đây

  1. connection.close () không vứt bỏ kết nối db
  2. Thời gian kết nối không có nghĩa là vấn đề chỉ với truy vấn db
  3. Thời gian kết nối cũng có thể là do các kết nối đầy đủ trong nhóm kết nối (thủ phạm đó là do nó đạt đến mức tối đa phiên imum của kết nối db)

Fix: - Phân tích mất thời gian dài nhưng sửa chữa là chỉ 2 phút

using(DbConnection instance) 
{ 

} 

Ví dụ: -

using (DbConnection objDbConnection = new DbConnection()) 
{ 
    ojDbConnection.PersistData(); 
} 

Dưới PersistData(); Tất cả các thao tác db như Open, đóng e.tc. sẽ được thực hiện

Như chúng ta đều biết "Sử dụng" là viết tắt của

try 
{ 

} 
catch() 
{ 

} 
Finally 
{ 
    Dispose objDbConnection; 
} 

Hy vọng nó sẽ giúp, vì nó giúp tôi

Các vấn đề liên quan