12. 실무에서 프로시저

Last updated - 2023년 04월 24일 Edit Source

    유튜버 쉬운코드 님의 데이터베이스 강의를 정리한 내용


    # 실무에서 프로시저

    실무에서 프로시저를 사용한다는 것은 권장되지 않는다. 왜 그럴까?

    # 3-tier architecture

    최근 실무에서는 client-server architecture의 한 종류인 3-tier architecture 모델로 서비스를 개발함


    Logic tier

    • 비즈니스 로직이란?
      • ex) 당근마켓의 비즈니스 로직
      • 회원 가입 / 탈퇴
      • 상품 리스트업 알고리즘
      • 상품 정보 업로드 기능
      • 상품 검색 기능
      • 메시지 기능
      • etc …

    Data tier

    • 데이터?
      • ex) 당근마켓의 데이터
      • 회원 정보
      • 상품 정보
      • 판매 / 구매 내역
      • 지역 정보
      • etc …

    • 즉, stored procedure를 사용한다는 것은 data tier에 비즈니스 로직이 생기게 된다는 의미이다.
    • data tier에 비즈니스 로직이 생기게 된다는 것은 어떤 장/단점이 있을까 ??



    # 프로시저 장점

    stored procedure 장점

    • Application에 투명(transparent)하게 동작할 수 있다.
    • Network traffic을 줄여서 응답 속도를 향상시킬 수 있다.
    • 여러 서비스에서 재사용 가능하다.
    • 민감항 정보에 대한 접근을 제한할 수 있다.



    # transparent

    ex) stored procedure를 사용하지 않고 Logic tier에서만 비즈니스 로직을 관리한다고 생각해보자.

    • 비즈니스 로직을 수정할 일이 생겼고, 현재 서버는 트래픽을 받고 있는 상황이다.
    • 이제 배포해야하니까 컴파일시키고 배포파일 만든 이후에 기존의 인스턴스는 내리고 새로운 인스턴스를 띄워야 한다.
      • 하지만, 동시에 모두 서버 애플리케이션을 껐다 키면 안된다. 트래픽을 받고 있는 상황이라 바꿔주는 동안 트래픽을 처리할 수 없다.
      • 따라서, 나눠서 처리해야한다.
    • 하나 바꾸고 재가동, 하나 바꾸고 재가동… 비즈니스 로직을 수정할 일이 있을 때마다, 컴파일 새로하고, 빌드해서 배포 파일 만들고, 한대 한대씩 재가동 하는 것은 귀찮아 보인다.

    ex) 하지만, 이 비즈니스 로직이 stored procedure를 이용하여 관리된다면 어떻게 될까?

    • Logic tier에서는 프로시저를 호출만 하고 있으니까, 서버 애플리케이션 쪽은 바꿀 필요 없음
    • Data tier에 프로시저만 쏙 바꾸면 되는거다.

    transparent 하다는 의미는, 뭔가를 바꿔도 바뀌기 전에 사용하고 있던 부분들은 바꾸지 않고도 내용을 바꿀 수 있다는 의미이다. 따라서, stored procedure는 application에 대해서 transparent 할 수 있다는 장점이 있는 것이다.



    # 응답속도 감소

    ex) stored procedure를 사용하지 않고 Logic tier에서만 비즈니스 로직을 관리한다고 생각해보자.

    • 스프링 서버와 DB 서버는 다른 서버이기 때문에 쿼리문마다 호출해야 한다.
    • 요청을 보내는 순간 네트워크 트래픽이 발생

    ex) 하지만, 이 비즈니스 로직이 stored procedure를 이용하여 관리된다면 어떻게 될까?

    • 어차피 비즈니스 로직이 DB 서버에서 처리되기 때문에 프로시저를 호출만 하면 된다.
    • 네트워크 트래픽이 한 번만 왔다갔다 하면 된다.
    • 따라서, Network traffic을 줄여서 응답 속도를 향상시킬 수 있다는 장점이 있다.



    # 재사용 가능

    ex) DB에 저장되어있는 data를 이용하는 서비스가 3개 있다고 하자.

    • 각 서비스는 Java, Python, Javascript 각각으로 비즈니스 로직을 구현해야함

    • stored procedure를 쓰면 여러 서비스에서 재사용 가능하다는 장점이 있다.



    # 정보 제한

    ex) 회사 내의 개발자나 임직원이 DB에 접근하는 것을 막는 경우

    • 예를 들어, 사용자의 주민등록번호, 신용카드 정보 등등 민감한 정보에 접근을 막는 경우
    • 하지만, 개발자가 개발은 해야하는 상황

    • 개발자가 프로시저에 접근하는 것은 허용함으로써, 직접적인 접근은 막고 비즈니스 로직은 구현할 수 있도록 해주는 것이 stored procedure의 장점!!



    # 프로시저 단점

    stored procedure 단점

    • 유지 관리 보수 비용이 커진다.
    • DB 서버를 추가하는 것은 간단한 작업이 아님
      • DB 서버의 CPU 사용량이나 메모리 사용량이 늘어나게 되고, 트래픽이 폭발적으로 증가한 유사시에 긴급하게 대응이 힘듦
    • stored procedure가 언제나 transparent 인 것은 아님
    • stored procedure가 transparent 하다고 무조건 좋은 것도 아님
    • 재사용이 가능하다는 것은 양날의 검이 될 수도 있다.
    • stored procedure가 민감한 정보에 대하여 접근을 완벽히 제한할 수 없음
      • 또, DB 혹은 테이블 접근을 막으면 개발 및 CS 업무의 신속함이 떨어짐
      • CS 업무는 Customer Service를 뜻함



    # 유지보수 힘듦

    ex) Logic tier에도 비즈니스 로직, Data tier에도 비즈니스 로직이 있는 경우

    • Logic tier 봤다가~ Data tier 봤다가~ 왔다갔다 힘듦
    • 소스 코드의 버전 관리도 해야하고, 프로시저의 버전 관리도 해야함
    • 원래는 소스코드만 관리하면 되니까, 여기에서는 Java만 알면 되는데, 프로시저의 문법도 알아야함
    • 만약, 신규 기능 개발시 이에 대한 비즈니스 로직을 프로시저로 개발한다고 하자.
      • 프로시저쪽 코드도 수정
      • 애플리케이션쪽에 호출하는 소스코드도 수정
      • 컴파일, 배포 등 다시 다해야함
    • 따라서, 유지 관리 보수 비용이 커진다는 단점 발생



    # DB서버 추가

    ex) Presentation tier에서 온 트래픽 증가 시 DB 서버 추가하는 경우

    • Logic tier 서버의 CPU 사용량보다 Data tier의 DB 서버 CPU 사용량이 훨씬 많을 것

    • 이런 상황에서 Traffic이 갑자기 폭발적으로 증가하면?
    • 프로시저를 통해 비즈니스 로직을 다 가지고 있으니까 DB 서버 하나로 감당하기 힘들 것

    • RDBMS에 부하가 몰려서 신규 DB 서버를 추가했다고 하자.
    • 추가해봤자, 바로 해결이 안된다. 데이터는 기존 서버에만 있고 새로운 서버에는 똑같이 데이터를 복제해줘야 하는데… 언제 데이터를 전부 복사하겠나?
    • 비즈니스 로직을 프로시저를 통해서 RDBMS에 두게 된다면, DB 서버의 CPU 사용량이나 메모리 사용량이 늘어나게 되고, 트래픽이 폭발적으로 증가한 유사시에 긴급하게 대응이 불가능하게 된다. DB 서버를 추가하는 것은 간단하지 않다.

    # transparent 보장X

    ex) stored procedure의 이름을 바꾸는 상황이라고 하자

    • 이렇게 바로 이름을 바꿔버리면? 기존에 애플리케이션 서버에서 호출하던 프로시저의 이름과 다르기 때문에 바로 서비스에 문제가 생긴다.

    • 이렇게 이름 바꿀 프로시저를 새로 만들고 기존에 애플리케이션 서버에서 호출하던 프로시저의 이름을 하나 바꾸고 재가동, 하나 바꾸고 재가동, … 이 짓을 반복한다.
    • 마지막으로 기존의 프로시저를 삭제하는 것이다.
    • 오히려, transparent 하기는 커녕, 소스 코드에 로직이 있는 경우보다 더 손이 많이 갈 수 있는 단점이 있다.



    # transparent 항상좋음?

    ex) stored procedure의 body 부분만 바꾸는 상황이라고 하자

    • body 부분만 바꿔서 번거롭게 애플리케이션 서버의 프로시저 호출 부분을 바꾸지 않고 transparent하게 변경할 수 있다.
    • 그런데, 바뀐 부분에 예상치 못한 버그가 생겨서 난리가 나게 되었다.
    • 다시 이전으로 롤백한다고 하더라도, 버그가 있는 프로시저가 동작하고 있었던 동안에 이와 관련된 모든 트래픽들은 안좋은 영향을 받았을 것이다.



    # 양날의 검 재사용

    ex) 하나의 서비스에서 요청하는 트래픽이 폭발적으로 증가한다고 하자.

    • 스프링 쪽 서비스 A에서 폭발적으로 요청한다면 나머지 다른 서비스도 영향을 받게 됨
    • 이렇게, 여러 서비스가 동시에 DBMS의 프로시저를 사용하게 되면, 통제되지 않는 사용으로 모두에게 문제가 발생할 수 있게 된다. stored procedure를 재사용 가능하다는 것은 양날의 검이 되는 것이다.

    • 그래서 이런 식으로 아키텍처를 가져가는 것이 좋다.
    • DB의 앞단에 데이터를 관리하는 서비스를 하나 만든다.
      • 실제 서비스들은 Data Service를 통해 원하는 로직을 사용할 수 있도록 한다.
      • Data Service는 Restful API 같은 것을 통하여 인터페이스를 제공해야 한다.
      • 각각의 서비스들은 API를 호출하는 형태로 사용하는 것이다.
    • 이런 상황에서 Service A의 트래픽이 폭발적으로 증가하면, Data Service 쪽에서 Service A에 해당하는 호출만 막으면 된다.
      • 이렇게 하면 Service B와 Service C는 문제가 없게 된다.

    그런데, 이렇게 하면 Data Service 쪽에서는 고민이 된다.

    • 프로시저를 서비스 A, B, C에서 재사용하면서 사용하는 것이 아니라 Data Service에서만 사용하기 때문이다.

    • 그래서 Data Service 쪽을 관리하는 사람은 그냥 프로시저를 쓰지 말고 소스코드로 관리하자는 쪽으로 가게 되는 것이다.



    # 완벽한 정보제한 불가

     사실 위에서는 간접적으로 정보에 접근하도록 하여 민감한 정보를 감췄다고는 하지만..

    • 이렇게 return 값을 받아버리면 적어도, 개발자들은 민감한 정보에 대한 접근이 가능해진다.

    • 또, 이렇게 DB 혹은 테이블 접근을 막으면 개발 및 CS (Customer Service) 업무의 신속함이 떨어진다.

    그래서, 사실 보안과 관련된 부분은 아래와 같이 하는 것이 좋다.

    • 담당자나 개발자에게만 DB 혹은 테이블 권한을 부여하자
    • 민감한 정보는 암호화해서 저장하자
    • 보안서약서 등을 통해 정책적으로 보안을 강화하자



    # 이외의 단점

    • procedure로는 복잡하고 유연한 코드를 작성하기 어렵다.
    • 오늘날의 프로그래밍 언어는 훨씬 다양하고 강력한 기능들을 제공한다.
      • 굳이 프로시저를??
    • procedure는 가독성이 떨어진다.
    • procedure는 디버깅이 어렵다.



    # Logic tier 장점

    그렇다면, 프로시저를 쓰지 않고 Logic tier에서 비즈니스 로직을 관리하는 방식은 어떤 면에서 좋다는 말일까? 사실 프로시저의 장점에서 언급했던 것을 로직 티어에서 관리하면 더 좋게 해결할 수도 있다.

    • 트래픽이 증가했을 때, 서버 추가가 쉽다.
    • 하나씩 재가동하는 불편한 방법이, 버그 발생에 관한 이점을 가져온다.
    • 응답속도 향상은 사실 가능하다.



    # 서버추가 쉬움

    프로시저의 단점에서 DB서버 추가가 힘들다는 것이 있었는데, Logic tier에서는 애플리케이션 서버 투입이 간단하다.

    • 애초에 트래픽을 분산받아서 사용하기 떄문에 좀 더 좋은 상황

    • 최근은 클라우드가 잘 되어있어서 오토 스케일링(auto scaling) 같은거 이용하면 애플리케이션 서버 추가하는 것은 매우 쉽다.
    • Logic tier에 애플리케이션 서버를 투입하는 것은 간단하다. 데이터를 가지고 있지 않기에 그냥 추가하면 된다. 따라서, CPU 혹은 메모리 부하를 쉽게 분산시킬 수 있다.



    # 버그 피해 최소화

    프로시저의 단점에서 transparent가 항상 좋은 것이냐는 것이 있었는데, Logic tier에서의 하나하나 재가동 하는 부분 덕에 오히려 좋은 점도 있다.

    • 하나 하나 재가동 해야하니까, 하나 바꾸고 모니터링 하고 있는다.

    • 이렇게 버그가 발생한걸 발견하면, 간헐적으로 문제가 발생했다는 것을 확인하니까 빠르게 이전 버전으로 롤백할 수 있다.
    • 물론, 이 순간에 이 서버로 들어온 트래픽은 안좋은 영향을 받았을 것이다.
      • 하지만 stored procedure 때는 온전히 모든 서버가 안좋은 영향을 받았다면,
      • 이번에는 4분의 1에 해당하는 서버만 안좋은 영향을 받았을 것이다. 그나마 훨씬 낫다.
    • 이렇게 애플리케이션 서버를 통해 배포를 매번 하는 것은 번거롭기는 해도 예상치 못한 버그의 영향을 최소화 할 수 있다.



    # 응답 속도 감소

    프로시저의 장점에서 응답속도 감소를 말할 때, Logic tier에 비즈니스 로직을 둔다면 응답속도가 느리다고 했는데, 사실 Logic tier에 비즈니스 로직을 두고도 응답 속도를 향상시킬 수 있다.

    • 각각의 쿼리문 (select, insert, update)이 매번 요청을 보내서 응답속도에 문제가 있다고 했었다.
    • 그렇다면 만약에, insert와 update를 동시에 한다면?

    • 스레드 풀(Thread Pool)을 사용하던 Non-blocking IO를 사용하던 동시에 DB서버로 요청을 보낸다.
    • 순차적으로 요청할 필요가 없는 경우라면, ( 동시에 진행이 가능한 경우라면 ) 동시에 호출하여 응답속도를 향상시킬 수 있다.

    ex) 그런데, 예를 들어 순차적으로 요청해야 하는 경우라면 어떻게 응답 속도를 향상시킬까?

    • select문 A와 B는 반드시 순차적으로 실행되어야 하는 상황이라고 하자.
    • 이 경우에는 어떻게 응답 속도를 향상시킬까?

    • 이렇게 캐시(cache)를 사용한다. 여기서 사용된 캐시는 redis이다.
      • 소스코드에 캐시 관련 로직도 추가한다.
      • 캐시가 추가되면서 타임라인에도 변화가 생긴다.
    • getPoint(int id)라는 로직은 id를 받으면 그 id의 포인트를 가져오는 로직이다.
      1. getFromCache(id)는 id에 대한 포인트가 캐시에 있는지 먼저 확인
      2. 초기에는 당연히 캐시에 아무것도 없기 때문에 return point if not null 수행하지 않고 밑으로 코드 실행
      3. 2번의 select문 수행 이후 계산하여 얻은 포인트를 캐시에 넣는다.
        • redis는 key-value 형태로 데이터를 저장함
        • 얼마동안 캐시에 저장할 것인지 life time도 저장함. 여기서는 60초라고 해놨음
      4. 이후 계산한 포인트를 반환
    • 당장은 네트워크를 좀 더 타게 되어서 복잡해진 것처럼 보임. 하지만..?

    • 같은 id에 대해서는 캐시에 있는 동안 한 번만 왔다갔다 하니까 응답 속도가 향상됨!!
    • 이런식으로 비즈니스 로직을 소스코드에 두고도, 캐시를 사용하면 응답 속도를 향상시키면서 DB 부하까지고 줄이는 엄청난 효과를 가져온다. 실무에서 정말 많이 사용하는 패턴

    Comment