{"id":28831403,"url":"https://github.com/earlgrey02/webflux-performance-test","last_synced_at":"2026-04-21T16:36:48.890Z","repository":{"id":299454631,"uuid":"1002739052","full_name":"earlgrey02/webflux-performance-test","owner":"earlgrey02","description":"Performance Comparison of Spring WebFlux and Spring Web MVC","archived":false,"fork":false,"pushed_at":"2025-06-16T16:15:05.000Z","size":57,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-16T17:37:50.248Z","etag":null,"topics":["kotlin","spring"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/earlgrey02.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-16T04:21:07.000Z","updated_at":"2025-06-16T16:15:08.000Z","dependencies_parsed_at":"2025-06-16T17:38:58.699Z","dependency_job_id":"8ecd9648-d1dc-461e-bfe2-3c6447be166a","html_url":"https://github.com/earlgrey02/webflux-performance-test","commit_stats":null,"previous_names":["earlgrey02/webflux-performance-test"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/earlgrey02/webflux-performance-test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earlgrey02%2Fwebflux-performance-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earlgrey02%2Fwebflux-performance-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earlgrey02%2Fwebflux-performance-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earlgrey02%2Fwebflux-performance-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/earlgrey02","download_url":"https://codeload.github.com/earlgrey02/webflux-performance-test/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earlgrey02%2Fwebflux-performance-test/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32100573,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T11:25:29.218Z","status":"ssl_error","status_checked_at":"2026-04-21T11:25:28.499Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kotlin","spring"],"created_at":"2025-06-19T06:39:26.210Z","updated_at":"2026-04-21T16:36:48.881Z","avatar_url":"https://github.com/earlgrey02.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"## WebFlux performance test\n\n\u003e **Spring Web MVC와의 비교를 통한 Spring WebFlux 성능 테스트**\n\n본 저장소는 Spring Web MVC와 Spring WebFlux의 성능 비교를 수행하는 테스트에 대한 저장소이다.\n\n## Setup\n\n### Environment\n\n일반적인 개발 환경을 구성하기 위해 대부분의 설정에서 기본값을 사용하도록 했다.\n참고로 테스트에 사용된 시스템의 CPU 코어 수는 총 12개이다.\n\n* Spring Web MVC\n    * Tomcat\n        * 스레드 풀 크기: 200\n* Spring WebFlux\n    * Reactor Netty\n        * 이벤트 루프 스레드 개수: 12(CPU 코어 수)\n    * Reactor\n        * `ParallelScheduler`의 스레드 풀 크기: 12(CPU 코어 수)\n        * `BoundedElasticScheduler`의 스레드 풀 크기: 120(CPU 코어 수 x 10)\n\n### Test Case\n\nApache JMeter를 사용하여 부하 테스트를 수행하며, 모든 테스트는 Cold Start 환경에서 10,000건의 요청을 한 번에 받도록 하는 방식으로 수행했다.\n\n* CPU Bound\n    * 반복문을 통해 총 10,000,000회의 제곱근 연산(`sqrt()`)을 수행\n* I/O Bound\n    * 데이터베이스로부터 단일 데이터 조회(`SELECT * FROM DEMO WHERE id = 1 LIMIT 1`) 수행\n\n## Result\n\n### CPU Bound\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth rowspan=\"2\"\u003e\u003c/th\u003e\n      \u003cth rowspan=\"2\"\u003eSpring Web MVC\u003c/th\u003e\n      \u003cth colspan=\"3\"\u003eSpring WebFlux\u003c/th\u003e\n    \u003c/tr\u003e \n    \u003ctr\u003e\n      \u003cth\u003eWithout Scheduler\u003c/th\u003e\n      \u003cth\u003eWith Scheduler\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eTotal Requests\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eAverage Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e1435\u003c/td\u003e\n      \u003ctd\u003e2229\u003c/td\u003e\n      \u003ctd\u003e1877\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eMin Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e136\u003c/td\u003e\n      \u003ctd\u003e50\u003c/td\u003e\n      \u003ctd\u003e85\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eMax Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e4421\u003c/td\u003e\n      \u003ctd\u003e8383\u003c/td\u003e\n      \u003ctd\u003e4785\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eResponse Time Std. Dev.\u003c/td\u003e\n      \u003ctd\u003e787.49\u003c/td\u003e\n      \u003ctd\u003e2824.23\u003c/td\u003e\n      \u003ctd\u003e815.68\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eError Rate (%)\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eThroughput (req/sec)\u003c/td\u003e\n      \u003ctd\u003e2201.18\u003c/td\u003e\n      \u003ctd\u003e1022.39\u003c/td\u003e\n      \u003ctd\u003e2085.94\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003ePeak Thread Count\u003c/td\u003e\n      \u003ctd\u003e222\u003c/td\u003e\n      \u003ctd\u003e46\u003c/td\u003e\n      \u003ctd\u003e57\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\nCPU Bound 테스트에서는 **Spring Web MVC가 Spring WebFlux보다 뛰어난 성능**을 보이는 것을 확인할 수 있다.\n이는 Spring WebFlux에서는 CPU Bound 작업으로 인해 이벤트 루프 스레드가 차단되면 요청을 더 이상 받을 수 없기 때문이다.\n게다가 이벤트 루프 스레드는 기본적으로 CPU 코어 수와 동일한 개수만을 가지는데, 이는 Tomcat의 최대 스레드 수 기본값인 200개에 비해 훨씬 적은 개수이다.\n그러므로 Spring WebFlux는 CPU Bound 작업 등의 블로킹 작업에 더 큰 성능 저하를 겪게 된다.\n\n그러나 **Spring WebFlux에서 Reactor의 `ParallelScheduler`를 사용한 경우에는 Spring Web MVC와 비슷한 성능**을 보이는 것을 확인할 수 있다.\n이는 CPU Bound 작업이 이벤트 루프와 분리된 전용 스레드 풀에서 처리되기 때문이다.\n\n### I/O Bound\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth rowspan=\"3\"\u003e\u003c/th\u003e\n      \u003cth rowspan=\"3\"\u003eSpring Web MVC\u003c/th\u003e\n      \u003cth colspan=\"3\"\u003eSpring WebFlux\u003c/th\u003e\n    \u003c/tr\u003e \n    \u003ctr\u003e\n      \u003cth rowspan=\"2\"\u003eR2DBC\u003c/th\u003e\n      \u003cth colspan=\"2\"\u003eJDBC\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth\u003eWithout Scheduler\u003c/th\u003e\n      \u003cth\u003eWith Scheduler\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eTotal Requests\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n      \u003ctd\u003e10000\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eAverage Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e2927\u003c/td\u003e\n      \u003ctd\u003e1065\u003c/td\u003e\n      \u003ctd\u003e3225\u003c/td\u003e\n      \u003ctd\u003e3148\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eMin Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e200\u003c/td\u003e\n      \u003ctd\u003e199\u003c/td\u003e\n      \u003ctd\u003e129\u003c/td\u003e\n      \u003ctd\u003e101\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eMax Response Time (ms)\u003c/td\u003e\n      \u003ctd\u003e4700\u003c/td\u003e\n      \u003ctd\u003e1585\u003c/td\u003e\n      \u003ctd\u003e7978\u003c/td\u003e\n      \u003ctd\u003e4995\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eResponse Time Std. Dev.\u003c/td\u003e\n      \u003ctd\u003e1185.45\u003c/td\u003e\n      \u003ctd\u003e289.32\u003c/td\u003e\n      \u003ctd\u003e2363.67\u003c/td\u003e\n      \u003ctd\u003e1206.43\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eError Rate (%)\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n      \u003ctd\u003e0.00%\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003eThroughput (req/sec)\u003c/td\u003e\n      \u003ctd\u003e1348.25\u003c/td\u003e\n      \u003ctd\u003e2874.39\u003c/td\u003e\n      \u003ctd\u003e1006.40\u003c/td\u003e\n      \u003ctd\u003e1316.70\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\"\u003ePeak Thread Count\u003c/td\u003e\n      \u003ctd\u003e223\u003c/td\u003e\n      \u003ctd\u003e47\u003c/td\u003e\n      \u003ctd\u003e46\u003c/td\u003e\n      \u003ctd\u003e166\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\nI/O Bound 테스트에서는 **R2DBC를 사용한 Spring WebFlux가 Spring Web MVC보다 뛰어난 성능**을 보이는 것을 확인할 수 있다.\n지연 시간뿐만 아니라 사용한 스레드 수 측면에서도 훨씬 효율적인 결과를 보여주는데, 이는 Spring WebFlux에서는 논블로킹 I/O를 기다리는 동안 이벤트 루프 스레드는 차단되지 않고 계속해서 새로운 요청을 처리할 수 있기\n때문이다.\n\n그러나 **Spring WebFlux에서 R2DBC와 같은 논블로킹 I/O가 아닌 JDBC와 같은 블로킹 I/O를 사용할 경우에는 오히려 Spring Web MVC보다 낮은 성능**을 보이는 것을 확인할 수 있다.\n이는 앞서 살펴본 CPU Bound 테스트와 마찬가지로, 블로킹 작업이 이벤트 루프 스레드를 점유하면서 전체 처리 성능을 저하시키기 때문이다.\n이러한 경우에도 **Reactor의 `BoundedElasticScheduler`를 사용하면 Spring Web MVC와 비슷한 성능**을 낼 수 있음을 확인할 수 있다.\n\n## Summary\n\n테스트 결과를 통해, **Spring WebFlux는 논블로킹 I/O가 많은 환경에서 가장 뛰어난 성능**을 발휘한다는 결론을 도출할 수 있었다.\n반면, **CPU Bound 작업이나 블로킹 I/O가 많은 경우에는 Spring Web MVC가 압도적으로 더 나은 성능**을 보였다.\n다만, 이러한 상황에서도 **Reactor의 `Scheduler`를 적절히 활용하면 적은 수의 스레드로도 Spring Web MVC에 근접한 성능**을 낼 수 있다는 것으로 결론을 내렸다.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearlgrey02%2Fwebflux-performance-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fearlgrey02%2Fwebflux-performance-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearlgrey02%2Fwebflux-performance-test/lists"}