应用程序服务器如何处理多个请求以将数据保存到 table

How application server handle multiple requests to save data into table

我在 jsf 中创建了一个 Web 应用程序,它有一个按钮。 如果单击该按钮,它将转到服务器端并执行以下功能以将数据保存在 table 中,我正在为此使用 mybatis。

public void save(A a)
{

SqlSession session = null; 

try{ 

session = SqlConnection.getInstance().openSession(); 

TestMapper testmap= session.getMapper(TestMapper.class); 

testmap.insert(a); 

session .commit(); 

}
catch(Exception e){
}
finally{
session.close();
}

}

现在我已经在应用程序服务器 JBoss(wildfly) 中部署了这个应用程序。

据我了解,当多个用户尝试访问该应用程序时 通过点击 URL,应用程序服务器为每个用户请求创建线程。 例如,如果有 4 个客户端发出请求,则将生成 4 个线程,即 t1、t2、t3 和 t4。

如果4个用户同时点击保存按钮,保存方法将如何执行,如t1访问该方法并执行插入语句 插入数据到table,然后t2,t3和t4或者同时所有4个线程执行insert方法并插入数据?

为了提供一些背景信息,我将描述前两种可能的处理请求的方法。在这种情况下,HTTP 但这些方法不依赖于所使用的协议,最重要的是请求来自网络,并且为了执行它们,需要一些 IO(访问文件系统或数据库或对其他系统的网络调用)。请注意,以下描述有一些简化。

这两种方法是:

  • 同步
  • 异步

一般来说,要处理涉及数据库访问的典型 HTTP 请求,至少需要四个 IO 操作:

  • 请求处理程序需要从客户端套接字读取请求数据
  • 请求处理程序需要将请求写入连接到数据库的套接字
  • 请求处理程序需要从数据库套接字读取响应
  • 请求处理程序需要将响应写入客户端套接字

让我们看看这两种情况是如何完成的。

同步

在这种方法中,服务器有一个准备好为请求提供服务的线程池(想想一个集合)。

当请求到达时,服务器从池中借用一个线程并在该线程中执行请求处理程序。

当请求处理程序需要执行 IO 操作时,它会启动 IO 操作,然后等待其完成。等待是指线程执行被阻塞,直到 IO 操作完成并且数据(例如 SQL 查询结果的响应)可用。

在这种情况下,同时为多个客户端处理请求的并发性是通过在池中拥有一定数量的线程来实现的。与 CPU 相比,IO 操作要慢得多,因此大多数时候处理某些请求的线程在 IO 操作上被阻塞,并且 CPU 核心可以执行其他客户端的请求处理阶段。

请注意,由于 IO 操作的缓慢,用于处理 HTTP 请求的线程池通常足够大。 wildfly 中使用的同步请求处理子系统的文档 says 每个 CPU 核心大约 10 个线程是一个合理的值。

异步

在这种情况下,IO 的处理方式不同。有少量线程处理IO。它们都以相同的方式工作,我将描述其中的一个。

这样的线程 运行 是一个基本上等待事件的循环,每次事件发生时它都会调用事件的处理程序。

第一个这样的事件是新请求。当请求处理开始时,请求处理程序由 IO 线程之一从 运行 的循环中调用。请求处理程序做的第一件事是尝试从客户端套接字读取请求。因此处理程序在客户端套接字上发起 IO 操作,并将 returns 控制权交给调用者。这意味着线程被释放,它可以处理另一个事件。

当从客户端套接字读取的 IO 操作获得一些可用数据时,会发生另一个事件。在这种情况下,循环在 IO 启动后处理程序将控制返回到循环的点调用处理程序,即它在下一步处理输入数据(如解析 HTTP 参数)并启动新的 IO 操作(在这种情况下请求到数据库套接字)。处理程序再次释放线程,以便它可以处理其他事件(例如完成其他客户端请求处理中的 IO 操作)。

考虑到 IO 操作比 CPU 本身的速度慢,一个处理 IO 的线程可以同时处理很多请求。

注意:请求处理程序代码永远不要使用任何阻塞操作(如阻塞 IO),这一点很重要,因为那样会窃取 IO 线程,并且不允许其他请求继续进行。

JSF 和 Mybatis

对于 JSF 和 mybatis,使用同步方法。 JSF 通过 WildFly 中的同步处理器使用 servlet to handle requests from the UI and servlets are handled。 JDBC mybatis 用来与数据库通信的也是使用同步 IO,因此线程用于并发执行请求。

拥塞

以上所有内容都是在没有其他拥塞源的假设下编写的。这里的拥塞是指对系统的某些组件并行执行事物的能力的限制。

例如,假设一个数据库被配置为一次只允许一个客户端连接的情况(这不是一个合理的配置,我使用它只是为了演示这个想法)。在这种情况下,即使多个线程可以并行执行 save 方法的代码,但在它们尝试打开与数据库的连接时,除了一个之外,其他所有线程都会被阻塞。

另一个类似的例子是如果你使用的是sqlite数据库。它一次只允许一个客户端写入数据库。因此,当线程 A 尝试执行 insert 时,如果另一个线程 B 已经在执行插入,它将被阻塞。只有在线程 B 执行提交后,线程 A 才能继续插入。时间 A 取决于 B 执行其请求所花费的时间以及等待对同一数据库执行写操作的其他线程的数量。

在实践中,如果您使用扩展性更好的 RDBMS(如 postgresql、mysql 或 oracle),则在使用少量连接时不会遇到此问题。但是当并发请求量大,DB对客户端连接数有限制,或者应用端使用连接池限制连接数时,就可能出现问题。在这种情况下,如果已经有很多连接到数据库,新客户端将等待现有请求完成并关闭连接。