播放框架和 jdbc 阻塞 io 调用是否有主要的扩展限制
Are there major scaling limits with play framework and jdbc blocking io calls
我正在使用 Java 的游戏框架 (2.4) 并将其连接到 Postgres。播放框架被用作 restful 服务,它所做的只是使用 JDBC 插入、更新、读取和删除。在这个播放页面 https://www.playframework.com/documentation/2.3.x/JavaAsync 上,它清楚地指出 JDBC 正在阻塞并且播放线程很少。对于了解这一点的人来说,这会有多大限制,我有什么办法可以解决这个问题吗?我的特定应用程序每秒可以调用数百次数据库。我将拥有所有的硬件和额外的服务器,但不知道游戏如何处理这个问题或如何扩展以在代码中处理这个问题。我的代码如下所示:
public static Result myprofile() {
DynamicForm requestData = Form.form().bindFromRequest();
Integer id = Integer.parseInt(requestData.get("id"));
try {
JSONObject jo = null;
Connection conn = DB.getConnection();
ResultSet rs;
JSONArray ja = new JSONArray();
PreparedStatement ps = conn.prepareStatement("SELECT p.fullname as fullname, s.post as post,to_char(s.created_on, 'MON DD,YYYY') as created_on,s.last_reply as last_reply,s.id as id,s.comments as comments,s.state as state,s.city as city,s.id as id FROM profiles as p INNER JOIN streams as s ON (s.profile_id=p.id) WHERE s.profile_id=? order by created_on desc");
ps.setInt(1, id);
rs = ps.executeQuery();
while (rs.next()) {
jo = new JSONObject();
jo.put("fullname", rs.getString("fullname"));
jo.put("post", rs.getString("post"));
jo.put("city", rs.getString("city"));
jo.put("state", rs.getString("state"));
jo.put("comments", rs.getInt("comments"));
jo.put("id", rs.getInt("id"));
jo.put("last_reply", difference(rs.getInt("last_reply"), rs.getString("created_on")));
ja.put(jo);
}
JSONObject mainObj = new JSONObject();
mainObj.put("myprofile", ja);
String total = mainObj.toString();
System.err.println(total);
conn.close();
return ok(total);
} catch (Exception e) {
e.getMessage();
}
return ok();
}
我也知道我可以尝试将其包装在期货承诺中,但仍然会发生阻塞。如前所述,我会处理所有服务器和其他事情,但是播放框架是否能够使用 jdbc 扩展到每秒数百个请求?我现在正在问和学习,以避免以后出现严重错误。
Play 绝对可以处理这个负载。
文档指出,应避免在控制器方法内使用阻塞代码 - 默认配置已调整为异步执行。如果您在其中插入一些阻塞调用,您的控制器现在将等待该调用完成,然后才能处理另一个传入请求 - 这很糟糕。
You can’t magically turn synchronous IO into asynchronous by wrapping
it in a Promise. If you can’t change the application’s architecture to
avoid blocking operations, at some point that operation will have to
be executed, and that thread is going to block. So in addition to
enclosing the operation in a Promise, it’s necessary to configure it
to run in a separate execution context that has been configured with
enough threads to deal with the expected concurrency. See
Understanding Play thread pools for more information.
https://www.playframework.com/documentation/2.4.x/JavaAsync#Make-controllers-asynchronous
我相信你知道这一点,但我想指出粗体部分。您的数据库中可供应用程序调用的线程数量有限 - 跟踪此数量、创建一个为这些线程打开的新执行上下文并将该新执行上下文分配给一个承诺可能会有所帮助包装您的数据库调用。
查看此 post 关于应用程序转向 Play 的内容,它应该让您了解它的外观。我相信他使用的是 Akka Actors,这可能超出了您的范围,但是线程调优的想法是相同的:
Play 2 is optimized out-of-the-box for HTTP requests which don’t
contain blocking calls (i.e. asynchronous). Most database-driven apps
in Java use synchronous calls via JDBC so Play 2 needs a bit of extra
configuration to tune Akka for these types of requests.
http://www.jamesward.com/2012/06/25/optimizing-play-2-for-database-driven-apps
如果您尝试在不开启线程的情况下对数据库执行大量请求,您 运行 将面临使其余应用程序线程耗尽的风险,这将停止您的应用程序。对于您期望的负载,默认调整可能没问题,但值得进行一些额外的调查。
线程调优入门:
https://www.playframework.com/documentation/2.4.x/ThreadPools
您应该将您的控制器更新为 return Promise,也没有理由再使用 Play 2.4 将其设为静态。 https://www.playframework.com/documentation/2.4.x/Migration24#Routing
在 application.conf 中定义一个名为 "jdbc-execution-context"
的执行上下文
//reference to context
ExecutionContext jdbcExecutionContext = Akka.system().dispatchers()
.lookup("jdbc-execution-context");
return promise(() -> {
//db call
}, jdbcExecutionContext)
.map(callResult -> ok(callResult));
我正在使用 Java 的游戏框架 (2.4) 并将其连接到 Postgres。播放框架被用作 restful 服务,它所做的只是使用 JDBC 插入、更新、读取和删除。在这个播放页面 https://www.playframework.com/documentation/2.3.x/JavaAsync 上,它清楚地指出 JDBC 正在阻塞并且播放线程很少。对于了解这一点的人来说,这会有多大限制,我有什么办法可以解决这个问题吗?我的特定应用程序每秒可以调用数百次数据库。我将拥有所有的硬件和额外的服务器,但不知道游戏如何处理这个问题或如何扩展以在代码中处理这个问题。我的代码如下所示:
public static Result myprofile() {
DynamicForm requestData = Form.form().bindFromRequest();
Integer id = Integer.parseInt(requestData.get("id"));
try {
JSONObject jo = null;
Connection conn = DB.getConnection();
ResultSet rs;
JSONArray ja = new JSONArray();
PreparedStatement ps = conn.prepareStatement("SELECT p.fullname as fullname, s.post as post,to_char(s.created_on, 'MON DD,YYYY') as created_on,s.last_reply as last_reply,s.id as id,s.comments as comments,s.state as state,s.city as city,s.id as id FROM profiles as p INNER JOIN streams as s ON (s.profile_id=p.id) WHERE s.profile_id=? order by created_on desc");
ps.setInt(1, id);
rs = ps.executeQuery();
while (rs.next()) {
jo = new JSONObject();
jo.put("fullname", rs.getString("fullname"));
jo.put("post", rs.getString("post"));
jo.put("city", rs.getString("city"));
jo.put("state", rs.getString("state"));
jo.put("comments", rs.getInt("comments"));
jo.put("id", rs.getInt("id"));
jo.put("last_reply", difference(rs.getInt("last_reply"), rs.getString("created_on")));
ja.put(jo);
}
JSONObject mainObj = new JSONObject();
mainObj.put("myprofile", ja);
String total = mainObj.toString();
System.err.println(total);
conn.close();
return ok(total);
} catch (Exception e) {
e.getMessage();
}
return ok();
}
我也知道我可以尝试将其包装在期货承诺中,但仍然会发生阻塞。如前所述,我会处理所有服务器和其他事情,但是播放框架是否能够使用 jdbc 扩展到每秒数百个请求?我现在正在问和学习,以避免以后出现严重错误。
Play 绝对可以处理这个负载。
文档指出,应避免在控制器方法内使用阻塞代码 - 默认配置已调整为异步执行。如果您在其中插入一些阻塞调用,您的控制器现在将等待该调用完成,然后才能处理另一个传入请求 - 这很糟糕。
You can’t magically turn synchronous IO into asynchronous by wrapping it in a Promise. If you can’t change the application’s architecture to avoid blocking operations, at some point that operation will have to be executed, and that thread is going to block. So in addition to enclosing the operation in a Promise, it’s necessary to configure it to run in a separate execution context that has been configured with enough threads to deal with the expected concurrency. See Understanding Play thread pools for more information. https://www.playframework.com/documentation/2.4.x/JavaAsync#Make-controllers-asynchronous
我相信你知道这一点,但我想指出粗体部分。您的数据库中可供应用程序调用的线程数量有限 - 跟踪此数量、创建一个为这些线程打开的新执行上下文并将该新执行上下文分配给一个承诺可能会有所帮助包装您的数据库调用。
查看此 post 关于应用程序转向 Play 的内容,它应该让您了解它的外观。我相信他使用的是 Akka Actors,这可能超出了您的范围,但是线程调优的想法是相同的:
Play 2 is optimized out-of-the-box for HTTP requests which don’t contain blocking calls (i.e. asynchronous). Most database-driven apps in Java use synchronous calls via JDBC so Play 2 needs a bit of extra configuration to tune Akka for these types of requests. http://www.jamesward.com/2012/06/25/optimizing-play-2-for-database-driven-apps
如果您尝试在不开启线程的情况下对数据库执行大量请求,您 运行 将面临使其余应用程序线程耗尽的风险,这将停止您的应用程序。对于您期望的负载,默认调整可能没问题,但值得进行一些额外的调查。
线程调优入门: https://www.playframework.com/documentation/2.4.x/ThreadPools
您应该将您的控制器更新为 return Promise,也没有理由再使用 Play 2.4 将其设为静态。 https://www.playframework.com/documentation/2.4.x/Migration24#Routing
在 application.conf 中定义一个名为 "jdbc-execution-context"
的执行上下文//reference to context
ExecutionContext jdbcExecutionContext = Akka.system().dispatchers()
.lookup("jdbc-execution-context");
return promise(() -> {
//db call
}, jdbcExecutionContext)
.map(callResult -> ok(callResult));