【问题标题】:400 Bad Request on AWS Dynamo DB as Session Provider for ASP.NETAWS Dynamo DB 作为 ASP.NET 的会话提供程序的 400 错误请求
【发布时间】:2014-06-25 02:07:43
【问题描述】:

我们在应用中使用AWS's DynamoDB Session Provider 来存储会话数据。

我最近搬到了一个可以让 NewRelic 监控我的应用程序的环境,它开始发出有关 Dynamo DB 访问的警报。但是,NewRelic 是唯一获得它的监控工具。我在我的应用程序日志记录 (log4net) 或 Windows 事件查看器中看不到与此问题相关的任何内容。

我搜索了很多,甚至浏览了提供程序的源代码,但结果是空的。

我收到了 (400) 个错误请求,似乎是在 1 或 2 分钟内发出的所有呼叫,每小时发生 3 或 4 次。

我能得到的堆栈跟踪并不乐观:

at System.Net.HttpWebRequest.GetResponse() at System.Net.HttpWebRequest.GetResponse() at Amazon.Runtime.AmazonWebServiceClient.getResponseCallback(IAsyncResult result)

而有问题的网址是:

dynamodb.us-east-1.amazonaws.com/Stream/GetResponse

从下面的时间图中,我们可以看到大部分时间所有请求都很好(图 1),但是当问题发生时,向 DynamoDB 发出的成功请求数变为 0(图 1)。同时,抛出的错误数量激增(图 2)。


更新:在周末的低使用期间,我在生产服务器上运行了 Fiddler,也查看了来自 AWS 的错误是什么样的。我收到“条件请求失败”,这似乎是因为在请求和旧值时更新了值,因此该值与预期不一致。以下是完整的请求/响应示例。

请求:


POST https://dynamodb.us-east-1.amazonaws.com/ HTTP/1.1
X-Amz-Target: DynamoDB_20120810.UpdateItem
Content-Type: application/x-amz-json-1.0
User-Agent: aws-sdk-dotnet-35/2.0.15.0 .NET Runtime/4.0 .NET Framework/4.0 OS/6.2.9200.0 SessionStateProvider TableSync
Host: dynamodb.us-east-1.amazonaws.com
X-Amz-Date: 20140510T153947Z
X-Amz-Content-SHA256: e7a4886acac6ccf16f0da9be962d3a68bd50e381c202277033d0d2bb3208aa8a
Authorization: AWS4-HMAC-SHA256 Credential=redacted/20140510/us-east-1/dynamodb/aws4_request, SignedHeaders=content-type;host;user-agent;x-amz-content-sha256;x-amz-date;x-amz-target, Signature=redacted
Accept: application/json
X-NewRelic-ID: redacted
X-NewRelic-Transaction: redacted
Content-Length: 399

{
    "TableName": "ASP.NET_SessionState",
    "Key": {
        "SessionId": {
            "S": "redacted"
        }
    },
    "AttributeUpdates": {
        "LockId": {
            "Value": {
                "S": "42a9ed29-7a92-4455-8733-2f56c7d974b3"
            },
            "Action": "PUT"
        },
        "Locked": {
            "Value": {
                "N": "1"
            },
            "Action": "PUT"
        },
        "LockDate": {
            "Value": {
                "S": "2014-05-10T15:39:47.324Z"
            },
            "Action": "PUT"
        }
    },
    "Expected": {
        "Locked": {
            "Value": {
                "N": "0"
            },
            "Exists": true
        }
    },
    "ReturnValues": "ALL_NEW"
}

回复:


HTTP/1.1 400 Bad Request
x-amzn-RequestId: redacted
x-amz-crc32: redacted
Content-Type: application/x-amz-json-1.0
Content-Length: 120
Date: Sat, 10 May 2014 15:33:17 GMT

{
    "__type": "com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException",
    "message": "The conditional request failed"
}

图表 1

图表 2

感谢任何帮助。谢谢!

