REST API 响应时间在负载下增加 [Tomcat]

Mad*_*uja 2 java performance spring tomcat akka

我们有一个 REST API (GET),可供大量移动用户同时调用。我们目前的用户群约为 30 万,但预计将增长到 100 万左右。

API 很简单。它使用 Akka 发出 3 个并行请求,并返回组合结果。主要代码如下所示:

        Future<List<CardDTO>> pnrFuture = null;
        Future<List<CardDTO>> newsFuture = null;

        ExecutionContext ec = ExecutionContexts.fromExecutorService(executor);

        final List<CardDTO> combinedDTOs = new ArrayList<CardDTO>();

        // Array list of futures
        List<Future<List<CardDTO>>> futures = new ArrayList<Future<List<CardDTO>>>();

        futures.add(future(new PNRFuture(pnrService, userId), ec));
        futures.add(future(new NewsFuture(newsService, userId), ec));
        futures.add(future(new SettingsFuture(userPreferenceManager, userId), ec));

        Future<Iterable<List<CardDTO>>> futuresSequence = sequence(futures, ec);

        // combine the cards
        Future<List<CardDTO>> futureSum =  futuresSequence.map(
                new Mapper<Iterable<List<CardDTO>>, List<CardDTO>>() {
                    @Override
                    public List<CardDTO> apply(Iterable<List<CardDTO>> allDTOs) {

                        for (List<CardDTO> cardDTOs : allDTOs) {

                            if(cardDTOs!=null)
                                combinedDTOs.addAll(cardDTOs);

                        }

                        Collections.sort(combinedDTOs);

                        return combinedDTOs;
                    }
                }
        );

        Await.result(futureSum, Duration.Inf());

        return combinedDTOs;
Run Code Online (Sandbox Code Playgroud)

这 3 个 future 是来自 MY SQL 数据库的简单选择语句,执行时间不到一毫秒。我们这里使用 Spring + Hibernate。

整个API平均需要50ms返回结果。

现在,当我们用3台服务器进行性能测试时,我们得出的结论是,在大约200个请求/秒之后,API的响应时间开始线性增加。在负载下它会高达 3 -5 秒。令人惊讶的是,当时 CPU 使用率约为 20%,而 JVM 内存中没有发生任何重大变化。内存使用量约为 700 MB。我们有 16 GB

我找不到瓶颈在哪里。如何将此 API 扩展到至少 1000 个请求/秒。我至少正在寻找从哪里开始的指导。我探索过类似的工具topvisualvm之类的工具,但没有发现任何令人担忧的事情。

这是我们在 Java 7 上的 JVM 设置

导出JAVA_OPTS =“$ JAVA_OPTS -Djava.awt.headless = true -server -Xms4g -Xmx16g -XX:MaxPermSize = 1g -XX:PermSize = 512m -XX:MaxNewSize = 4g -XX:NewSize = 512m -XX:SurvivorRatio = 16 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=0 -XX:CMSInitiatingOccupancyFraction=60 -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:ParallelGCThreads=12 -XX:LargePageSizeInBytes=256m -Dspring.profiles.active =staging -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9899 -Djava.rmi.server.hostname=$HOSTNAME -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun。管理.jmxremote.ssl = false”

我读过这些问题,似乎这是一个大趋势。切换到其他框架(例如 Node.js 或 Erlang)会有帮助吗?

Java 中的响应时间随着并发量的增加而增加

随着 apache bench 中并发性的增加,Tomcat 响应时间也在增加

Ada*_*ent 5

不可能确定你的性能问题出在哪里,但我发现它通常是因为(根据你的描述):

  • 存在争用问题的线程或连接池(数据库连接池或 tomcat 请求池)
  • 同步变量/代码或BlockingQueue(可以是上述内容的超集)。
  • 负载均衡器或配置错误
  • 信号不好

我建议你尽可能地隔离。首先证明不是数据库连接池。即运行相同的并发负载,但仅执行数据库部分。请记住,三台服务器需要 3 个连接。

接下来运行 1-3 个服务器来进行模拟响应,而无需使用或不使用负载均衡器进行任何数据处理。您可能会惊讶地发现负载均衡器/网络经常会导致问题。

继续分离事物......测试、观察、重复。

最后,当您将其真正隔离为 Tomcat 时,您可能想阅读Netflix 的内容。