Play非阻塞与Spring阻塞-纯Play的性能

时间:2018-12-24 10:45:08

标签: spring performance playframework blocking nonblocking

我制定了一些基准测试来确定非阻塞io是否真的比阻塞更好。

为此,我写信给服务:一个在玩,另一个在春天。 每个服务发出几个并行的远程请求: Play使用非阻塞WSClient,Sprint-阻塞RestTemplate。

但是在具有各种配置的所有基准测试中(我已经使用过Apache长凳和火炮),弹簧靴的性能要优于其他。

在游戏中,我经常会因apache bench发生Connection reset by peer (54)错误(尽管spring句柄可以很好地保存并发用户的值)。

这确实让我感到困惑,我试图在播放配置中设置各种值(例如并行度等),但仍然无济于事。

这两个服务都部署到了运行ubuntu 18的t2.xlarage的AWS(每个服务都在其自己的实例上运行)。

播放服务代码:

HomeController

@Singleton
class HomeController @Inject()(requestService: RequestService, cc: ControllerComponents)(implicit ec: ExecutionContext) extends AbstractController(cc) {


  def index() = Action { implicit request: Request[AnyContent] =>
    Ok(views.html.index())
  }

  val rand = new Random

  def parallelRequests() = Action.async {
    val futures = (1 to 10).map( _ =>
      requestService.makeRequest(s"http://3.17.161.135:9000?p=${rand.nextInt(99999) + 1}"),
    )

    Future.sequence(futures).map{ _ =>
      Ok("Done")
    }
  }
}

请求服务

@Singleton
class RequestService @Inject()(wsClient: WSClient)(implicit ec: ExecutionContext){

  def makeRequest(url: String): Future[String] = {
      wsClient.url(url).get().map { r =>
        r.body
      }
  }

}

application.conf

# https://www.playframework.com/documentation/latest/Configuration
play.filters.enabled += play.filters.hosts.AllowedHostsFilter

play.filters.hosts {
  # Allow requests to example.com, its subdomains, and localhost:9000.
  allowed = ["."]
}

play.application.secret = "supersecret"

akka {
  http {
    server {
      max-connections = 1024
    }
  }
  actor {
    default-dispatcher {
      # This will be used if you have set "executor = "fork-join-executor""
      fork-join-executor {
        # Min number of threads to cap factor-based parallelism number to
        parallelism-min = 8

        # The parallelism factor is used to determine thread pool size using the
        # following formula: ceil(available processors * factor). Resulting size
        # is then bounded by the parallelism-min and parallelism-max values.
        parallelism-factor = 3.0

        # Max number of threads to cap factor-based parallelism number to
        parallelism-max = 64

        # Setting to "FIFO" to use queue like peeking mode which "poll" or "LIFO" to use stack
        # like peeking mode which "pop".
        task-peeking-mode = "FIFO"
      }
    }
  }
}

(我在这里尝试过其他操作,包括播放的默认配置)

完整的播放服务源代码:http://cat1.com

春季服务

控制器

@RestController
public class Controller {

    private RequestService requestService;

    @Autowired
    public Controller(RequestService requestService) {
        this.requestService = requestService;
    }

    Random rand = new Random();

    @GetMapping
    public String home() {
        return "Hi";
    }

    @GetMapping("/parallel-requests")
    public String parallelRequests() throws InterruptedException {
        CompletableFuture<String> res1 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res2 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res4 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res5 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res6 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res7 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
//        CompletableFuture<String> res8 = requestService.makeRequest("https://amazon.com?p=" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res9 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);
        CompletableFuture<String> res10 = requestService.makeRequest("http://18.188.1.66:8080" + rand.nextInt(99999) + 1);

        CompletableFuture.allOf(res1, res2, res4, res5, res6, res7,  res9, res10).join();
        return "Done";
    }
}

RequestService

@Service
public class RequestService {

    private static final Logger logger = LoggerFactory.getLogger(RequestService.class);

    private final RestTemplate restTemplate;

    @Autowired
    public RequestService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    @Async
    public CompletableFuture<String> makeRequest(String url) throws InterruptedException {
//        logger.info("Making request to url " + url);
        String result = "";
        result = restTemplate.getForObject(url, String.class);
        return CompletableFuture.completedFuture(result);
    }
}

应用

@SpringBootApplication
@EnableAsync
public class BenchmarkApplication {

    public static void main(String[] args) {
        SpringApplication.run(BenchmarkApplication.class, args);
    }

    @Bean
    public Executor taskExecutor() {
        return Executors.newFixedThreadPool(400);

    }
}

application.properties

server.tomcat.max-threads=500

完整的源代码https://github.com/teimuraz/benchmark-play-async

用炮兵进行基准测试

artillery quick --count 500 -n 20 [url]

播放

Summary report @ 14:47:25(+0400) 2018-12-24
  Scenarios launched:  500
  Scenarios completed: 411
  Requests completed:  8614
  RPS sent: 104.45
  Request latency:
    min: 150.9
    max: 72097.2
    median: 195
    p95: 1793.2
    p99: 12623.9
  Scenario counts:
    0: 500 (100%)
  Codes:
    200: 8614
  Errors:
    ECONNRESET: 89

春天

Summary report @ 14:49:14(+0400) 2018-12-24
  Scenarios launched:  500
  Scenarios completed: 500
  Requests completed:  10000
  RPS sent: 600.24
  Request latency:
    min: 155.2
    max: 3550.4
    median: 258.9
    p95: 500.8
    p99: 1370.7
  Scenario counts:
    0: 500 (100%)
  Codes:
    200: 10000    

游戏中的RPS为150,而春季为600 !!

以a作为基准结果

ab -n 5000 -c 200 -s 120 [url]

播放

apr_socket_recv: Connection reset by peer (54)

春天

Concurrency Level:      200
Time taken for tests:   23.523 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      680000 bytes
HTML transferred:       20000 bytes
Requests per second:    212.56 [#/sec] (mean)
Time per request:       940.924 [ms] (mean)
Time per request:       4.705 [ms] (mean, across all concurrent requests)
Transfer rate:          28.23 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      153  352 198.5    303    1485
Processing:   163  364 242.4    319    6589
Waiting:      163  363 240.3    318    6589
Total:        324  716 313.2    642    7003

我在玩游戏时怎么了?

我应该调整哪些配置值以使游戏性能更好?

还是非阻塞仅仅是炒作和流行语?

0 个答案:

没有答案