【问题标题】:Multiple requests go into same thread of Java gRPC Server多个请求进入 Java gRPC Server 的同一个线程
【发布时间】:2021-03-25 22:40:08
【问题描述】:

我有一些用java写的微服务,通过gRPC相互通信,放到AWS ECS中运行。 当我运行服务并使用客户端程序调用这些服务时,我注意到了一件很奇怪的事情。

通常,Tomcat 的线程池设置将确保多个请求将由相同数量的线程处理。但是当我运行我的程序时,有时它会发生一个线程开始处理一个新请求,而它已经在处理一个先前的请求。它使进程线程不安全,因此发生了错误。 这在普通服务上很少发生,当我同时向同一个服务发送 10 个请求时一定会发生。

请问有没有遗漏的设置?我可以在互联网上搜索的是我只能增加线程池大小。

---------2020/12/22 已编辑---------

通过进入调试模式,我看到一个 RPC 请求将被拆分为两个任务。一个用于消息本身,另一个用于从第一个任务返回的侦听器。我之前 90% 的错误发生在这两个任务的时间间隔之间。 此外,在运行侦听器时,ServerImpl 类将使用上下文来处理每个 RPC 消息,以及方法单元中的每个步骤,这些方法涵盖了重写的侦听器中的所有编写代码。 因此它会在监听器运行期间发生线程切换。

【问题讨论】:

  • 一个线程在处理另一个请求的同时开始一个新的请求是什么意思;一个线程如何同时执行两段代码?您能详细解释一下您注意到的线程不安全问题吗?
  • @EricAnderson 从日志中,我看到线程开始处理请求 A 几个步骤,然后开始处理请求 B。有些情况最后可以同时处理请求 A 和 B,但其他情况就像请求 B 接管请求 A 一样。

标签: java multithreading tomcat grpc grpc-java


【解决方案1】:

StreamObserver's documentation:

实现不需要是线程安全的(但应该是线程兼容的)。

“线程兼容”是您问题的重要部分。这意味着您不能假设对您的实例的每次调用都会发生在同一个线程上。几乎所有非线程安全的 gRPC API 都是如此。这对大多数代码无关紧要,但会影响ThreadLocals 之类的内容。

基本上,线程不属于 RPC。相反,RPC 共享所有线程,当需要传递回调时,它只会找到 一个 线程来运行回调。与 servlet 使用的大部分阻塞模型相比,这是一个异步模型,它允许更大的扩展性,因为您可以用更少的线程为更多的 RPC 提供服务。但这意味着一旦您从回调中返回,同一线程可能会用于其他一些 RPC 回调。

【讨论】:

  • 感谢您的评论。我同意你的评论,但我的情况更有可能是同一个线程中的两个进度,而不是多个线程处理多个进度。我使用线程本地来处理线程安全对象,以便不同的线程可以处理自己的资源。但我的情况是两个进程在同一个线程中运行,线程局部变量或普通变量都变得不安全。
  • 不可能同时在一个线程中运行两个不同的东西。时期。可能发生的情况是您正在保存 Thr​​eadLocal 的值并在另一个回调中使用该值,而没有意识到您现在在另一个线程上。我建议你在请求处理代码中多次打印出Thread.currentThread().getId(),并寻找它意外变化的地方。
  • 如何区分线程内的调用?如果第一个调用先关闭/发送,关闭/发送第二个调用将导致 Nullpointer,因为调用已经关闭。
  • 不清楚您在做什么以及为什么会看到 NPE。您需要使用堆栈跟踪发布代码 sn-p 和异常。
  • 谢谢。我已经跟踪了所有堆栈,并找到了您在以前的 cmets 中的意思。我已经解决了这个问题。
猜你喜欢
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
相关资源
最近更新 更多