2017-02-23 49 views
1

下面是一些使用Azure Application Insights进行分析的图片。它来自于执行那个简单的请求:实体框架6 - 阻止等待连接的时间

public HttpResponseMessage Login(LoginRequest loginRequest) 
     { 
      var t = new DependencyTracker(); 
      using (var context = t.TrackDependency(() => new SocialDbContext(), "NewContext")) 
      { 
       var user = t.TrackDependency(() => context.Users.AsNoTracking().SingleOrDefault(x => x.Email == loginRequest.Id || x.Name == loginRequest.Id), "GetUser"); 
       if (user == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsUser"); 
       var sid = t.TrackDependency(() => context.IdMappers.AsNoTracking().SingleOrDefault(x => x.Provider == "custom" && x.UserId == user.Id)?.Sid, "GettingSid"); 
       var account = t.TrackDependency(() => context.Accounts.AsNoTracking().SingleOrDefault(a => a.Id == sid), "GettingAccount"); 
       if (account == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsAccount"); 
       var incoming = t.TrackDependency(() => Hash(loginRequest.Password, account.Salt), "Hash"); 
       var isLoginOk = t.TrackDependency(() => SlowEquals(incoming, account.SaltedAndHashedPassword), "SlowEquals"); 
       if (isLoginOk && account.TempPasswordExpiry != null) 
       { 
        if (DateTimeOffset.Now.CompareTo(account.TempPasswordExpiry.Value) > 0) 
         return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsPassword"); 
        return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.TemporaryPassword), "WrongCredentialsExpiredTempPassword"); 
       } 
       return isLoginOk 
        ? t.TrackDependency(() => SendToken(user.Id, sid), "SendToken") 
        : t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.Unauthorized, ApiError.WrongCredentials), "WrongCredentialsPassword"); 
      }   
     } 

有3 SingleOrDefault调用。在分析器结果中,我看到了这3个调用。

  1. 第一个就是,3325ms(3017ms等待连接)
  2. 第二个需要2356ms(2349ms等待连接)
  3. 然后最后一个需要0.28ms



连接的这些令人难以置信的漫长等待时间是什么?
是什么引起了他们,以及如何获得它?

Entity Framework profiling

trace

UPDATE

我可能是错的,但我想我知道什么是延迟加载的混合物发生,从that linethis documentation的解释上Metdata锁定。

帐户将需要sid,但它锁定了元数据。所以sid等待。然后sid需要用户,但它锁定了元数据。所以用户等待。然后用户得到执行然后sid然后帐户。
虽然我会认为user == null.Sid会强制执行。

有没有办法让懒加载测试我在说什么?

更新2

我只是this.Configuration.LazyLoadingEnabled = false;试图在我的上下文构造函数,但问题仍然存在:-(

请注意,我只能重现该问题,每5分钟左右。在这之间似乎有一些缓存,因为查询立即执行。

UPDATE 3

我取代了代码使用一个查询,而不是三个:

public HttpResponseMessage Login(LoginRequest loginRequest) 
     { 
      var t = new DependencyTracker(); 
      using (var context = t.TrackDependency(() => new SocialDbContext(), "NewContext")) 
      { 
       var query = from a in context.Users 
          join b in context.IdMappers on a.Id equals b.UserId 
          join c in context.Accounts on b.Sid equals c.Id 
          where b.Provider == "custom" && (a.Email == loginRequest.Id || a.Name == loginRequest.Id) 
          select new { Sid = c.Id, c.Salt, c.SaltedAndHashedPassword, c.TempPasswordExpiry, UserId = a.Id }; 

       var account = t.TrackDependency(() => query.SingleOrDefault(), "GettingAccount"); 
       if (account == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsAccount"); 

       var incoming = t.TrackDependency(() => Hash(loginRequest.Password, account.Salt), "Hash"); 
       var isLoginOk = t.TrackDependency(() => SlowEquals(incoming, account.SaltedAndHashedPassword), "SlowEquals"); 
       if (isLoginOk && account.TempPasswordExpiry != null) 
       { 
        if (DateTimeOffset.Now.CompareTo(account.TempPasswordExpiry.Value) > 0) 
         return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsPassword"); 
        return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.TemporaryPassword), "WrongCredentialsExpiredTempPassword"); 
       } 
       return isLoginOk 
        ? t.TrackDependency(() => SendToken(account.UserId, account.Sid), "SendToken") 
        : t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.Unauthorized, ApiError.WrongCredentials), "WrongCredentialsPassword"); 
      } 
     } 

但是,即使现在只有一个等待的问题仍然存在。
但是,它只是每5分钟发生一次。
注意:我无法在本地重现它,它只发生在Azure上。

UPDATE 4

问题通过上下文调用存储过程时仍然连。所以我想这与查询计划无关。

我不明白的是,即使我调用存储过程与SqlCommand问题仍未以及因此实体内部消除框架...

UPDATE 5

这是不是实体框架问题。问题在于等待sql连接。无论使用EF还是使用SqlCommand,每5分钟都会发生相同的缓慢等待时间。我会解决这个问题,并用适当的问题开一个新问题。

回答

0

这不是一个实体框架问题。问题在于等待sql连接。无论使用EF还是使用SqlCommand,每5分钟都会发生相同的缓慢等待时间。