API서버 에서 DB접근이 많을 때 질문있습니다.

일전에 C# Winform 프로그램(이하 클라이언트) 보안에 대해 궁금한 점을 올린적이 있었는데요,
결국 디컴파일은 피할수 없기때문에 핵심로직이나 DB에 접근해야하는 경우는 따로 API서버를 두고 사용하는 것이 좋을 것 같다는 생각을 했습니다.

그래서 일단 우분투서버에 도커를 설치 후 컨테이너에 API서버를 구축해서 해당 API서버에서 DB에 접근하도록 했는데요, 클라이언트에서 DB 조회나 삽입, 업데이트 등의 동작을 하기 위해 각각의 api 요청을 하게끔 했습니다.
api요청 → 서버에서 db 연결-> 필요한 작업 진행(조회, 삽입, 업데이트) → db 연결 해제 → 작업결과 리턴
이런 순서로 진행을 하는데, 여기서 궁금한점은 다수의 클라이언트 프로그램에서 api 동시요청이 많아지면
제 생각으로는 db연결과 해제를 계속해서 많이 반복하게 될 텐데 이 때 발생할만한 문제가 있을지, 그리고 저 반복으로 인해 응답시간에 영향이 생기지는 않을 지, 혹은 그 외 다른 이슈는 없을 지 궁금합니다!

참고로 api서버는 fastapi를 사용하여 구현하였습니다!

1개의 좋아요

커넥션 풀을 이용하기 때문에 문제 없습니다.

3개의 좋아요

한번 요청에 connect() → close() 반복해도 내부적으로는 커넥션풀을 사용한다는걸까요?

1개의 좋아요


기본 옵션이 커넥션풀 사용입니다.

2개의 좋아요

서버를 만들기 나름인데 보통 서버는 캐싱해서 메모리에서 처리됩니다.

1개의 좋아요

아아 그렇다면 동시에 다수의 api요청이 들어오더라도 쿼리자체가 오래걸리거나 내부로직에서 시간이 걸리는 경우가 아닌 이상 응답속도에는 영향이 없다고 이해해도 괜찮을까요?

1개의 좋아요

네 맞습니다.

2개의 좋아요

좀 부분적인 얘기인데요.

Api에서 Db에 조회 쿼리를 보내는 것보다, 저장 프로시저를 호출하는 쿼리를 보내는 것이 Db 성능, 안정성, 보안에 도움을 준다고 합니다.

Db는 쿼리를 받으면, 이를 컴파일한 후에 실행하는데, 저장 프로시저는 쿼리를 미리 컴파일해 놓은 것이라, 쿼리 컴파일에 자원을 소모할 일이 없어, Db 성능에 좋고,

Db 에 Api 계정을 만들고, 이 계정의 모든 쿼리 권한을 박탈하고, 오로지 저장 프로시저만 호출할 수 있도록 한정하면, Api 계정 정보가 유출되어도 파괴적인 쿼리 공격을 예방할 수 있습니다.

저장 프로시저는 Transaction으로 선언이 가능하기에, 연결에 문제가 생겨도 안전합니다.

ORM을 쓰지 않는 경우, 쿼리를 코드에서 작성하나, 데이터베이스에서 작성하나 작성하는 것은 똑 같이 한번이라, 코드량이 늘어나지도 않습니다.

2개의 좋아요

저장 프로시저에 대해 개인적인 반대의견을 댓글로 달아 봅니다.

저는 저장 프로시저는 사용하지 않는 것을 주장하는데요 이유는 다음과 같습니다.

  1. 성능 적인 부분은 저장 프로시저나 일반 쿼리 실행이나 큰 차이는 없습니다.
    기본적으로 동일한 쿼리와 동일한 인덱스를 타는 조건이라면 캐싱 처리 되어
    쿼리 구문을 다시 분석하지 않기 때문에 저장 프로시저 호출과 비슷하게 성능 제약은 없습니다.

  2. 저장 프로시저는 형상 관리가 어렵습니다.
    저장 프로시저를 별도의 파일로 형상 관리 하지 않는 이상
    내용 변경 이력 관리가 어려워 이러한 모습을 볼 수 있을 가능성이 있습니다.
    [저장 프로시저]
    xxx_select_01
    xxx_select_01_02
    xxx_select_01_02_최종
    물론 회바회로 어떻게 관리하느냐에 따라 다를 수 있습니다.

  3. ORM을 사용한다면 더욱이 저장 프로시저를 사용 할 이유는 없습니다.
    저장 프로시저를 사용하게 되면 비지니스 로직이 저장 프로시저안에 포함될 가능성이 매우 높습니다.

    이렇게 되면 특정 문제가 발생 되었을때 DB의 저장 프로시저 부분이 문제인지 프로그램 코드의 오류인지 확인이 어렵고 제3자가 볼때는 더더욱 두개의 관리 부분을 다 확인해야 하는 문제가 있습니다.


    간혹 ‘저장 프로시저 부분만 수정하면 프로그램 업데이트 없이 간편하게 오류 패치가 되서 이점이 크다’ 라고 말씀하시는 분들도 계시는데

    그런 환경은 CI/CD 구축이 제대로 되어 있지 않다 라고 말하는 것과 동일하다고 생각합니다.

    CI/CD 가 제대로 되어 있다면 프로그램 수정 후 배포의 과정은 그렇게 귀찮거나 오래 걸리지 않을테니깐요.