【问题讨论】:

  • 您使用的是哪个版本的适用于 .NET 的 AWS 开发工具包?您能否获得有关您最终收到哪个400 - Bad Request 的更多详细信息?这将有助于隔离可能的原因,请参阅API Error Codes
  • @SteffenOpel 我使用的是 AWS 开发工具包 1.5.37.0 版本,但升级到最新版本 (2.0.14.0) 以查看在打开此问题之前是否有所改进,但没有运气。

标签: asp.net-mvc-4 session amazon-web-services session-state amazon-dynamodb


【解决方案1】:

更新

Norm Johanson's answer 揭示了当前问题的根本原因,对于仍然适用的部分以及相关问题的指针,我将分别保留我的调整答案。


初步回答

我没有遇到您描述的确切问题,但它敲响了在调查 AWS API 的Eventual Consistency 的上下文中遇到的类似模式的警钟,请参阅例如我对Deterministically creating and tagging EC2 instances 的回答是关于此的更多信息。从那以后情况有了很大改善:

现在,我怀疑是这样的:

  • New Relic 正在检测 .NET 字节码,这使他们能够例如记录所有异常,无论是否处理。
  • 您的客户是例如因违反请求限制而受到限制,这导致根据API Error Codes 可重试400 - ThrottlingException,即它触发一个异常,该异常被处理并依次启动指数重试,最终最终成功请求,并且没有留下任何痕迹相应的其他工具。
    • 更新:手头的异常结果是不可重试的400 - ConditionalCheckFailedException,因此这种怀疑在这里不适用。

以防万一,问题显然是可能导致这种情况的原因 - 即使问题描述与您的不匹配,Performance issue in 2.0.12.0 中的讨论暗示了 .NET SDK 的ongoing threading issue in the 2.0.x releases,这可能根据手头的使用模式,表面会有所不同?

【讨论】:

  • 我开始在 SDK 的 1.X 版本中看到问题,因此可能不是同一个问题。但是,我会在那里发布问题,看看是否有人对此有线索。与此同时,我更新了我的问题以反映我能够获得的其他证据。
【解决方案2】:

如果您的应用程序同时发出多个访问会话状态的请求,则可能发生条件锁定失败。这在 Ajax 调用中很常见。文章The Downsides of ASP.NET Session State 很好地解释了 ASP.NET 如何通过一些变通方法序列化对特定会话状态的访问:

我们要看的第一个问题是很多开发人员都不知道的问题;默认情况下,ASP.NET 管道不会同时处理属于同一会话的请求。它将它们序列化,即按照接收它们的顺序对它们进行排队,以便它们被串行处理而不是并行处理。 [...]

这些错误不应上升到应用程序级别。 AWS SDK for .NET 抛出条件更新失败的异常,会话提供者将其解释为未能获得锁。这将传递回 ASP.NET 框架,该框架将请求排队,直到它可以获取锁:

[...] 这意味着如果一个请求正在进行中并且来自同一会话的另一个请求到达,它将排队等待仅在第一个请求完成时才开始执行。为什么 ASP.NET 会这样做?用于并发控制,使多个请求(即多个线程)不会以不一致的方式读写会话状态。

【讨论】:

  • 感谢@normj 的回复和出色的参考。如果我理解正确,这些异常是正常的和预期的,我不应该担心它,因为 ASP.NET/SessionProvider 的内部工作正在处理它。 New Relic也不应该。我可以做两件事来“解决”这个问题:a)减少会话使用的并发性 b)尝试在 New Relic 中过滤这些异常,这样它们就不会打扰我。唯一困扰我的是会话记录永远不会在 DynamoDB 中删除。这是预期的行为吗?
  • 只要 ASP.NET 告诉它何时放弃会话,会话状态提供程序就会删除表中的会话。问题是 ASP.NET 通常不会告诉会话提供者有关放弃会话的信息。您可以定期在 DynamoDBSessionStateStore 上调用静态实用程序方法 DeleteExpiredSessions 来清除这些会话状态。我建议在您的应用程序使用率较低时调用它,因为它会进行表扫描。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多