2012-01-25 37 views
15

Tôi thấy thông báo "Thời gian chờ đã hết hạn trước khi nhận kết nối từ hồ bơi".Làm thế nào để tìm rò rỉ xử lý hồ bơi kết nối db?

Tôi đã tìm kiếm mã cho bất kỳ kết nối db không được đính kèm nào, nhưng không thể tìm thấy bất kỳ kết nối nào.

Điều tôi muốn làm là: lần sau chúng tôi gặp lỗi này, hệ thống sẽ liệt kê danh sách các procs hoặc yêu cầu http đang giữ tất cả các tay cầm, vì vậy tôi có thể tìm ra mã nào đang gây ra sự cố.

Thậm chí tốt hơn là nên xem các nắm giữ đã được giữ trong bao lâu, vì vậy tôi có thể phát hiện các kết nối được sử dụng nhưng không được tiết lộ.

Có cách nào để thực hiện việc này không?

+0

Có thể bạn có nhiều người dùng hơn kết nối trong hồ bơi không? –

+0

Bạn có lưu trữ các tham chiếu kết nối của mình ở trạng thái phiên hoặc một nơi khác có thời lượng vượt quá một yêu cầu http không? – Jan

+0

Không, chúng chỉ được mở và (được cho là) ​​đóng trên mỗi yêu cầu. – Jesse

Trả lời

5

Có một số liên kết tốt để theo dõi hồ bơi kết nối. Thực hiện tìm kiếm google cho ".net connection pool monitoring".

Một bài viết tôi đã đề cập đến trong khi quay lại là Bill Vaughn's article (Lưu ý đây là cũ nhưng vẫn chứa thông tin hữu ích). Nó có một số thông tin về giám sát các hồ bơi kết nối, nhưng một số thông tin chi tiết tuyệt vời về những nơi rò rỉ có thể xảy ra là tốt.

Để theo dõi, ông đề xuất;

"Giám sát hồ bơi kết nối

Được rồi, vì vậy bạn mở một kết nối và đóng cửa nó và muốn biết nếu kết nối vẫn được đặt ra-tiều tụy trong hồ bơi kết nối trên một nệm không khí. Vâng , có một số cách để xác định có bao nhiêu kết nối vẫn còn ở vị trí (vẫn được kết nối) và thậm chí những gì chúng đang thực hiện. TSQL_Replay mẫu cho dấu vết. Đối với những người bạn quen thuộc với Profiler, điều này dễ hơn việc bỏ phiếu bằng SP_WHO.

· Chạy SP_WHO hoặc SP_WHO2, trả về thông tin từ bảng sysprocesses trên tất cả các quy trình làm việc cho biết trạng thái hiện tại của mỗi quá trình. Nói chung, có một quy trình máy chủ SPID cho mỗi kết nối . Nếu bạn đã đặt tên cho kết nối của mình, hãy sử dụng đối số Tên ứng dụng trong chuỗi kết nối, nó sẽ dễ tìm.

· Sử dụng màn hình hiệu suất (PerfMon) để theo dõi các hồ bơi và kết nối. Tôi thảo luận chi tiết này tiếp theo.

· Giám sát bộ đếm hiệu suất bằng mã. Tùy chọn này cho phép bạn hiển thị hoặc chỉ cần theo dõi sức khỏe của hồ bơi kết nối của bạn và số lượng kết nối được thiết lập. Tôi thảo luận về điều này trong phần tiếp theo trong bài báo này."

Edit:

Như mọi khi, kiểm tra một số các other similar posts đây trên SO

Second Edit:

Một khi bạn đã xác nhận rằng kết nối được không đang được khai hoang bên hồ bơi, một thứ khác bạn có thể thử là sử dụng sự kiện StateChange để xác nhận khi nào các kết nối đang được mở và đóng lại, nếu bạn thấy rằng có rất nhiều e thay đổi trạng thái để mở hơn là đóng, sau đó sẽ chỉ ra rằng có rò rỉ ở đâu đó. Bạn cũng có thể đăng nhập dữ liệu trong sự kiện được statechanged cùng với dấu thời gian và nếu bạn có bất kỳ đăng nhập nào khác trên ứng dụng của mình, bạn có thể bắt đầu phân tích cú pháp tệp nhật ký cho các trường hợp có vẻ như thay đổi trạng thái đóng để mở không có mở tương ứng để đóng. Xem this link để biết thêm thông tin về cách xử lý StateChangedEvent.

+0

Nếu các kết nối vẫn mở trong hồ bơi, bạn có thể thấy như thế nào trong SQL Profiler khi chúng bị mồ côi? Có vẻ như thông tin tôi muốn không có trong db, nhưng trong lớp quản lý nhóm. – Jesse

