Web
수정·
FastAPI와 NestJS 의 단순 IO 성능 비교
FastAPi, NestJS간의 비교
Python의 Web Framework FastAPI 와 Node 의 Web Framework를 DB R/W 를 통한 단순 성능 비교를 해보았다 테스트 방식은 wrk + luascript 를 이용하여 10초간 최대한 많은 data를 Post Method 를 이용하여 생성 요청을 보내고, 최대한 많은 데이터를 GET method 를 통하여 조회하도록 하였다.
공통 설정
- Database : Postgres 14.3
$ docker run -it --rm \
-e POSTGRES_DB=postgres \
-e POSTGRES_DB_USER=postgres \
-e POSTGRES_DB_PASSWORD=postgres \
--network host \
postgres:latest
- Test Entity
class Entity :
id = Column(Integer,pk=True, autoincrement=True)
title = Column(String, not_null = True)
content = Column(String, not_null = True)
FastAPI 설정
- ORM : SQLAlchemy['asyncio'] 사용
- JSON Serializer : Pydantic 이용
- 기타 : 비동기 처리를 위해 asyncpg 를 이용하였음.
- 실행옵션
$ uvicorn --host 0.0.0.0 --port 8000 --no-access-log --workers=1
# 입력, 조회 코드
@app.get('/{id:int}', response_model = TestEntityScheme)
async def get(id : int, session : AsyncSession = Depends(get_session)) :
stmt = select(TestEntity).where(TestEntity.id==id)
future = await session.execute(stmt)
data = future.scalar()
return data
@app.post('/')
async def post(model : TestScheme, session : AsyncSession = Depends(get_session)) :
new_entity = TestEntity(model)
session.add(new_entity)
return model
Nestjs 설정
- ORM : typeorm
- 기타 : Nestjs 는 backend로 express와 fastify 를 지원하여 둘 다 테스트를 진행하였다.
- 실행옵션
$ npm run start
// 입력/조회 코드
async create(form : TestEntityRegisterScheme) : Promise<TestEntityScheme>{
const gen = this.entity.create(form);
const ret = await this.entity.save(gen)
if(ret){
return ret;
}
throw new HttpException("fail to create entity.", HttpStatus.CONFLICT);
}
async fetch(id : number) : Promise<TestEntityScheme>{
// console.log("find by id : ", id)
const entity : TestEntityScheme = await this.entity.findOneBy({id:id})
return entity;
}
결과
FastAPI + Uvicorn + Asyncpg + SQLAlchemy
$ (benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/post.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 31.91ms 70.07ms 435.51ms 89.09%
Req/Sec 0.95k 401.81 1.34k 77.91%
16969 requests in 10.01s, 2.75MB read
Requests/sec: 1695.83
Transfer/sec: 281.22KB
$ (benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/get.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 9.56ms 12.82ms 148.44ms 93.63%
Req/Sec 715.47 180.99 0.93k 67.34%
14184 requests in 10.01s, 2.42MB read
Requests/sec: 1417.18
Transfer/sec: 247.14KB
NestJS + TypeORM + PG + Express
$ (benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/post.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.00ms 6.64ms 129.87ms 98.54%
Req/Sec 2.11k 390.20 3.59k 86.57%
42189 requests in 10.10s, 11.46MB read
Requests/sec: 4176.98
Transfer/sec: 1.13MB
$ (benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/get.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.66ms 723.29us 7.92ms 78.88%
Req/Sec 1.87k 263.51 2.16k 90.51%
29419 requests in 10.00s, 8.09MB read
Socket errors: connect 0, read 0, write 0, timeout 10
Requests/sec: 2940.47
Transfer/sec: 827.94KB
NestJS + TypeORM + PG + Fastify
(benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/post.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.61ms 6.13ms 124.44ms 98.76%
Req/Sec 4.89k 1.04k 6.11k 85.57%
97879 requests in 10.10s, 20.61MB read
Requests/sec: 9692.73
Transfer/sec: 2.04MB
(benchmark) ➜ wrk git:(master) ✗ ./wrk http://127.0.0.1:8000 -s ./scripts/get.lua
Running 10s test @ http://127.0.0.1:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.25ms 647.62us 20.98ms 96.01%
Req/Sec 4.11k 490.81 4.65k 89.11%
82676 requests in 10.10s, 17.70MB read
Requests/sec: 8185.85
Transfer/sec: 1.75MB
결과
단순 IO bound 회피 성능을 확인해보고자 한 테스트였고 그에 따른 성능의 결과는 NestJS-Fastify (초당 8000건) > NestJS-Express(초당 3500건) > FastAPI(초당 1600건) 순으로 나타났다. 프레임워크에 대한 조작 미숙으로 인해 발생한 문제라면 해당하지 않겠지만 FastAPI 가 주장하는 express 급 성능은 단순히 String만을 바로 반환하는 Endpoint 에서만 나타났고 DB 조회 쪽에선 급격히 떨어지는 것으로 보인다. 이 성능이 json serializer 로 인한 성능 차이인지도 확인이 필요하다.