Это будет длинный пост, поэтому, пожалуйста, держитесь со мной.
Один из рабочих мест, которые мы реализовали здесь на работе несколько месяцев назад, я начал так часто видеть сообщение об ошибке утечки соединения в наших журналах ELMAH.
"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached."
Это озадачило меня, поскольку мы используем EF, и обработка соединений должна была быть автоматической.
Итак, я начал рыть. Первым потенциальным виновником, который я рассматривал, был MiniProfiler (или, я бы сказал, наша реализация использования минипрофилера). Мы использовали это, и он работает хорошо, но я беспокоился о возможных утечках соединений.
public OurContext() : base(GetProfilerConnection(), true)
{}
private static DbConnection GetProfilerConnection()
{
return new EFProfiledDbConnection(new SqlConnection(ConfigurationManager.ConnectionStrings["Database"].ConnectionString),
MiniProfiler.Current);
}
У меня создалось впечатление, что "истинный" параметр в базовом вызове заставил контекст взять на себя ответственность за соединение, поэтому я считаю, что это должно работать нормально, и соединение будет удалено.
В нашей ветке расширения DEV я удалил miniprofiler, поскольку он не был обновлен для поддержки EF5, и мы собираемся мигрировать в какой-то момент в недалеком будущем, поэтому это должно быть устранено как проблема.
Вторая проблема заключалась в том, что "мы правильно распоряжаемся нашими данными"? Поэтому я загрузил Entity Framework Profiler на пробную версию и взял нашу самую тяжелую страницу и проверил тест.
Результаты явно показали, что какой-либо контекст, который мы открыли, был закрыт, а часть, относящаяся ко мне, - это число контекстов, которые мы открываем. У нас есть наша установка контейнера DI (Ninject 2), чтобы установить один контекст на веб-http-запрос, который я бы считайте правильным. Проблема заключается в том, как мы обрабатываем изображения в нашем приложении. Эта страница, в частности, может содержать до семи изображений в базе данных. Каждое из этих изображений включено в страницу посредством действия MVC. Например:
[<img src="/Controller/GetPhotoAction/[ImageId] />]
Поскольку изображение представляет собой запрос separte, открывается отдельный контекст. Итак, для этой конкретной страницы мы используем семь разных подключений из пула соединений, если я правильно понимаю это. Умножьте это на множество пользователей, и я вижу как это могло бы быть сообщено выше.
Причина хранения изображений в базе данных двоичная. Во-первых, наше административное приложение для управления данными для этого приложения находится на Западном побережье США, но серверы, на которых размещено приложение, находятся на восточном побережье США. Eсть VPN-туннель между нашей сетью здесь, на работе на Западном побережье и серверах на Восточном побережье. Приложение также сбалансировано по нагрузке (2 веб-интерфейса). Было принято решение сохранить изображения в БД, чтобы избежать копирования изображений через туннель VPN, а затем с разрешениями на запись изображений в местоположение файла в веб-приложении на каждом сервере (эти два местоположения также являются полностью разными доменами).
В то же время, пока мы тестируем, мы увеличили размер пула максимального соединения в нашей строке соединения и будем развертывать его в PROD в начале следующей недели.
Итак, мои вопросы:
1) Я проверил здесь свои базы в проверке утечки? Полагаю, что у меня есть. Я не прав во всем, что я сказал выше?
2) Если контексты нескольких данных на этой странице оказались виновниками, предложения о том, как записать образ на два сервера по всей стране, имея в виду разрешения, будут пересекать домены? Реально, я бы хотел сделать это в ожидании, но технические препятствия немного больше, чем мы готовы сделать в это время перед праздниками.
3) Если вы считаете, что ни одно из перечисленных проблем не является проблемой, что я могу потерять? Неужели это действительно так, что запросы достаточно высоки, и мы сталкиваемся с этой ошибкой, и нам нужно масштабироваться? Я могу выкопать журналы, чтобы просматривать статистику использования, но это кажется маловероятным. Эта страница кэшируется в течение часа (есть переменная по параметру)