实体框架6 - 等待连接的阻塞时间

时间:2017-02-23 17:57:43

标签: entity-framework entity-framework-6

下面是Azure Application Insights的一些分析图片。它来自执行该简单请求:

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来电。在分析器结果中,我看到了这三个电话。

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


  4. 连接这些令人难以置信的等待时间是多少?
    是什么原因导致他们以及如何驾驭它?

    Entity Framework profiling

    trace

    更新

    我可能错了,但我想我知道that line中解释的this documentation中的延迟加载和锁定Metdata会发生什么。

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

    有没有办法把延迟加载来测试我说的是什么?

    更新2

    我刚刚在我的上下文中尝试了this.Configuration.LazyLoadingEnabled = false;,但问题仍然存在:-(

    请注意,我每5分钟左右才能重现一次。在它们之间似乎有一些缓存,因为查询会立即执行。

    更新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上。

    更新4

    即使在通过上下文调用存储过程时,问题仍然存在。所以我猜这与查询计划无关
    我不明白的是,即使我用SqlCommand调用存储过程因此没有实体框架,问题仍然存在......

    更新5

    这不是实体框架问题。问题是等待sql连接。无论是使用EF还是使用SqlCommand,每5分钟都会出现相同的慢速等待时间。我将结束这个问题并用适当的问题打开一个新问题。

0 个答案:

没有答案