+0

Tôi không thể nhận xét về tùy chọn SQL Profiler vì tôi chưa sử dụng tùy chọn này để giám sát các hồ bơi kết nối. Thông tin thêm về loại thông tin bạn có thể nhận được từ PerfMon và quầy hiệu suất (cặp vợ chồng cuối cùng mà anh ta nói về có thể tìm thấy tại . tại đây chỉ ** sau ** bạn nhận được "lỗi đáng sợ" sẽ không cho bạn biết ** khi ** họ đã bị mồ côi mặc dù. Tôi đã thăm dò dữ liệu bằng cách sử dụng các bộ đếm hiệu suất chủ yếu để xác nhận rằng số lượng kết nối trong Một khi đã được xác nhận, bạn phải săn lùng nó –

+0

Hmm.Không chính xác viên đạn bạc tôi đang tìm kiếm, nhưng tôi đánh giá cao sự giải thích kỹ lưỡng! – Jesse

0

tôi đã sử dụng này

http://www.simple-talk.com/sql/performance/how-to-identify-slow-running-queries-with-sql-profiler/

để tìm dài chạy thủ tục được lưu trữ trước đó, tôi sau đó có thể làm việc trở lại và tìm ra phương pháp mà gọi là SP.

không biết nếu điều đó sẽ giúp

+0

Vấn đề (tôi nghĩ) tôi đang gặp phải là không có các truy vấn chạy chậm - đó là với mã chạy truy vấn, sau đó không buông tay cầm db. – Jesse

13

Nếu bạn đủ may mắn khi việc tạo/mở kết nối được tập trung thì lớp sau sẽ giúp dễ dàng phát hiện các kết nối bị rò rỉ. Thưởng thức :)

/// <summary> 
/// This class can help identify db connection leaks (connections that are not closed after use). 
/// Usage: 
/// connection = new SqlConnection(..); 
/// connection.Open() 
/// #if DEBUG 
/// new ConnectionLeakWatcher(connection); 
/// #endif 
/// That's it. Don't store a reference to the watcher. It will make itself available for garbage collection 
/// once it has fulfilled its purpose. Watch the visual studio debug output for details on potentially leaked connections. 
/// Note that a connection could possibly just be taking its time and may eventually be closed properly despite being flagged by this class. 
/// So take the output with a pinch of salt. 
/// </summary> 
public class ConnectionLeakWatcher : IDisposable 
{ 
    private readonly Timer _timer = null; 

    //Store reference to connection so we can unsubscribe from state change events 
    private SqlConnection _connection = null; 

    private static int _idCounter = 0; 
    private readonly int _connectionId = ++_idCounter; 

    public ConnectionLeakWatcher(SqlConnection connection) 
    { 
     _connection = connection; 
     StackTrace = Environment.StackTrace; 

     connection.StateChange += ConnectionOnStateChange; 
     System.Diagnostics.Debug.WriteLine("Connection opened " + _connectionId); 

     _timer = new Timer(x => 
     { 
      //The timeout expired without the connection being closed. Write to debug output the stack trace of the connection creation to assist in pinpointing the problem 
      System.Diagnostics.Debug.WriteLine("Suspected connection leak with origin: {0}{1}{0}Connection id: {2}", Environment.NewLine, StackTrace, _connectionId); 
      //That's it - we're done. Clean up by calling Dispose. 
      Dispose(); 
     }, null, 10000, Timeout.Infinite); 
    } 

    private void ConnectionOnStateChange(object sender, StateChangeEventArgs stateChangeEventArgs) 
    { 
     //Connection state changed. Was it closed? 
     if (stateChangeEventArgs.CurrentState == ConnectionState.Closed) 
     { 
      //The connection was closed within the timeout 
      System.Diagnostics.Debug.WriteLine("Connection closed " + _connectionId); 
      //That's it - we're done. Clean up by calling Dispose. 
      Dispose(); 
     } 
    } 

    public string StackTrace { get; set; } 

    #region Dispose 
    private bool _isDisposed = false; 

    public void Dispose() 
    { 
     if (_isDisposed) return; 

     _timer.Dispose(); 

     if (_connection != null) 
     { 
      _connection.StateChange -= ConnectionOnStateChange; 
      _connection = null; 
     } 

     _isDisposed = true; 
    } 

    ~ConnectionLeakWatcher() 
    { 
     Dispose(); 
    } 
    #endregion 
} 
+0

Điều này đã giúp chúng tôi tìm thấy một kết nối đã được mở và không bao giờ đóng Lớp thực sự tuyệt vời :) Cảm ơn rất nhiều! – Challe

+0

Tuyệt vời! Vui mừng khi biết điều này có thể được sử dụng cho người khác. – LOAS

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