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

时间:2015-11-29 17:39:24

标签: java spring performance 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;

3期货是来自MY SQL数据库的简单select语句,它在一毫秒内执行。我们在这里使用Spring + Hibernate。

整个API需要50毫秒才能平均返回结果。

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

我无法找到瓶颈所在。如何将此API扩展到至少1000个请求/秒。我至少在寻找从哪里开始的指针。我已经探索了topvisualvm等工具,但没有发现任何令人担忧的内容。

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

  

export JAVA_OPTS =&#34; $ 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.management.jmxremote.ssl = false&#34;

我已经阅读了这些问题,这似乎是一个大趋势。会切换到node.js或Erlang等其他框架吗?

Response time Increases as concurrency increases in Java

Tomcat response time is increasing as concurrency is increased in apache bench

1 个答案:

答案 0 :(得分:3)

无法确定您的性能问题在哪里,但我发现它一般是因为(根据您的描述):

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

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

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

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

最后当你把它隔离成真正的Tomcat时,你可能想要阅读Netflix does