java - 高容量Java服务器的线程模型

标签 java multithreading sockets server client-server

我正在为一个相当大的模拟创建一个 Java 服务器,并且我有几个高级设计问题。

一些背景:

  • 服务器将运行模拟。
  • 客户端将通过 TCP 连接从移动设备连接到服务器,并与模拟中的数据结构进行交互。最初我将尝试在客户端中使用简单的轮询方案。我发现很难在移动设备和服务器之间维持长期的 TCP 连接,而且我还不确定客户端是否会尝试保持开放的 TCP 连接,或者是否会在每次传输时建立并拆除它。
  • 当客户端在移动设备上处于 Activity 状态时,我希望客户端每分钟至少轮询服务器几次。
  • 无论客户端是否连接,模拟都会继续运行。
  • 现有客户总数可能会非常大,达到数千。
  • 客户端主要轮询服务器以获取模拟状态,但有时也会向模拟发出控制命令。
  • 所有消息都很小。
  • 我希望服务器能够在 Linux 下的多核 CPU 服务器硬件上运行。

目前我对服务器中的线程模型有以下想法:

  • 模拟逻辑由几个线程执行。模拟逻辑线程对模拟数据结构进行读写。
  • 对于每个客户端,都有一个 Java 线程对该客户端的套接字执行阻塞读取调用。当从客户端接收到轮询命令时,相应的客户端线程从模拟数据结构中读取信息(一个客户端轮询通常对总数据结构的一小部分感兴趣),并在客户端的套接字上向客户端发送回复。因此,对数据结构的访问需要在客户端线程和模拟线程之间同步(我会尝试对较小的数据子集进行锁定)。如果从客户端收到控制命令,客户端线程将写入数据结构。

对于少数客户,我认为这会很好用。

问题 1:此线程模型是否适用于大量(数千)个连接的客户端?我不熟悉这样的 Java 实现中会有多少内存/CPU 开销。

问题 2:我想避免让服务器异步向客户端发送消息,但在某些情况下,我可能需要让服务器向一些或许多客户端异步发送“立即更新自己”消息,但我不太确定如何做到这一点。让模拟逻辑线程发送这些消息似乎不对......也许是一些“客户端通知线程池”概念?

最佳答案

你问两个问题;我先回答一下。

我之前编写过一个应用程序,其中一个应用程序涉及数千个线程。我们曾经遇到过 Linux 服务器上最大线程数的问题;对于我们来说,我认为限制大约是 1000 个线程。这影响了我们的 Java 应用程序,因为 Java 线程使用 native 线程。我们将限制设置得更高,应用程序扩展到大约 2000 个线程,这正是我们所需要的,没有出现问题;我不知道如果我们需要将其扩展得更高会发生什么。

默认最大线程数为 1000,这一事实表明在单个 Linux 服务器上运行数千个线程可能并不明智。我认为主要问题是需要为每个线程分配足够的堆栈内存。

我们预期的长期解决方案是更改为一种架构,其中线程池中的线程分别为多个套接字提供服务。这确实不是什么大问题;对于每个套接字,线程只需处理所有挂起的消息,然后再继续处理下一个套接字。您必须小心同步内存访问,但您的应用程序已经需要这样做,因为您的模拟已经与多个线程交互,因此该部分不会有巨大的变化。

关于java - 高容量Java服务器的线程模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38836279/

相关文章:

java - 了解 Java 中可变参数的意外行为

java - 如何在支持 opengl 的 java 中创建一个新线程?

c++ - boost::asio::streambuf 为空?

c# - 将 try-catch 放入循环中,直到 try block 中的所有语句都执行完,没有任何异常,这是一种好习惯吗?

java - 如何将KStream的Object类型的值存储在Hashmap中?

Java KeyListener : KeyTyped Backspace, Esc 作为输入

asp.net - ConfigureAwait(false) 如何防止 Ui 死锁

c - 将参数传递给 bind() 函数

java - 如何像在 java 中一样在 kotlin 中自动实现/生成方法

c++ - 即使数据会更快可用,是否预计 poll() 需要 40 毫秒才能返回?