我有一个测试 EE7 应用程序,其中一个 servlet 调用一个 EJB,该 EJB 使用 ExecutorService 运行一组线程化的任务。与运行相同任务集的沼泽标准 Java 控制台应用程序相比,性能(每秒事务数)相差甚远 - 控制台应用程序中的 2.5k tps 与 EE 应用程序中的 50 tps(均使用 256 个线程调用重复代码 60 秒,EE 应用程序通过 SoapUI 完成)。
这些任务只是休眠 100 毫秒的虚拟实现。测试中,提交了5个并行任务;时序显示所有这些都按预期在 100-101 毫秒内完成 - Glassfish+Servlet+EJB 似乎根本不会增加太多开销。
我在 Windows 和 Linux 下都做了同样的测试,结果是一样的。在这两种情况下,我都使用带有默认 ManagedExecutorService 的 Glassfish 4.0。我已将最大连接数/缓存/bean/线程/等设置增加到 256。
注意:如果我只是调用 EJB 但不向 ExecutorService 提交任何内容,我会得到 9k tps。如果我从任务中等待,我会得到 5k tps。我的机器似乎永远不会耗尽资源(cpu 核心平均在 10-25% 之间,系统内存可用(尚未调整 jvm))。
我很欣赏这有点含糊,但您认为这更多是 Glassfish 的配置问题,还是在 Java EE7 中运行托管线程?我希望 Glassfish 至少有 1k tps,并希望有 2k。
更新:我已经尝试过 JBoss 的 Wildfly 8 beta,我得到了大约 5k tps - 一个巨大的差异。
从下面的代码重新创建:在 Netbeans 7.4 中创建一个针对 Glassfish 4/EE7 的 EE 应用程序,然后添加 Servlet 和 EJB。
EJB + 任务类:
package ejb;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import javax.annotation.Resource;
import javax.ejb.*;
import javax.enterprise.concurrent.ManagedExecutorService;
@Stateless
@LocalBean
public class NewSessionBean {
@Resource(name="concurrent/__defaultManagedExecutorService")
ManagedExecutorService executor;
public String businessMethod() {
long start = System.currentTimeMillis();
String message = "<p>starting businessMethod()</p>";
List<MyTask> tasks = new ArrayList<MyTask>();
for(int i = 0; i < 5; i++) {
MyTask task = new MyTask(String.format("Task %d \r\n", i));
tasks.add(task);
}
List<Future<String>> futures = new ArrayList<Future<String>>();
int taskCount = tasks.size();
for(int i = 0; i < taskCount; i++) {
MyTask task = tasks.get(i);
if(task != null) {
futures.add(executor.submit(task));
}
}
int futureCount = futures.size();
for(int i = 0; i < futureCount; i++) {
Future<String> future = futures.get(i);
if(future != null) {
try {
message += future.get();
} catch (InterruptedException ex) {
message += ex.getMessage();
Logger.getLogger(NewSessionBean.class.getName()).log(Level.SEVERE, null, ex);
} catch (ExecutionException ex) {
message += ex.getMessage();
Logger.getLogger(NewSessionBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
long end = System.currentTimeMillis();
message += String.format("<p>took %d ms (started at %d)</p>", end-start, start);
return message;
}
}
class MyTask implements Callable<String> {
String message;
public MyTask(String message) {
this.message = message;
}
@Override
public String call() throws Exception {
if(message == null) message = "";
long start = System.currentTimeMillis();
message += String.format("<p>thread %s</p>", Thread.currentThread().getName());
message += String.format("<p>started at %d</p>", start);
Thread.sleep(100);
long end = System.currentTimeMillis();
message += String.format("<p>ended at %d (duration = %d ms)</p>", end, end-start);
return message;
}
}
小服务程序:
package servlet;
import java.io.*;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class NewServlet extends HttpServlet {
@EJB
ejb.NewSessionBean nsb;
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet NewServlet at " + request.getContextPath() + "</h1>");
out.println(nsb.businessMethod());
out.println("</body>");
out.println("</html>");
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}
}