播放框架和jdbc阻止io调用是否存在主要的扩展限制

我正在使用playframework(2.4)for Java并将其连接到Postgres。 play框架被用作一个宁静的服务,它所做的就是使用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可以绝对处理这个负载。

文档指出应该在控制器方法中避免阻塞代码 – 调整默认配置以使它们具有异步执行。 如果你在那里粘贴了一些阻塞调用,你的控制器现在将等待该调用完成,然后才能处理另一个传入请求 – 这很糟糕。

通过将同步IO包装在Promise中,您无法神奇地将同步IO转变为异步。 如果您无法更改应用程序的体系结构以避免阻塞操作,那么在某些时候必须执行操作,并且该线程将阻塞。 因此,除了将操作包含在Promise中之外, 还必须将其配置为在单独的执行上下文中运行,该上下文已配置有足够的线程来处理预期的并发性 。 有关更多信息,请参阅了解Play线程池。 https://www.playframework.com/documentation/2.4.x/JavaAsync#Make-controllers-asynchronous

我相信你知道这一点,但我想指出粗体部分。 您的数据库具有可供应用程序调用的有限数量的线程 – 跟踪此数字可能会有所帮助,为这些线程创建新的执行上下文,并将新的执行上下文分配给承诺包装你的数据库调用。

查看这篇关于Play应用程序转换的post,它应该让你知道这看起来像什么。 我相信他正在使用Akka Actors,这可能超出你的范围,但线程调整的想法是一样的:

对于不包含阻塞调用(即异步)的HTTP请求,Play 2已经开箱即用。 Java中大多数数据库驱动的应用程序都使用JDBC进行同步调用,因此Play 2需要一些额外的配置来针对这些类型的请求调整Akka。 http://www.jamesward.com/2012/06/25/optimizing-play-2-for-database-driven-apps

如果您尝试在不转动线程的情况下在数据库上执行大量请求,则存在使线程应用程序的其余部分挨饿的风险,这将使您的应用程序停止运行。 对于您期望的负载,默认调整可能没问题,但值得进行一些额外的调查。

线程调整入门: https : //www.playframework.com/documentation/2.4.x/ThreadPools

你应该更新你的控制器以返回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));