TIL

24/01/14 TIL __ 커넥션 풀

GABOJOK 2024. 1. 14. 23:34

 

 

대용량 트레픽 관련 필요한 기술들을 찾다보니 

커넥션 풀 이라는 개념을 만났다.

 

 

커넥션 풀

네트워크와 데이터베이스 연결을 하는 것 자체가 비용이 든다.

커넥션 풀 없이 데이터베이스에 연결해서 요청을 처리하는 과정을 한번 생각해 보자

 

----> 클라이언트가 연결요청을 보내면, 데이터베이스 서버에 연결요청을 한다. 

----> 그럼 데이터베이스 서버는 새로운 연결을 생성하고, 클라이언트에게 할당한다. (이때 리소스, 비용 소모)

----> 클라이언트는 할당받은 연결을 이용해서 쿼리를 수행하고, 연결을 종료한다

----> 연결 종료를 하면 연결은 완전히 해제가 되고, 다시 사용될 수 없다.

 

유저가 적다면 크게 상관이 없겠지만,

수많은 유저가 동시에 요청을 보낸다면, 엄청난 리소스와 비용이 소모될 것이다. 

뿐만 아니라 서버 에러가 발생할 수 있을 것이다. 

 

이러한 부분을 보완하기 위해 나온 것이 커넥션 풀이다.

클라이언트 요청과, 데이터 베이스 사이에 커넥션 풀을 두어서

미리 연결을 해두고, 클라이언트가 요청 할 때 마다 새로 연결할 필요 없이 미리 만들어둔 연결루트를 사용한다.

과정을 살펴보면 아래와 같다. 

 

----> 클라이언트가 연결요청을 보내면, 커넥션 풀에 연결 요청이 간다. 

----> 커낵션 풀은 이미 생성된 연결중 한개를 할당해서 클라이언트에게 제공한다

----> 클라이언트는 할당받은 연결로 쿼리 수행하고 끝나면 연결을 풀에 반환한다.

----> 반환된 연결은 다시 사용 가능한 상태로 유지된다.

 

 

 

 

그럼 언제 연결을 생성할까? 

초기 연결 풀링 이라고 하던데,

애플리케이션이 시작할 때 미리 정의된 개수만큼의 연결을 생성한다. 

그래서 생성한 연결로 클라이언트 요청이 들어오면 연결을 할당해서 사용하는 것!

예상된 동시 사용자 수, 서버가 감당할수 있는 리소스 양을 계산하고

또 응답시간을 어느 정도로 설정할 것인지를 생각해서 결정하면 될것 같다.

 

거기에 동적으로 연결을 생성할 수도 있다고 한다.

일정시간동안 사용되지 않은 연결이 있다면, 이걸 해제하거나 할 수도 있다.

물론 주의해야 할 부분은 분명 있다. 많은 연결이 갑자기 동시에 생성되어 서버가 감당 가능한 최대 연결수를 초과하지 않도록 해야한다. 

서버의 성능, 용량 고려해야 한다는 말이다.

 

 

 

커넥션 풀을 처리하기 위한 다양한 방법

 

nodejs 환경에서 사용할만한 도구로는 

TypeORM, Prisma, pg-pool, mysql2 등이 있었는데,

 

나라면 TypeOrm을 선택해 사용할 것 같다고 생각했다.

 

왜냐하면,

TypeORM은 내장 커넥션 풀 이기 때문에 별도의 설정이 필요가 없고,

typescript에서 지원도 잘 될 뿐더러,

데이터베이스와 연동도 간편하기 때문이다. 

외부에서 내장된 커넥션 풀을 쉽게 변경하기 어려다는 단점도 있다고 하지만, 

이부분은 좀더 고민해 봐야 할 것 같다. 라이브 스트리밍 서비스에 과연 어떤 영향을 가진 단점인지.

 

pg-pool은 postgreSQL과 사용하는 라이브러리 인데, sql을 사용할것이기 때문에 패스

 

prisma는 커스텀 쿼리 사용이 제한적이라 대용량 트래픽 처리시 쿼리 최적화를 할때 불편할것 같아 패스

 

mysql2는 mysql에 특화된 라이브러리 이기도 하고, 비동기도 지원하지만, 타입스크립트 지원이 미흡하다 해서 패스할것 같다. 

 

 

 

 

 

TypeORM 으로 커넥션 풀을 만들어 관리하려면

이런식으로 사용하면 될 것 같은데, 자세한건 실제 코드 구현할때 좀더 봐야할 것 같다. 

// database.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'user',
      password: 'password',
      database: 'mydb',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
      extra: {
        connectionLimit: 10, // 최대 동시 커넥션 수
      },
    }),
  ],
})
export class DatabaseModule {}