在将AWS Dynamo DB作为ASP.NET会话提供程序时出现400 Bad Request错误

5
我们在应用程序中使用AWS的DynamoDB Session提供程序来存储会话数据。
最近我切换到一个可以监控我的应用程序的 NewRelic 环境,它开始发出关于 DynamoDB 访问的警报。然而,NewRelic 是唯一能获取这个警报的监控工具。我无法在我的应用程序日志(log4net)或 Windows 事件查看器中看到任何与此问题相关的信息。
我搜索了很多并甚至查看了提供程序的源代码,但是没有发现任何问题。
我每小时会发生3到4次1到2分钟的调用,所有的调用都会得到(400)错误请求。
我获得的堆栈跟踪不太好:
at System.Net.HttpWebRequest.GetResponse()
at System.Net.HttpWebRequest.GetResponse()
at Amazon.Runtime.AmazonWebServiceClient.getResponseCallback(IAsyncResult result)
有问题的 URL 是:
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

非Web事务-图1

图2

错误-图2

感谢您的帮助。


你正在使用哪个版本的AWS SDK for .NET?你能否获取有关你最终收到的“400 - Bad Request”的更多详细信息?这将有助于隔离可能的原因,请参阅API错误代码。 - Steffen Opel
@SteffenOpel 我之前使用的是AWS SDK 1.5.37.0版本,但在提问之前已升级到最新版(2.0.14.0),希望能有所改善,但没有成功。 - tucaz
2个回答

4
如果您的应用程序同时发起多个访问会话状态的请求,可能会出现条件锁定失败。这在Ajax调用中很常见。文章ASP.NET会话状态的缺点提供了一个很好的解释,介绍了ASP.NET如何序列化对特定会话状态的访问以及一些解决方法:

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

这些错误不应该冒泡到应用程序级别。AWS SDK for .NET针对条件更新失败抛出异常,会话提供程序将其解释为获取锁定失败。这被传递回ASP.NET框架,直到它可以获取锁定时才排队处理请求。
这意味着,如果一个请求正在进行中,而来自同一会话的另一个请求到达,则它将被排队,直到第一个请求完成才开始执行。为什么ASP.NET要这样做?为了并发控制,以避免多个请求(即多个线程)以不一致的方式读写会话状态。

1
感谢您的回复和出色的参考@normj。如果我理解正确,这些异常是正常的和预期的,我不应该担心它,因为ASP.NET/SessionProvider的内部工作正在处理它。New Relic也不应该担心。我可以做两件事来“修复”问题:a)减少会话使用的并发性;b)尝试在New Relic中过滤这些异常,以便它们不会打扰我。唯一仍然困扰我的是DynamoDB中的会话记录从未被删除。这种行为是否符合预期? - tucaz
1
会话状态提供程序将在 ASP.NET 告知其放弃会话时删除表中的会话。问题是,ASP.NET 经常不会通知会话提供程序关于废弃的会话。有一个静态实用方法 DeleteExpiredSessions,您可以定期在 DynamoDBSessionStateStore 上调用以清除这些会话状态。建议在应用程序使用率较低的情况下调用此方法,因为它需要进行表扫描。 - Norm Johanson

1

更新

Norm Johanson的答案揭示了手头问题的根本原因,我将保留已经做出适当调整的答案中仍然适用的部分以及相关问题的指向。


初始回答

我没有遇到你描述的确切问题,但它让我想起在调查AWS API 最终一致性时遇到的类似模式,例如,请参见我的答案确定性创建和标记EC2实例。自那以来情况已经大大改善:

现在,我怀疑的是类似这样的情况:

  • New Relic正在对.NET字节码进行仪器化,这使得他们可以记录所有异常,无论它们是否被处理。
  • 例如,您的客户由于请求限制违规而被限制,这导致可重试的400-ThrottlingException,根据API错误代码,即触发一个已处理的异常,进而启动指数级别的重试,最终成功地完成请求,并相应地留下其他工具的痕迹。
    • 更新:手头的异常实际上是不可重试的400-ConditionalCheckFailedException,因此这个怀疑在这里不适用。

如果问题显然是什么导致的,尽管问题描述与您的不符,2.0.12.0中的性能问题讨论暗示了.NET SDK 2.0.x版本中持续的线程问题可能会因使用模式而有所不同?


我开始在SDK的1.X版本中看到这个问题,所以可能不是同一个问题。然而,我会在那里发布这个问题,看看是否有人对此有线索。与此同时,我更新了我的问题,以反映我能够获得的额外证据。 - tucaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接