2015-01-28 15 views
1

У меня очень трудное время, прибивая проблему, исходящую от NHibernate (3.3). Приложение обслуживает около 150 req/s в кластере NLB с шестью узлами. Приложение работает нормально, но иногда, возможно, через 1-2 дня в журналах появляется следующая ошибка, и все запросы терпят неудачу.Запросы Nhibernate терпят неудачу.

Я использую adonet.batch_size из 15 и MultipleActiveResultSets=True имеет значение true. Все контроллеры наследуют от AsyncController (это приложение ASP.NET MVC 4), поэтому состояние сеанса считывается только для максимизации параллелизма.

Первоначально у нас было много проблем с обработкой сеанса NHibernate, потому что AbstractBatcher сделал довольно плохую работу, с которой читатели были связаны с каким соединением. Таким образом, с большой нагрузкой читатели будут пытаться читать из уже закрытых соединений. Мы решили это, определяя вручную время жизни SQLConnection, которое стабилизировало ситуацию.

Однако часто возникает следующее. Я думаю, что это симптом чего-то действительно неправильного с фабрикой сеансов. На этом этапе я думаю о повторной инициализации фабрики сеансов, когда вызывается необработанное исключение этого типа, но это не приятно. Кто-нибудь знает, почему это происходит?

System.NotSupportedException: PartialEvaluationExceptionExpression 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) 
    at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitExpression(Expression expression) 
    at NHibernate.Linq.Visitors.QueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index) 
    at Remotion.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index) 
    at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel) 
    at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel) 
    at NHibernate.Linq.Visitors.QueryModelVisitor.GenerateHqlQuery(QueryModel queryModel, VisitorParameters parameters, Boolean root) 
    at NHibernate.Linq.NhLinqExpression.Translate(ISessionFactoryImplementor sessionFactory) 
    at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) 
    at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) 
    at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) 
    at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) 
    at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) 
    at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) 
    at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) 
    at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source) 

ответ

0

Для тех, кто может столкнуться этот вопрос, я думал, что я хотел бы дать некоторое представление о двух лет в производстве (тысячи пользователей) из починки, которые мы ставим на место, чтобы решить эту проблему.

В базовом конструкторе мы имеем что-то вроде этого:

 public MvcBaseController() 
     { 
      try 
      { 
       var currentRepositorySession = RepositorySession.Current; 

       dbConnection = new SqlConnection(currentRepositorySession.GetConnectionString()); 
       dbConnection.Open(); 
       session = currentRepositorySession.Create(false, dbConnection); 

      } 
      catch (Exception e) 
      { 
       LogDebug("Error was thrown: " + e.Message); 
      } 
     } 

Binding подключения дб к сессии NHibernate силы является единственным способом, чтобы гарантировать, что AbstractBatcher не закрывает сессию, прежде чем все читатель сделали , На Dispose мы имеем следующее:

protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      try 
      { 
       if (session != null) 
       { 
        session.Dispose(); 
        session = null; 
       } 
      } 
      catch (Exception ex) 
      { 
       LogDebug("Error was thrown: " + ex.Message); 
      } 
      try 
      { 
       if (dbConnection != null) 
       { 
        dbConnection.Close(); 
        dbConnection.Dispose(); 
        dbConnection = null; 
       } 
      } 
      catch (Exception ex) 
      { 
       LogDebug("Error was thrown: " + ex.Message); 
      } 
     } 

     base.Dispose(disposing); 
    } 

Это означает, что соединение открыто для каждого запросов, которое отлично. Нам пришлось увеличить работу с SQL Server, но система стабильна уже два года. Единственный раз, когда мы видели перерыв в работе фабрики NHibernate, - это когда в базе данных загружено много данных, скажем, 1 миллион записей. Затем пул приложений переполняется и становится сиротой. Это были в основном ошибки кода и не связаны с проблемами параллелизма, описанными в вопросе.

Смежные вопросы