참고로 저장 프로시저 수정만으로 무중단 업데이트가 가능하다는 말은 별개의 문제 입니다.

7개의 좋아요

저도 저장프로시저의 사용은 크게 좋아하는 편은 아닌데요

속도면에선 저장 프로시저가 더 빠르다고 공부(?) 했는데 아닌가보네요?

저장 프로시저는 @BigSquare 님이 말씀해주신대로 미리 실행계획을 만들어 놓고
같은 쿼리를 계속 실행하는 거라서 캐싱 전략도 좀 더 유연하게 사용하는 걸로 알았는데!!

만약 속도가 비슷하다면 저장프로시저를 써야 하는 목적은 뭘까요?

2개의 좋아요

좋은 의견감사합니다.

@aroooong 님의 주장에 대한 질문입니다.

  1. 캐싱의 효익은 쿼리에만 있고, 모든 쿼리는 캐싱의 효익을 누리는지요?

  2. 단순한 관리의 문제 아닐까요?
    아래는 누가 봐도 잘 못 관리하고 있는 전형적인 모습인 것 같습니다.

  1. ORM 과 저장 프로시저가 상호 대체적이었으나 지금도 그렇다고 볼 수 있을까요?

  2. 저장 프로시저는 로직을 포함할 수 있지만, 코드와 협업 할 경우, 로직을 저장 프로시저(데이터 레이어)에 포함시키는 것은 안티 패턴 아닌지요?

뷰모델을 뷰의 비하인드 파일에 적어 놓고, MVVM 의 문제라고 말하는 것과 같지 않을까요?

2개의 좋아요

캐싱 처리되면 일반 쿼리도 저장 프로시저에 비해서 속도가 느리진 않습니다.

저장 프로시저는 개발자가 프로그램상 데이터 조회, 데이터 가공, 비즈니스 로직 처리 목적이 아닌

DBA 가 DB 관리 목적의 데드락 테이블 조회 등 관리 쿼리 집합의 저장 프로시저
데이터 분석가가 데이터 통계 용도의 저장 프로시저
이런 목적으로 간편하게 사용하는 용도가 적합하다고 생각합니다.


아, 물론 테이블 관계가 복잡하다던지 추출 대상의 데이터 내용 복잡해서
쿼리 작성이 힘들어서 저장 프로시저를 사용할 수 도 있습니다.

하지만 그런 경우 복잡하게 얽힌 DB의 구조에 문제가 있는지 정규화 대상의 시점이 온건지 먼저 검토 해봐야하지 않을까 합니다.
고칠 수 없는 복잡한 구조 때문에 저장 프로시저가 필수라면 더 이상 할 말은 없습니다. ^^

5개의 좋아요
  1. 캐싱의 효익은 쿼리에만 있고, 모든 쿼리는 캐싱의 효익을 누리는지요?
    → MSSQL 기준, 모든 쿼리는 실행되기 전에 쿼리 계획이 만들어 집니다. 쿼리 계획이 만들어 지는 비용이 큰 경우 해당 쿼리는 '느리다’라고도 말 할 수 있습니다.

    최초 실행 된 쿼리는 성능 향상을 위해 쿼리 계획을 캐시 테이블에 별도로 관리 합니다.

    또한 자주 사용되는 쿼리는 더 오랜 기간동안 캐시가 유지 됩니다.

    이후 대/소문자 포함, 공백 포함 등 쿼리 구문이 같다면 캐시된 계획을 사용하기 때문에 분석 단계를 하지 않고 바로 실행 되기에 저장 프로시저와 비교해서 속도가 느리지 않습니다.



    이 과정은 저장 프로시저도 동일 합니다. 저장 프로시저도 마찬가지로 최초 실행될때 실행 계획이 분석되어 캐싱 처리 되는데 저장 프로시저는 보통 대/소문자 공백 등 쿼리가 변경될 가능성이 적기 때문에 가급적 캐시를 사용하게 되므로 더 나은 성능이라고 볼 수 있을 수 도 있지만,
    마찬가지로 저장 프로시저 또한 변경이 자주 일어 난다면 최초 실행되는 일반 쿼리 성능과 동일하다고 볼 수 있습니다.

    물론 미세하게나마 빠른 성능이 있을 순 있겠지만 의미 없는 차이라고 생각합니다.

  2. 단순한 관리의 문제 아닐까요?
    → 예시를 든 구문에만 꽂히신든 합니다.

    제가 말하고 싶은 것은 ‘형상 관리가 어렵다’ 입니다.
    따로 저장 프로시저만 형상관리를 하게 된다면 그 또한 관리 포인트가 늘어 난다는 점입니다.


    ※ 참고로 제가 경험이 많진 않지만 중.소 / 중견 기업에 이직 해본 단순 저의 경험으로 실제로 저렇게 관리 되는 회사가 적지 않았습니다.^^

  3. ORM 과 저장 프로시저가 상호 대체적이었으나 지금도 그렇다고 볼 수 있을까요?
    → ORM과 저장 프로시저가 상호 대체적 이었다는 말이 공감 되지 않습니다. 단편적으로 판단될게 아닌 듯 합니다.

  4. 저장 프로시저는 로직을 포함할 수 있지만, 코드와 협업 할 경우, 로직을 저장 프로시저(데이터 레이어)에 포함시키는 것은 안티 패턴 아닌지요?
    → 질문 의도를 제가 이해를 잘 못했습니다. 저장 프로시저를 사용할 경우 로직이 저장 프로시저에 포함될 가능성이 있기에 그 가능성을 열어두지 말자 입니다.

