Docker 竞争条件导致 curl 错误“传输已关闭,剩余 1 个字节需要读取”

Docker 竞争条件导致 curl 错误“传输已关闭,剩余 1 个字节需要读取”

很难完整描述我们的问题。不过,我会尽力提供完整的信息。我花了很多时间,但仍然卡住了。希望这里的任何人都可以帮助我。

目前,我们的容器在响应网络请求时随机挂起。

我有一个在端口 8082 上运行的 nodejs 应用程序,此端口也暴露给主机。我创建了一个桥接网络以将其与 nginx 代理容器链接起来。

我写了一个脚本来执行以下操作

  • 停止 nodejs 容器
  • 运行一个新的 nodejs 容器(来自相同或更新的图像)
  • 删除网络
  • 停止 nginx 容器
  • 创建新网络
  • 将 nodejs 链接到新网络
  • 使用新网络运行另一个 nginx 容器

有时,这种设计很完美。但有时它却被破坏了随机。中断发生在容器启动后,一旦中断,所有请求都会中断。

以下是它被破坏的方式

  • 从主机上,如果我运行curl localhost:8082,它会返回Found. Redirecting to /en。这是正确的。
  • 从主机上,如果我运行curl localhost:8082/en,它会挂起很长时间然后返回curl: (52) Empty reply from server
  • 从主机,我运行docker exec 041fe684edfb curl localhost:8082/en(041fe684edfb 是容器名称),它返回 99% 的响应并在打印时挂起<script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/admin-car-calendar~admin-host~admin-orders~admin-station~admin-stations~author-postView~holder-car-c~b1a1af4b.05ea0cbf23227e7a323a.js"></script>,然后返回curl: (18) transfer closed with 1 bytes remaining to read
  • 如果我运行,然后在容器终端中docker exec -it 041fe684edfb bash运行,它会打印响应,挂起但在不同的(后者)位置curl localhost:8082/en
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/runtime.93923d84c7f89f7844ae.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/admin-car-calendar~admin-host~admin-orders~admin-station~admin-stations~author-postView~holder-car-c~b1a1af4b.05ea0cbf23227e7a323a.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/admin-car-calendar~admin-car-orders~admin-cars~holder-car-calendar~holder-car-simple-calendar~holder~9dc2a71c.5714564e356df216ebb8.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/user-vs-home.dc7ac409e63e95c891ec.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/vendors.284ffc3f329d46200747.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/client.16b9bdc0c6df3c59afb6.js"></script>
    <script defer src="https://d3l80sdjn9d1ye.cloudfront.net/bundles/styles.91c5d85ab779777de531.js"></script>
</body>

</html>沒有打印出来。

当我检查我的nodejs应用程序日志时,该请求已完全处理该请求(直到</html>)。


更多信息

  • 如果我使用重新启动容器docker restart 041fe684edfb,问题就会消失
  • 如果我逐个运行脚本命令,问题就会消失
  • 我的 nodejs 应用程序连接到 10.0.81.135(AWS EC2 私有 IP)上的外部 mongo 和 redis 服务器。最初,这些服务器在其他容器中本地运行,完全没有问题。在我将它们迁移到单独的服务器后,问题就出现了。
  • 块大小为 221773。Nodejs 应用程序日志打印此大小并且 curlContent-Length正确解释标题。
  • 最后,nodejs抛出这个错误几次(6次),然后退出

12:07:00
AbortError: Redis connection lost and command aborted. It might have been processed.
12:07:00
at RedisClient.flush_and_error (/carstay/node_modules/redis/index.js:362:23)
12:07:00
at RedisClient.connection_gone (/carstay/node_modules/redis/index.js:664:14)
12:07:00
at RedisClient.on_error (/carstay/node_modules/redis/index.js:410:10)
12:07:00
at Socket.<anonymous> (/carstay/node_modules/redis/index.js:279:14)
12:07:00
at Socket.emit (events.js:223:5)
12:07:00
at Socket.EventEmitter.emit (domain.js:475:20)
12:07:00
at emitErrorNT (internal/streams/destroy.js:92:8)
12:07:00
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
12:07:00
at processTicksAndRejections (internal/process/task_queues.js:81:21)
12:07:00
AbortError: Redis connection lost and command aborted. It might have been processed.
12:07:00
at RedisClient.flush_and_error (/carstay/node_modules/redis/index.js:362:23)
12:07:00
at RedisClient.connection_gone (/carstay/node_modules/redis/index.js:664:14)
12:07:00
at RedisClient.on_error (/carstay/node_modules/redis/index.js:410:10)
12:07:00
at Socket.<anonymous> (/carstay/node_modules/redis/index.js:279:14)
12:07:00
at Socket.emit (events.js:223:5)
12:07:00
at Socket.EventEmitter.emit (domain.js:475:20)
12:07:00
at emitErrorNT (internal/streams/destroy.js:92:8)
12:07:00
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
12:07:00
at processTicksAndRejections (internal/process/task_queues.js:81:21)

答案1

遇到了类似的问题并找到了这篇文章:https://medium.com/grano/the-fault-in-our-responses-bytes-remaining-to-read-91efe0553676

尽管响应已经发送,自定义错误处理程序仍会调用 next(),这会导致此问题,因为最后一个 next() 是 Express 的默认处理程序,它会立即断开套接字。与此同时,Redis 可能仍会尝试保存您的会话并终止。

尝试逐步检查代码,看看在特定情况下请求是否被多次处理,例如在某个时候抛出错误。即使 res.send() 也可能会抛出错误,例如如果您尝试发送无法序列化的数据。

相关内容