Khách Tác giả:Michael J Swart (@MJSwart)
Gần đây, chúng tôi đã rất ngạc nhiên bởi một số ngoại lệ mà ứng dụng của chúng tôi đã ném ra. Ứng dụng của chúng tôi không thành công khi cố gắng Mở một SqlConnection. Các trường hợp ngoại lệ trông như thế này:
Error System.InvalidOperationException:Thời gian hết hạn. Khoảng thời gian chờ đã trôi qua trước khi nhận được kết nối từ nhóm. Điều này có thể đã xảy ra vì tất cả các kết nối tổng hợp đã được sử dụng và đã đạt đến kích thước nhóm tối đa.
Bể bơi kết nối
Hãy nhớ rằng .Net sử dụng nhóm kết nối để giúp tránh chi phí thiết lập kết nối trên mọi truy vấn. Nhóm kết nối được duy trì cho mọi chuỗi kết nối và theo mặc định, số lượng kết nối trong nhóm được giới hạn ở một trăm. Một trăm kết nối thường là đủ. Chúng tôi chưa bao giờ gặp sự cố với ngoại lệ này trước đây và máy chủ của chúng tôi không bận hơn bình thường, vì vậy chúng tôi đã do dự trong việc tăng giá trị của MaxPoolSize. Chúng tôi bắt đầu nghi ngờ rò rỉ kết nối cơ sở dữ liệu.
Rò rỉ kết nối cơ sở dữ liệu
Cũng giống như rò rỉ bộ nhớ, rò rỉ kết nối cơ sở dữ liệu có thể xảy ra nếu bạn không xử lý kịp thời các kết nối cơ sở dữ liệu của mình. SqlConnections là IDisposable vì vậy phương pháp hay nhất là sử dụng câu lệnh using:
using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); // etc... }
Ngay sau khi bạn thực hiện xong SqlConnection, nó sẽ bị loại bỏ và kết nối thực tế ngay lập tức trở lại nhóm kết nối để người khác có thể sử dụng nó. Nếu không, kết nối vẫn được sử dụng cho đến khi quá trình kết thúc hoặc quá trình thu gom rác dọn sạch nó.
Tìm rò rỉ kết nối của bạn
Vì vậy, nếu ứng dụng của bạn gặp phải tình trạng hết thời gian chờ kết nối do rò rỉ kết nối cơ sở dữ liệu, dấu vết ngăn xếp có thể không giúp được bạn. Cũng giống như ngoại lệ hết bộ nhớ do rò rỉ bộ nhớ, dấu vết ngăn xếp có thông tin về nạn nhân, nhưng không phải là nguyên nhân gốc rễ. Vì vậy, bạn có thể đi đâu để tìm rò rỉ?
Mặc dù rò rỉ kết nối cơ sở dữ liệu là một vấn đề của máy khách, bạn có thể tìm thấy sự trợ giúp từ máy chủ cơ sở dữ liệu. Trên máy chủ cơ sở dữ liệu, hãy xem các kết nối trên mỗi quá trình trên mỗi cơ sở dữ liệu để có được ước tính sơ bộ về kích thước của mỗi nhóm:
select count(*) as sessions, s.host_name, s.host_process_id, s.program_name, db_name(s.database_id) as database_name from sys.dm_exec_sessions s where is_user_process = 1 group by host_name, host_process_id, program_name, database_id order by count(*) desc;
Tên chương trình, tên máy chủ, id tiến trình và tên cơ sở dữ liệu thường đủ tốt để xác định các kết nối đến từ cùng một nhóm kết nối.
Điều này khiến tôi phải hỏi thêm một số câu hỏi về các nhóm có nhiều kết nối. Với một nhóm, có những phiên đã ngủ trong một thời gian và nếu có, chúng đã ngủ bao lâu và câu lệnh SQL cuối cùng mà chúng đã thực thi là gì?
declare @host_process_id int = 1508; declare @host_name sysname = N'SERV4102'; declare @database_name sysname = N'My_Database'; select datediff(minute, s.last_request_end_time, getdate()) as minutes_asleep, s.session_id, db_name(s.database_id) as database_name, s.host_name, s.host_process_id, t.text as last_sql, s.program_name from sys.dm_exec_connections c join sys.dm_exec_sessions s on c.session_id = s.session_id cross apply sys.dm_exec_sql_text(c.most_recent_sql_handle) t where s.is_user_process = 1 and s.status = 'sleeping' and db_name(s.database_id) = @database_name and s.host_process_id = @host_process_id and s.host_name = @host_name and datediff(second, s.last_request_end_time, getdate()) > 60 order by s.last_request_end_time;
Văn bản hiện có thể được sử dụng để tìm kiếm cơ sở mã ứng dụng của bạn để tìm nơi bạn có thể bị rò rỉ kết nối cơ sở dữ liệu.
Các truy vấn này hữu ích để khắc phục sự cố rò rỉ kết nối cơ sở dữ liệu và chúng cũng có thể được sử dụng để tạo màn hình hoặc kiểm tra tình trạng.
Vứt bỏ những đồ dùng một lần của bạn, sử dụng những đồ dùng đó, bịt kín những chỗ rò rỉ đó!