저장 프로시저가 관리 및 성능에 있어 만능 이라면 모든 데이터 조작은 모두 저장 프로시저로 사용 해야 되는거 아닐까요 ?
그런데 그렇지 않고, 보편적으로 저장 프로시저를 사용하는 이유는 마수리님 저의 답변 글 처럼 ‘복잡해서, 어쩔 수 없는 환경’ 때문에 사용 되어지고 있습니다.

3개의 좋아요

경험에 기반한 설명 감사합니다.

만능까지는 아니어도, 저장 프로시저를 선택하는 것에 대한 이점을 나열한 것이고, @aroooong 님에 의해 부정당한 것이구요. ^^.

저장 프로시저의 성능과 관련해서 캐싱 때문에 가시적으로 좋다고 할수는 없고, 관리의 문제도 있다는 취지로 받아들이겠습니다.

혹시나, 시간이 되신다면 안전성과 보안과 관련해서도 (반대)의견 주시면 감사하겠습니다.

2개의 좋아요

이미 원본 글 질문은 채택되어 해결 되었고, 질문과 관련 없는 부차적인 토론으로 계속 이어 나가는건 안좋은 것 같습니다.


마지막 토론으로 간단하게 말씀 드리면

단일 쿼리나 저장 프로시저나 같은 DB에서 실행 되니 권한 문제의 보안은 동등 하다고 봅니다.
권한에 취약점이 있다면 프로시저나 단일 쿼리나 모두 문제가 있겠지요.

다만 ORM을 이용하지 않고 단일 쿼리를 사용 하면서 동적 쿼리 조합 형태로 사용된다면 SQL 인젝션 취약점 등은 별도로 신경 써야 하겠지요.

4개의 좋아요

Procedure vs EF를 비교할때 DB 실행계획및 유지보수성에서
상대적이긴 하지만 Procedure 가 유리하다는것이 그동안의 중론이었습니다.

EF에 경우 10개 데이타를 위해 100개를 가져온다는 느낌때문에 고성능에서는 안좋다는
인식이 사실입니다.

하지만 개인적인 개발경험으로 비추어볼때

EF 는 발전하고 6.0 부터 실행 쿼리에 대해서 LOG 확인이 가능해졌습니다.
즉 ORM 쿼리에 대해서 개발자가 인지하고 확인 해서
불필요하거나 문제있는 LINQ쿼리에 대해서 확인 수정이 가능해졌습니다.

이건 기능적인 문제이고 실무에서 사용할때 둘중 어느방법이 맞다는것의 문제는

Code First, DB First 일때 달라진다고 생각합니다.

Code First 에 경우 처음 개발부터 DB 스키마에 대해서 관리를 가능하고 Shema를
EF 가장 맞게 설계 가능합니다. 이럴경우 EF 가 유리하고

DB First 에 경우 기존 Asis 에 DB가 먼저 구축 된 Regacy 의 경우 Dapper를 이용한 Procedure
사용이 유리하다고 생각합니다.

개인적으로 요즘 HW 성능이 좋아져서 EF를 주로 사용합니다.
그리고 치명적으로 EF는 다른 DB랑 Join이 안되는 문제가 있어(어떻게 하는 방법은 있다지만)
복잡한 Business 가 들어간 로직에 경우 Procedure를 활용해야 한다고 봅니다.

아마도 대부분 Hybid 방식으로 (EF,DAPPER) 사용하시는경우가 많을텐데
뭐가 옮다는것 없는것 같고 상황에 맞게 써야 된다고 봅니다.

하지만 EF 유지보수성과 사용성 이 더 장점이 많다고 생각합니다.

개인적으로 RDB는 점점 Repository 다순 저장 개념으로 가는것 같습니다. 그래야
다양한 DB 메이커 Flexible 하게 사용가능하니까요 요즘 외래키 잘안걸지 않나요??

4개의 좋아요