반응형

목차

    PHP와 Node.js 바로 알기

    PHP(Hypertext Preprocessor)는 C언어와 유사한 문법으로 비교적 쉽게 배울 수 있어 진입장벽이 낮은 서버 사이드 언어에 속합니다. 상대적으로 높은 점유율과 풍부한 레퍼런스들로 인해 웹 개발을 처음 시작하는 초보 개발자들에게 적극적으로 채택되어왔습니다.Node.js가 등장하기 전 PHP는 JavaScript와 떼려야 뗄 수 없는 단짝이었습니다. 클라이언트 사이드 언어인 JavaScript는 브라우저의 디테일을, 서버사이드 언어인 PHP는 서버 수준의 동적인 작업 전반을 담당하고 있었기 때문입니다. 하지만 2009년 Ryan Dahl이 JavaScript를 활용해 서버 스택을 구축할 수 있는 Node.js를 고안한 이후 JavaScript와 PHP의 긴 협력의 역사가 마감됩니다.Node.js는 클라이언트 개발에만 국한해 활용되던 JavaScript로 서버 사이드 개발을 가능케 하는 런타임 환경입니다. Node.js는 Window, Linux, Mac OS에서 모두 실행이 가능하고, Node.js 내에 HTTP 서버 라이브러리를 포함하고 있기 때문에 WAS 없이는 동작할 수 없는 PHP와 달리 별도의 WAS 없이도 웹 서버에서 동작할 수 있습니다.Node.js의 등장으로 인해 JavaScript만으로 클라이언트와 서버단을 모두 개발할 수 있게 되었습니다. 추가적인 언어를 학습하지 않아도 JavaScript로 서버단을 개발할 수 있어 프런트엔드(Front-end) 개발자들에게는 Node.js는 더욱 중요한 의미를 지닙니다. PHP와 Node.js의 차이점을 구분하지 못하는 경우가 종종 있습니다. PHP와 Node.js를 보다 명확히 이해하기 위해 각각이 지닌 장점에 대해 정리해보겠습니다.


    PHP의 장점

    코드와 콘텐츠의 혼합

    HTML과 CSS를 활용해 웹사이트를 구축하는 와중에 PHP를 통해 특정 프로세스를 웹에 추가하거나, 데이터베이스에서 가져온 데이터를 웹상의 내용과 결합해 보여주는 것이 가능합니다. 이 경우 바로 PHP 스크립트를 열어 원하는 내용을 추가하기만 하면 됩니다.

    단단한 기반을 갖춘 언어

    워드프레스나 드루팔, 줌라와 같은 인기 CMS(콘텐츠 관리 시스템)들이 모두 웹 서버 구축에 PHP를 활용하고 있습니다. 또한 짧지 않은 역사로 인해 현존하는 대다수의 웹 서버에는 PHP 언어로 작성된 코드가 넘쳐납니다. 긴 역사로 인해 다양한 플러그인이 개발되었고, 오픈소스로 공개된 코드도 많다는 장점이 있습니다.

    진입장벽이 낮은 서버 사이드 언어

    PHP는 문법을 익히는 것이 어렵지 않아 진입장벽이 낮은 언어에 속합니다. 그 때문에 웹 개발을 처음 시작하는 입문자가 접근하기 쉽고 관련 레퍼런스 또한 어렵지 않게 찾을 수 있어 어렵지 않게 서버 개발을 할 수 있다는 장점이 있습니다.

    Node.js의 장점

    코드와 콘텐츠의 분리

    PHP와 달리 코드와 컨텐츠를 분리하는 점이 Node.js의 장점이 될 수 있습니다. 코드와 컨텐츠를 하나로 융합할 경우 완성도가 떨어지거나 복잡한 논리 구조로 전락할 가능성이 있습니다. 하지만 이 둘을 분리하는 경우 코드를 체계적으로 관리할 수 있어, 소스 코드를 직접 작성하지 않은 프로그래머도 쉽게 내용을 파악하고 유지/보수를 할 수 있습니다.

    Non-blocking I/O 처리 방식

    Node.js는 Non-blocking I/O(NIO) 처리 방식을 채택하고 있습니다. 이는 곧 한 개의 요청이 완료될 때까지 시스템이 기다릴 필요가 없음을 의미합니다. 서버 입장에서 NIO는 당연한 처리 방식일 수 있지만, 클라이언트 개발의 전유물이었던 JavaScript로 NIO 처리가 가능한 서버 개발을 할 수 있게 된 점은 그 자체로 의미가 있습니다.

    다양한 모듈 생태계와 활발한 커뮤니티

    Node.js 관련 패키지를 관리해주는 NPM(Node Package Manager)과 같은 모듈이 여럿 존재합니다. 따라서 모든 기능을 직접 개발할 필요 없이 패키지를 다운받아 사용할 수 있고, 이는 개발 과정을 훨씬 수월하게 만듭니다. 또한 활발한 커뮤니티 활동으로 개발 과정에서 발생할 수 있는 이슈를 해결하고, 다른 개발자들의 지원을 받는 것이 용이합니다.


    Node.js는 파일을 업로드하거나 스트리밍하는 애플리케이션, 많은 양의 데이터가 오고 가는 채팅이나 게임 애플리케이션에 적합한 플랫폼으로 손꼽힙니다. 하지만 복잡한 컴퓨팅이 필요하거나 성능이 무거운 애플리케이션에는 Node.js를 채택하지 않는 것이 바람직합니다. 그 이유는 Node.js의 단일 스레드(Single Thread)가 많은 컴퓨팅을 요하는 웹 서비스에 적합하지 않기 때문입니다. 또한 서버단의 로직이 복잡한 경우 콜백 함수의 늪에 빠질 수 있어 서버 체크로직이 많은 경우에도 적합하지 않습니다.

    미항공우주국 NASA를 비롯해 넷플릭스나 링크드인, 우버와 같은 글로벌 기업들조차도 적극적으로 Node.js를 도입해 활용하고 있습니다. 또한 가비아의 하이웍스 메신저 서버 또한 Node.js로 개발/운영되고 있습니다. 하이웍스 메신저의 동시 접속자 수가 6만 명에 육박하는 것을 고려하면 Node.js로 충분히 안정적인 서비스를 운영할 수 있음을 알 수 있습니다.
    JavaScript가 익숙한 개발자들에게 Node.js는 개발 가능한 범위를 넓혀줬다는 점에서 그리고 활발한 커뮤니티 활동으로 지속해서 고도화를 거듭하고 있다는 점에서 앞으로도 그 인기는 쉬이 식지 않을 것으로 보입니다.

    서비스하고자 하는 애플리케이션이 Node.js를 도입하기에 적합한 경우라면 간단한 채팅 서버 개발부터 시작해볼 수 있습니다.

    반응형
    반응형

    목차

      인덱스(Index) 란?

      인덱스는 데이터베이스 테이블에 대한 검색 성능의 속도를 높여주는 자료구조이다. 만약 인덱스를 타게 되면 먼저 인덱스에 저장 되어있는 데이터의 물리적 주소로 가서 데이터를 가져오는 식으로 동작하여 검색 속도의 향상을 가져올 수 있다.

      예시

      만약 다음과 같은 테이블이 있고 내가 이름(Data)가 SMITH라는 사람을 조회(Select) 하고자 한다면 full scan 작업이 필요하다.

      쿼리문

      더보기
      SELECT *
      FROM TABLE
      WHERE 1=1
      AND Data = 'SMITH'
      ;

      만약 인덱스 처리를 하면 다음과 같이 처리 할 수 있다. 마치 책에 있는 목차라고 생각하면 된다. 

      실제 DB 관련 작업을 할 때 대부분의 속도 저하는 바로 select문 특히 조건 검색 where절에서 발생하는데 가장 먼저 생각해 볼 수 있는 대안으로 Index를 생각할 수 있기도 하고, SQL 튜닝에서도 Index와 관련된 문제사항과 해결책이 많기 때문이다.

      인덱스(Index)를 사용하는 이유 : 조건 검색 Where 절의 효율성

      인덱스의 가장 큰 특징은 데이터들이 정렬이 되어있다는 점이다. 이 특징으로 조건 검색이라는 영역이 굉장히 장점이 된다. 테이블을 만들고 안에 데이터가 쌓이게 되면 테이블의 레코드는 내부적으로 순서가 없이 뒤죽박죽 저장된다. 하지만 인덱스 테이블은 데이터들이 정렬되어 있기 때문에 해당조건 where에 맞는 데이터들을 빠르게 찾아낼 수 있다. 위의 Index 테이블에서 SMITH 부분은 정렬이 되어있다.

      인덱스(Index)를 사용하는 이유 : 정렬 Order by 절의 효율성

      인덱스(Index)를 사용하면 Order by에 의한 Sort 과정을 피할 수 있다. Order by는 굉장히 부하가 많이 걸리는 작업이다. 정렬과 동시에 1차적으로 메모리에서 정렬이 이루어지고 메모리보다 큰 작업이 필요하다면 디스크 I/O도 추가적으로 발생된다. 하지만 인덱스를 사용하면 이러한 전반적인 자원의 소모를 하지 않아도 된다. 이미 정렬 되어 있기 때문에 가져오기만 하면 된다.

      인덱스(Index)를 사용하는 이유 : MIN ,MAX의 효율적인 처리가 가능하다.

      이것 또한 데이터가 정렬되어 있기에 얻을 수 있는 장점입니다. MIN값과 MAX값을 레코드의 시작값과 끝 값 한건씩만 가져오면 되기에 FULL TABLE SCAN 할 필요없다.

       

      인덱스의 단점

      인덱스가 주는 혜택이 있으면 그에 따른 부작용도 있습니다. 인덱스의 가장 큰 문제점은 정렬된 상태를 계속 유지 시켜줘야 한다는 점입니다. 그렇기에 레코드 내에 데이터값이 바뀌는 부분이라면 악영향을 미칩니다. INSERT, UPDATE, DELETE를 통해 데이터가 추가되거나 값이 바뀐다면 INDEX 테이블 내에 있는 값들을 다시 정렬을 해야겠죠. 그리고 INDEX 테이블, 원본 테이블 이렇게 두 군데에 데이터 수정 작업해줘야 한다는 단점도 있습니다.

       

      그리고 검색시에도 인덱스가 무조건 좋은 것이 아닙니다. 인덱스는 테이블의 전체 데이터 중에서 10~15% 이하의 데이터를 처리하는 경우에만 효율적이고 그 이상의 데이터를 처리할 땐 인덱스를 사용하지 않는 것이 더 낫습니다. 그리고 인덱스를 관리하기 위해서는 데이터베이스의 약 10%에 해당하는 저장공간이 추가로 필요합니다. 무턱대고 INDEX를 만들어서는 결코 안 될 말입니다. 

      인덱스(Index)의 관리

      앞서 설명했듯이 인덱스는 항상 최신의 데이터를 정렬된 상태로 유지해야 원하는 값을 빠르게 탐색할 수 있습니다. 그렇기 때문에 인덱스가 적용된 컬럼에 INSERT, UPDATE, DELETE가 수행된다면 계속 정렬을 해주어야 하고 그에 따른 부하가 발생합니다. 이런 부하를 최소화하기 위해 인덱스는 데이터 삭제라는 개념에서 인덱스를 사용하지 않는다 라는 작업으로 이를 대신합니다.

      • INSERT: 새로운 데이터에 대한 인덱스를 추가합니다.
      • DELETE: 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업을 진행합니다.
      • UPDATE: 기존의 인덱스를 사용하지 않음 처리하고, 갱신된 데이터에 대해 인덱스를 추가합니다.

      인덱스 생성 전략

      생성된 인덱스를 가장 효율적으로 사용하려면 데이터의 분포도는 최대한으로 그리고 조건절에 호출 빈도는 자주 사용되는 컬럼을 인덱스로 생성하는 것이 좋습니다. 인덱스는 특정 컬럼을 기준으로 생성하고 기준이 된 컬럼으로 정렬된 Index 테이블이 생성됩니다. 이 기준 컬럼은 최대한 중복이 되지 않는 값이 좋습니다. 가장 최선은 PK로 인덱스를 거는것이겠죠. 중복된 값이 없는 인덱스 테이블이 최적의 효율을 발생시키겠고. 반대로 모든 값이 같은 컬럼이 인덱스 컬럼이 된다면 인덱스로써의 가치가 없다고 봐야 할 것입니다.

       

      1. 조건절에 자주 등장하는 컬럼

      2. 항상 = 으로 비교되는 컬럼

      3. 중복되는 데이터가 최소한인 컬럼 (분포도가 좋은) 컬럼

      4. ORDER BY 절에서 자주 사용되는 컬럼

      5. 조인 조건으로 자주 사용되는 컬럼

      B * Tree 인덱스

      인덱스에는 여러가지 유형이 있지만 그 중에서도 가장 많이 사용하는 인덱스의 구조는 밸런스드 트리 인덱스 구조입니다. 그리고 B TREE 인덱스 중에서도 가장 많이 사용하는것은 B*TREE 와 B+TREE 구조를 가장 많이 사용되는 인덱스의 구조입니다.

      B * Tree 인덱스는 대부분의 DBMS 그리고 오라클에서 특히 중점적으로 사용하고 있는 가장 보편적인 인덱스입니다. 구조는 위와 같이 Root(기준) / Branch(중간) / Leaf(말단) Node로 구성됩니다. 특정 컬럼에 인덱스를 생성하는 순간 컬럼의 값들을 정렬하는데, 정렬한 순서가 중간 쯤 되는 데이터를 뿌리에 해당하는 ROOT 블록으로 지정하고 ROOT 블록을 기준으로 가지가 되는 BRANCH블록을 정의하며 마지막으로 잎에 해당하는 LEAF 블록에 인덱스의 키가 되는 데이터와 데이터의 물리적 주소 정보인 ROWID를 저장합니다.

       

      인덱스 사용 예시

      인덱스 생성

      --문법
      CREATE INDEX [인덱스명] ON [테이블명](컬럼1, 컬럼2, 컬럼3.......)
      --예제
      CREATE INDEX EX_INDEX ON CUSTOMERS(NAME,ADDRESS); 
      
      --예제 컬럼 중복 X
      CREATE[UNIQUE] INDEX EX_INDEX ON CUSTOMERS(NAME,ADDRESS); 
      

      위와같이 쿼리문을 작성하면 INDEX를 생성할 수 있습니다. UNIQUE 키워드를 붙이면 컬럼값에 중복값을 허용하지 않는다는 뜻입니다.

      인덱스 조회

      SELECT * FROM USER_INDEXES WHERE TABLE_NAME = 'CUSTOMERS';
      

      인덱스를 생성하면 USER_INDEXES 시스템 뷰에서 조회할 수 있습니다. 방금 CUSTOMERS 테이블에 만들었던 EX_INDEX가 첫번째 ROW에 있군요.

       

      인덱스 삭제

      --문법
      DROP INDEX [인덱스 명]
      --예제
      DROP INDEX EX_INDEX;
      

      인덱스는 조회성능을 극대화하기 위해 만든 객체인데 너무 많이 만들면 insert, delete, update시에 부하가 발생해 전체적인 데이터베이스 성능을 저하합니다. 고로 안쓰는 인덱스는 삭제시키는것이 좋습니다.

       

      인덱스 리빌드

      인덱스를 리빌드하는 이유

      인덱스 파일은 생성 후 insert, update, delete등을 반복하다보면 성능이 저하됩니다. 생성된 인덱스는 트리구조를 가집니다. 삽입,수정,삭제등이 오랫동안 일어나다보면 트리의 한쪽이 무거워져 전체적으로 트리의 깊이가 깊어집니다. 이러한 현상으로 인해 인덱스의 검색속도가 떨어지므로 주기적으로 리빌딩하는 작업을 거치는것이 좋습니다.

       

      인덱스(Index)를 남발하지 말아야 하는 이유

      개발을 진행할때에 대개 개발서버와 운영서버를 나누어서 관리합니다. 대부분 개발서버에서 개발을 할때에는 적은량의 데이터를 가지고 로직검사를 하며 로직검사에 통과한 코드들이 운영서버에 업데이트가 되죠. 하지만 개발서버에는 잘 동작하던 로직들이 운영서버의 많은량의 데이터들을 처리하다보면 성능이슈가 많이 발생합니다. 그 성능이슈의 주요원인은 바로 데이터베이스에 있습니다. 데이터베이스 관리자는 성능문제가 발생하면 가장 빨리 생각하는 해결책이 인덱스 추가 생성입니다.

       

      문제를 쉽게 해결을 위해 쿼리 속도 문제가 날때마다 인덱스를 추가하는것은 바람직하지 못합니다. 성능 이슈가 나서 인덱스를 만들고 또 다른 SQL에서문에서 성능이슈가 발생하여 또 인덱스를 만들었다고 합시다. 이렇게 문제가 발생할때마다 인덱스를 생성하면서 인덱스가 계속 추가되면 생성된 인덱스를 참조하는 하나의 쿼리문을 빠르게는 만들 수 있지만 전체적인 데이터베이스의 성능 부하를 초래합니다. 그렇기에 인덱스를 생성하는것 보다는 SQL문을 좀 더 효율적으로 짜는 방향으로 나가야합니다. 인덱스생성은 꼭 마지막 수단으로 강구해야 할 문제입니다.

      정리

      인덱스(Index)는 데이터베이스 분야에 있어서 테이블에 대한 동작의 속도를 높여주는 자료 구조를 일컫는다. 인덱스는 테이블 내의 1개의 컬럼, 혹은 여러 개의 컬럼을 이용하여 생성될 수 있다. 고속의 검색 동작뿐만 아니라 레코드 접근과 관련 효율적인 순서 매김 동작에 대한 기초를 제공한다. 인덱스를 저장하는 데 필요한 디스크 공간은 보통 테이블을 저장하는 데 필요한 디스크 공간보다 작다. (왜냐하면 보통 인덱스는 키-필드만 갖고 있고, 테이블의 다른 세부 항목들은 갖고 있지 않기 때문이다.) 관계형 데이터베이스에서는 인덱스는 테이블 부분에 대한 하나의 사본이다.

      인덱스는 고유 제약 조건을 실현하기 위해서도 사용된다. 고유 인덱스는 중복된 항목이 등록되는 것을 금지하기 때문에 인덱스의 대상인 테이블에서 고유성이 보장된다.

      출처) 위키백과

      위의 내용을 정리하자면

      1. 테이블에 대한 검색의 속도를 높여주는 자료 구조입니다.
      2. 색인이고 메모리 영역의 일종의 목차를 생성하는 개념입니다.
      3. 따라서 이런 목차를 이용하여 검색 범위를 줄여 속도를 높일 수 있습니다.

      인덱스의 종류

      다음과 같이 정리할 수 있습니다!

      1. B(Balanced)-tree Index
      2. Bitmap Index
      3. IOT Index
      4. Clustered Index

      위와 같이 존재하며 주로 B-tree 구조로 사용된다고 합니다!


      왜 사용해야하나?

      위에서 말씀드렸듯이 검색의 속도를 높여주기 때문입니다. 근데 어떻게 검색의 속도를 높여주는것이며 어떻게 사용되는지 감이 안잡히기 때문에 이 내용에 대하여 설명해보겠습니다!

      예를 들어 오른쪽 테이블의 Physics값을 조회해본다고 가정해보겠습니다.
      해당 과정을 표현하면

      1. Select 절을 활용하여 조회
      2. 어느 위치에 데이터가 존재하는지 모르기 때문에 Table Full scan 진행

      이처럼 테이블의 전체 데이터를 조회하기 때문에 데이터의 수가 적은 테이블이면 영향이 덜하겠지만,

      만약 수십만개의 데이터가 들어있는 테이블의 데이터를 조회하는데 조회 기능이 자주 사용되는 서비스라면 성능이 굉장히 떨어지게 될것입니다!

      그렇기 때문에 왼쪽과 같이 인덱스를 따로 생성하여 해당 데이터만 빠르게 찾을 수 있게 됨으로써 다이나믹한 성능 향상을 기대할 수 있는 부분입니다!


      어떻게 동작하는것인가?

      위의 예시를 이어서 설명하겠습니다!

      1. 해당 테이블을 생성시 생성하고 싶은 인덱스 컬럼을 지정
      2. 생성 후 인덱스 조회 시, WHERE 절이 포함된 쿼리로 조회
      3. 인덱스로 저장된 Key-Value값을 참조해서 결과 출력

      위와 같이 진행되게 됩니다!

      다음과 같이 B-tree 알고리즘을 통하여 조회하게 되고, 리프노드로 도착하기 까지 자식 노드에 대한 포인터가 저장되어 있어 탐색에 있어서 한개의 경로만 조회하면 되기 때문에 조회에 있어서 굉장히 효율적인 알고리즘이라고 합니다!


      언제 사용해야하나?

      주로 검색 및 조회를 할때 큰 효율성을 낼 수 있다고 합니다!

      기본적으로 이진 트리를 사용하기 때문에 이미 정렬이 되어있는 상태에서 추가, 수정, 삭제가 자주 일어나게 되면 인덱스에서도 마찬가지로 해당 동작들이 수행되기 때문에 성능 저하를 초래할 수 있다고 합니다!

      예를 들어, 한 쇼핑몰에 여러가지 카테고리가 존재할때 해당 카테고리의 상품들을 조회할때 이러한 인덱스 기능을 잘 사용하게 된다면 큰 효율을 발휘하게 되지만, 인스타그램같은 소셜 서비스들은 끊임없이 게시글이 작성되고 수정, 삭제되기 때문에 오히려 인덱싱을 하게되면 엄청난 성능 저하가 되기 때문입니다!

      인덱스 선정 기준

      인덱스는 하나 혹은 여러 개의 컬럼에 대해 설정할 수 있습니다.
      단일 인덱스를 여러 개 생성할 수도, 여러 컬럼을 묶어 복합 인덱스를 설정할 수도 있습니다.

      그러나 무조건 많이 설정하는게 검색 속도 향상을 높여주지는 않습니다.
      인덱스는 데이터베이스 메모리를 사용하여 테이블 형태로 저장되므로 개수와 저장 공간은 비례합니다.
      따라서,

      • 조회시 자주 사용하고
      • 고유한 값 위주로

      인덱스를 설정하는게 좋습니다.

      그럼 어떤 컬럼에 인덱스를 설정하는게 좋을까?

      인덱스는 한 테이블당 보통 3~5개 정도가 적당합니다.
      물론 테이블의 목적 등에 따라 개수는 달라질 수 있습니다.

      인덱스는 컬럼을 정해서 설정하는 것이므로 후보 컬럼의 특징을 잘 파악해야 합니다.
      아래 4가지 기준을 사용하면 효율적으로 인덱스를 설정할 수 있습니다.

      • 카디널리티 (Cardinality)
      • 선택도 (Selectivity)
      • 활용도
      • 중복도

      카디널리티 (Cardinality)

      ✔️ 카디널리티가 높을 수록 인덱스 설정에 좋은 컬럼입니다.
      = 한 컬럼이 갖고 있는 값의 중복 정도가 낮을 수록 좋습니다.

      컬럼에 사용되는 값의 다양성 정도, 즉 중복 수치를 나타내는 지표입니다.
      후보 컬럼에 따라 상대적으로 중복 정도가 낮다, 혹은 높다로 표현됩니다.

      예를 들어, 10개 rows를 가지는 ‘학생’ 테이블에 ‘학번’과 ‘이름’ 컬럼이 있다고 해봅시다.

      • ‘학번’은 학생마다 부여 받으므로 10개 값 모두 고유합니다.
        • 중복 정도가 낮으므로 카디널리티가 낮습니다.
      • ‘이름’은 동명이인이 있을 수 있으니 1~10개 사이의 값을 가집니다.
        • 중복 정도가 ‘학번’에 비해 높으므로 카디널리티가 높다고 표현할 수 있습니다.

      면접 답변 : 고유한 값이 도출되는 것을 기반으로 인덱싱을 잡는 편 입니다. 예를들면 상품명이나 옵션보다는 상품번호, 주문번호, 배송번호 등 고유한 값에 인덱싱을 거는 편입니다.

      선택도 (Selectivity)

      ✔️ 선택도가 낮을 수록 인덱스 설정에 좋은 컬럼입니다.
      5~10% 정도가 적당합니다.

      데이터에서 특정 값을 얼마나 잘 선택할 수 있는지에 대한 지표입니다.
      선택도는 아래와 같이 계산합니다.

      = 컬럼의 특정 값의 row 수 / 테이블의 총 row 수 * 100
      = 컬럼의 값들의 평균 row 수 / 테이블의 총 row 수 * 100

      예를 들어, 10개 rows를 가지는 ‘학생’ 테이블에 ‘학번’, ‘이름’, ‘성별’ 컬럼이 있다고 해봅시다.
      학번은 고유하고, 이름은 2명씩 같고, 성별은 남녀 5:5 비율입니다.

      • ‘학번’의 선택도 = 1/10*100 = 10%
        • SELECT COUNT(1) FROM '학생' WHERE '학번' = 1; (모두 고유하므로 특정 값: 1)
      • ‘이름’의 선택도 = 2/10*100 = 20%
        • SELECT COUNT(1) FROM '학생' WHERE '이름' = "김철수"; (2명씩 같으므로 특정 값: 2)
      • ‘성별’의 선택도 = 5/10*100 = 50%
        • SELECT COUNT(1) FROM '학생' WHERE '성별' = F; (5명씩 같으므로 특정 값: 5)

      즉, 선택도는 특정 필드값을 지정했을 때 선택되는 레코드 수를 테이블 전체 레코드 수로 나눈 것입니다.

      즉 , 위의 예시에선 '학번' 정도를 index로 잡는 것이 좋다. 

      면접 답변 : 고유한 값이 도출되는 것을 기반으로 인덱싱을 잡는 편 입니다. 예를들면 상품명이나 옵션보다는 상품번호, 주문번호, 배송번호 등 고유한 값에 인덱싱을 거는 편입니다.

      활용도

      ✔️ 활용도가 높을 수록 인덱스 설정에 좋은 컬럼입니다.

      해당 컬럼이 실제 작업에서 얼마나 활용되는지에 대한 값입니다.
      수동 쿼리 조회, 로직과 서비스에서 쿼리를 날릴 때 WHERE 절에 자주 활용되는지를 판단하면 됩니다.

      면접 답변 : 저희 팀에서 자주 사용하는 기초 데이터 중 order_srl, buy_srl 같은 활용도가 높은 컬럼을 인덱싱하는 편 입니다.

      중복도

      ✔️ 중복도가 없을 수록 인덱스 설정에 좋은 컬럼입니다.

      중복 인덱스 여부에 대한 값입니다.

      인덱스 성능에 대한 고려 없이 마구잡이로 설정하거나,
      다른 부서 다른 작업자의 분리된 요청으로
      같은 컬럼에 대해 인덱스가 중복으로 생성된 경우를 볼 수 있습니다.

      인덱스도 속성을 가집니다.
      인덱스는 테이블 형태로 생성되므로, 속성을 컬럼으로 관리합니다.

      면접 답변 : 타팀에서 같은 테이블을 사용할 때 이미 인덱싱 처리되어 있는 것을 확인하고 인덱싱 신청을 하는 편 입니다.

      기준정도

      기준 정도
      카디널리티 (Cardinality) 높을 수록 적합
      선택도 (Selectivity) 낮을 수록 적합 (5~10% 적정)
      활용도 높을 수록 적합
      중복도 없을 수록 적합

       


      참고

      https://coding-factory.tistory.com/419

       

      [Oracle] 오라클 인덱스(Index) 사용법 총정리(생성, 조회, 삭제, 리빌드)

      인덱스(Index)란? 인덱스는 데이터베이스 테이블에 있는 데이터를 빨리 찾기 위한 용도의 데이터베이스 객체이며 일종의 색인기술입니다. 테이블에 index를 생성하게 되면 index Table을 생성해 관리

      coding-factory.tistory.com

       

       

      반응형

      'Back-end > DB' 카테고리의 다른 글

      [DB] 결합 인덱싱  (0) 2022.05.14
      [DB] Dababase Sharding 이란?  (0) 2022.05.05
      인덱스 란? ***  (0) 2022.02.18
      반응형

      목차

        JUnit 순서

        테스트가 수행될 때는 @Test 만 수행되는 것이 아닌 @BeforeClass, 생성자, @Before, @AfterClass 가 존재합니다.

        생명주기를 이해하기 쉬운 방법 중 하나는 카운터를 세는 코드를 작성하시면 조금도 쉽게 이해할 수 있습니다.

        일단 코드를 먼저 작성하겠습니다. (테스트 코드 기준은 JUnit4 입니다.)

        public class JUnitLifecycle {
            private static int counter = 0;
        
            @BeforeClass
            public static void suiteSetup() {
                assertEquals(0, counter);
                counter++;
            }
        
            public JUnitLifecycle() {
                assertTrue(Arrays.asList(1, 5).contains(counter));
                counter++;
            }
        
            @Before
            public void prepareTest() {
                assertTrue(Arrays.asList(2, 6).contains(counter));
                counter++;
            }
        
            @Test
            public void peformFirstTest() {
                assertTrue(Arrays.asList(3, 7).contains(counter));
                counter++;
            }
        
            @Test
            public void performSecondTest() {
                assertTrue(Arrays.asList(3, 7).contains(counter));
                counter++;
            }
        
            @After
            public void cleanupTest() {
                assertTrue(Arrays.asList(4, 8).contains(counter));
                counter++;
            }
        
            @AfterClass
            public static void suiteFinished() {
                assertEquals(9, counter);
            }
        }

        1. @BeforeClass

        테스트 클래스 시작 시 한번만 수행

        -------------------------------------------------

        2. 생성자

        - 테스트 케이스 시작 전 호출

        - (@Before/@After 이외에도 생성자도 호출이 되는 걸 인지해주세요)

         

        3. @Before

        - 테스트 케이스 시작 전 호출

        - 테스트 값/상태 준비

         

        4. @Test

        - 테스트 케이스

        - public이고 void 타입 값으로 반환

         

        5. @After

        테스트 케이스 종료 후 호출

        - 테스트 후 정리

        -------------------------------------------------

        6. @AfterClass

        모든 테스트 케이스 완료 후, 테스트 클래스 종료 전 수행

         

        마지막 AfterClass 종료 시 카운터는 9인걸 보실 수 있습니다. 이유는 @Test(테스트 케이스)가 2번 호출이 되어 생성자와 @Before/@After 가 다시 한번 호출이 되었기 때문입니다.

        핵심 메소드

        assertEquals 			// 두개의 객체가 같은지 확인
        assertTrue / asertFalse	// Boolean 결과값 확인
        assertNotNull			// 객체가 Null이 아닌지 확인
        assertArrayEquals		// 두 배열의 값이 같은지 확인

         

        테스트 코드를 작성하기 위해서는 생각보다 많은 지식이 필요한 것은 아닙니다.

        테스트 코드를 작성하기 어려운 프로젝트는 이미 개발이 많이 되어 있으며 모듈(함수/클래스) 단위가 커서 테스트 코드를 작성하기 어려운 소스코드가 존재할 때가 오히려 테스트 작성이 어렵습니다.

        그렇기에 시작부터 프로그래밍을 하실 때는 항상 테스트코드를 생활화 하셔야겠습니다.

         

        Java code coverage의 약자로

        junit 테스트의 결과를 바탕으로 커버리지를 결과를 리포트 해주는 툴 입니다.

        특히 코드정적분석도구인 sonarqube와 연계하여 사용하는 경우가 많습니다.

         

        앞선 툴들에 대한 자세한 설명은 다른 포스팅에서 진행할 예정입니다. 이번 글은 제 프로젝트에 적용해볼려고 합니다.

         

        1. build.gradle에 jacoco 추가

        - plugins에 아래처럼 추가

        plugins {
        	...
        	id 'jacoco'
        }
        
        ...
        }

        추가한 뒤 gradle reload를 진행해주면 verification 에 아래 와 같이 추가됩니다.

        2. gradle test 진행

        - 위 사진의 test를 더블 클릭하셔도 되고 gradle test 명령어로 하셔도 됩니다.

        - test 진행이 완료 되면 build > test 폴더 안에 index.html을 발견하실 수 있습니다. 

        - 끌어다가 띄우고 크롬을 통해서 열면

        - 이런 화면을 확인 하실 수 있습니다. 이건 jacoco가 아니라 그냥 test 결과입니다.

        - 이제 jacoco 리포트를 확인해봅시다.

        3. jacocoTestReport 실행

        - jacocoTestReport를 더블클릭해서 실행해줍니다.

        - build > report > jacoco 폴더 안에서 index.html을 확인 하실 수 있습니다. 열어줍니다.

        5. 결과 확인

        - 원래 전체 결과가 나오는데 생각보다 참혹해서 ㅎㅎㅎ 깨달은 부분만 .... 후후 ..

        - 프로젝트 중에 mockito를 이용해서 단위 테스트를 진행하면서 신경을 제일 쓴 service 테스트인대 어디를 안타는 거지 했습니다....

        - 내용 확인을 해보니 아래처럼 예외 테스트가 부족했다는 것을 확인 하였습니다. 

        - 생각해보니 파일 업로드 등 파일 관련 처리를 s3로 옴기고 나서 테스트 코드를 추가하지 않았다는걸 알게되었습니다.

        (추가해야지 .....ㅠㅠㅠㅠ)

         

        - 27%? 이게 뭐지 라는 생각으로 확인 해보니 (참혹한 dto 테스트 커버리지 .....) 

        - Dto에 롬복을 통해서 @Data를 통해서 setter 생성하고 한번도 안써서 생긴 내용 이었습니다 .ㅎ (@Builder 짱짱맨.ㅎ)

        - dto 테스트를 추가하면

        import org.junit.jupiter.api.Test;
        
        import static org.assertj.core.api.Assertions.assertThat;
        import static org.junit.jupiter.api.Assertions.*;
        
        class ProjectResponseDtoTest {
        
            @Test
            void projectResponseDtoTest() {
                ProjectResponseDto projectResponseDto1 = new ProjectResponseDto();
                projectResponseDto1.setProjectId(1L);
                projectResponseDto1.setProjectTitle("이름");
                projectResponseDto1.setProjectContent("내용");
                projectResponseDto1.setProjectPostScript("추신");
                projectResponseDto1.setFileUrl("파일 주소");
                projectResponseDto1.setFileOriginName("파일 이름");
                projectResponseDto1.setProjectLink("프로젝트 링크");
                projectResponseDto1.setLevel(1);
                projectResponseDto1.setMemberId(1L);
        
                ProjectResponseDto projectResponseDto2 = ProjectResponseDto.builder()
                        .projectId(1L)
                        .projectTitle("이름")
                        .projectContent("내용")
                        .projectPostScript("추신")
                        .fileUrl("파일 주소")
                        .fileOriginName("파일 이름")
                        .projectLink("프로젝트 링크")
                        .level(1)
                        .memberId(1L)
                        .build();
        
                assertAll(
                        () -> assertThat(projectResponseDto1).isEqualTo(projectResponseDto2),
                        () -> assertThat(projectResponseDto1.toString())
                                .hasToString("ProjectResponseDto(projectId=1, projectTitle=이름, projectContent=내용," +
                                        " projectPostScript=추신, fileUrl=파일 주소, fileOriginName=파일 이름," +
                                        " projectLink=프로젝트 링크, level=1, memberId=1)")
                );
            }
        }

         

        - 테스트 커버리지가 올라가긴합니다만

         

        - 과연 dto를 테스트하는게 의미가 있는지 위와 같은 코드를 작성하는 게 의미가 있는지 등을 생각하게 되면서 jacoco 설정을 찾아보게 되었습니다.

         

        - 저의 경우 dto와 querydsl에 의해 생기는 Q클래스를 제외하도록 특정 디렉토리의 특정 클래스를 제외시키는 방법을 사용하였습니다.( 제가 사용한 방법과 다른 방법 등은 아래 주소에서 확인하실 수 있습니다.)

        // build.gradle 에 추가
        
        jacocoTestReport {
        	dependsOn test // tests are required to run before generating the report
        
        	afterEvaluate {
        		classDirectories.setFrom(files(classDirectories.files.collect {
        			fileTree(dir: it, exclude: [
        					"com/myintroduce/web/dto/*",
        					"**/Q*.class"
        			])
        		}))
        	}
        }

         

        (참고 : https://wellbell.tistory.com/242)

        반응형
        반응형

        목차

          도메인 주도 설계(Domain-Driven Design)는 왜 필요할까요?

          도메인 주도 설계란?

          말 그대로 도메인을 중심으로 설계해 나가는 방법입니다.

          그럼 도메인이란 무엇일까요?

          소프트웨어로 해결해야할 문제의 영역입니다.

          예를 들어 고객이 원하는 상품을 어떻게 잘 제공할 것인가? 의 대한 문제는 커머스라는 도메인이 있습니다.

          커머스 도메인의 하위 도메인으로 판매자가 무엇을 판매할 것인가? 의 대한 문제는 상품이라는 도메인이 있고,

          공통된 상품에 대해서 어떻게 공통 정보를 제공할 것인가? 의 대한 문제는 카탈로그 도메인이 있습니다.

          그 밖에 판매자, 사용자, 카테고리, 주문, 배송 등 많은 도메인이 존재합니다.

          소프트웨어의 존재에 대한 가치

          소프트웨어의 본질은 해당 소프트웨어의 사용자를 위해 도메인에 관련된 문제를 해결하는 능력에 있습니다.

          아무리 기술적으로 정교하고 뛰어난 성능을 갖추더라도 당면한 문제를 해결하지 못하는 소프트웨어는 실패한 소프트웨어라고 할 수 있습니다. 얼마나 빠른가, 얼마나 많이 처리할 수 있나, 얼마나 많은 사람이 붙어서 사용할 수 있나 등은 나중 이야기입니다.

          기존 개발의 문제점(비즈니스 로직의 위치)

          • 데이터베이스 위주의 개발 (데이터베이스 모델링을 중요시) - 서비스에는 흐름제어 로직밖에 없고 비즈니스 규칙과 개념들은 SQL에 존재한다. 이렇게 비즈니스 로직과 저장 기술이 강하게 결합되어 있는 구조인 경우, 저장소를 변경하기 쉽지 않다. 또한 성능 측면에서 성능을 데이터베이스에 의존하게 된다. 이러면 데이터가 많아졌을 때 데이터베이스의 성능은 지속적으로 떨어지고 이를 최적화 하기 위해 데이터베이스 서버의 사양과 용량을 계속 증가시키고 쿼리 튜닝에 몰두할 수 밖에 없다. 클라우드 인프라를 사용한 자동 스케일 아웃은 의미가 없어진다. 정작 바쁜 것은 데이터베이스이기 때문에 어플리케이션을 아무리 스케일 아웃해봐야 효과는 미미하다.
          • 트랜잭션 스크립트 패턴 - 서비스(Spring에서 사용되는 Service를 말함)에 모든 비즈니스 로직이 있고 비즈니스 절차에 따라 도메인 객체를 이용해 처리한다. 도메인 객체는 단지 속성값만 이용되는 정보 묶음의 역할만 하게 된다. 서비스는 유스케이스 처리의 단위이고 대부분의 비즈니스 로직 처리가 서비스에서 이뤄지므로 비슷한 유스케이스의 경우 서비스에 중복되는 코드가 계속 생겨날 수 있고 이런한 점이 유지보수를 어렵게 한다. 비즈니스 로직을 테스트하기 위해 Mocking을 해야하고 이는 테스트의 복잡성을 높이고 관리하기 어려운 테스트 코드를 발생시킨다.

          그럼 비즈니스 로직은 어디에 있는 것이 좋을까요?

          도메인 모델 패턴

          • 도메인 객체가 속성뿐만 아니라 비즈니스 행위를 가지고 있어 책임을 수행하게 된다.
          • 서비스의 책임들이 도메인으로 분산되기 때문에 서비스의 메서드는 단순해진다.
          • 거대한 서비스 클래스 대신 각기 적절한 책임을 가진 여러 클래스로 구성되므로 이해하기 쉽고 관리 및 테스트하기 쉽다.
          • 잘 정의된 도메인 모델은 코드양을 줄이고 재사용성도 높다.
          • 도메인 모델 패턴은 도메인 주도 설계의 애그리거트 패턴을 적용할 수 있는 구조이다.

          도메인 주도 설계

          도메인 주도 설계는 크게 전략적 설계와 전술적 설계로 나뉩니다.

          전략적 설계 - 도메인 전문가 및 기술팀이 함께 모여 유비쿼터스 언어를 통해 도메인 지식을 공유 및 이해하고 이를 기준으로 개념과 경계를 식별해 바운디드 컨텍스트(bounded context)로 정의하고 경계의 관계를 컨텍스트 맵(context map)으로  정의하는 활동

          전술적 설계 - 전략적 설계에서 도출된 바운디드 컨텍스트와 도메인을 이용하여 애그리거트 패턴, 엔티티와 값 객체, 레포지토리, 등을 구성하고 구현하는 활동

          전략적 설계

          도메인과 서브도메인

          • 도메인은 한 조직이 행하는 일과 그 조직 안의 세계를 의미합니다.
          • 서브 도메인은 어떤 도메인 영역의 상위 도메인이 있는 것을 강조하기 위해 사용하는 용어입니다.
          • 서브 도메인은 중요도에 따라 핵심 서브도메인, 지원 서브도메인, 일반 서브도메인으로 나눕니다.
          • 핵심 서브도메인 - 다른 경쟁자와 차별화를 만들 비즈니스 영역이기 때문에 기업의 프로젝트 목록에서 높은 우선순위를 갖는 영역이자 소프트웨어 개발에서 전략적으로 가장 큰 투자가 필요한 영역. 예) 커머스 도메인에서 핵심 서브도메인은 주문, 결졔, 상품, 카테고리 등
          • 지원 서브도메인 - 비즈니스에 필수적이지만 핵심은 아닌 부분으로 볼 수 있다. 그러나 핵심 도메인을 성공시키기 위해서는 반드시 필요한 영역. 핵심 서브도메인 다음으로 중요한 영역. 예) 커머스 도메인에서 지원 서브도메인은 카탈로그, 쿠폰 등
          • 일반 서브도메인 - 비즈니스적으로 특화된 부분은 아니지만 전체 비즈니스 솔루션에는 필요한 부분으로 기존 제품을 구매해서 대체할 수 있다. 예) 커머스 도메인에서 일반 서브도메인은 파일관리, 인증관리 등
          • 예시로 든 서브 도메인들은 커머스 도메인이라고 할지라도 회사마다 중요하게 보는 것이 다르기 때문에 달라질 수 있음

          유비쿼터스 언어

          같은 것을 보고 다른 용어를 사용하고 있다.

          • 특정 도메인에서 특정 용어가 해당 도메인에서의 의도를 명확히 반영하고, 도메인의 핵심 개념을 잘 전달할 수 있는 언어
          • 모든 팀원이 특정 용어를 들었을 때 같은 것을 생각할 수 있는 명확하게 정의된 언어. 같은 용어에 각자 다른 생각을 하거나 같은 것을 말하지만 용어가 다른 경우가 있으면 안된다.
          • 도메인에서 사용하는 언어는 코드에 그대로 똑같이 반영되야 한다. 똑같이 반영되지 않으면 개발자는 해당 용어를 해석하고 이해해야하는 부담이 생긴다.
          • 유비쿼터스 언어를 사용함으로써 코드의 가독성을 높여 코드를 분석하고 이해하는데 시간을 절약할 수 있다.
          • 용어가 정의 될 때마다 용어 사전에 이를 기록하고 명확하게 정의 함으로써 추후 또는 다른 사람들도 공통된 언어를 사용할 수 있도록 한다.

          용어사전 예시)

          한글명 영문명 설명
          상품 product 메뉴를 관리하는 기준이 되는 데이터
          메뉴 그룹 menu group 메뉴 묶음, 분류
          메뉴 menu 메뉴 그룹에 속하는 실제 주문 가능 단위
          메뉴 상품 menu product 메뉴에 속하는 수량이 있는 상품
          금액 amount 가격 * 수량
          주문 테이블 order table 매장에서 주문이 발생하는 영역
          빈 테이블 empty table 주문을 등록할 수 없는 주문 테이블
          주문 order 매장에서 발생하는 주문
          주문 상태 order status 주문은 조리 ➜ 식사 ➜ 계산 완료 순서로 진행된다.
          방문한 손님 수 number of guests 필수 사항은 아니며 주문은 0명으로 등록할 수 있다.
          단체 지정 table group 통합 계산을 위해 개별 주문 테이블을 그룹화하는 기능
          주문 항목 order line item 주문에 속하는 수량이 있는 메뉴
          매장 식사 eat in 포장하지 않고 매장에서 식사하는 것

          바운디드 컨텍스트

          • 도메인 영역의 경계
          • 바운디드 컨텍스트안에서는 유비쿼터스 언어를 사용해야한다.
          • 도메인 영역의 경계의 기준은 유비쿼터스 언어를 사용했을 때, 해당 용어의 개념이 달리지는 그 곳을 기준으로 경계를 나눈다.

          바운디드 컨텍스트 경계

          • 고객이라는 도메인은 결제 도메인 입장에서는 신용카드 정보나 계좌 정보를 가진 결제자로서 사용되고 배송 도메인 입장에서는 상품을 받을 주소와 우편번호, 전화번호를 소유한 수취자를 의미한다.
          • 도메인 모델은 특정한 컨텍스트 안에서 완전한 의미를 갖는다.
          • 바운디드 컨텍스트는 여러개의 서브 도메인으로 구성되고 하나의 서브 도메인은 한 바운디드 컨텍스트에 포함된다.

          좋은 바운디드 컨텍스트

          • 하나의 BOUNDED CONTEXT는 하나의 팀에만 할당되어야 한다.
            • 하나의 팀은 여러 개의 BOUNDED CONTEXT를 다룰 수 있다.
          • 각각의 BOUNDED CONTEXT는 각각의 개발 환경을 가질 수 있다.

          컨텍스트 맵

          컨텍스트 맵 예시

          • 컨텍스트 경계를 식별해 내고 이들간의 관계를 표현한 그림을 컨텍스트 맵(Context Map)이라 한다
          • 컨텍스트간의 관계는 선으로 표현되고 U는 Upstream으로서 공급자, D는 Downstream으로서 수요자를 나타낸다. 즉 데이터가 흐르는 방향
          • 관계는 단방향으로 설정한다.
          • 동기 호출은 실선, 비동기 호출은 점선
          • 이렇게 도출된 바운디드 컨텍스트는 마이크로서비스 후보가 된다.
          • 자세한 내용은 아래 주소에서 확인

          https://engineering-skcc.github.io/microservice%20modeling/ddd-Srategic-design/

           

          마이크로서비스 모델링 ③ : DDD의 전략적 설계

          마이크로서비스 도출기법으로 활용되는 DDD의 전략적 설계 개념을 살펴보자.

          engineering-skcc.github.io

          이벤트 스토밍

          이벤트를 중심으로 이해관계자들이 모여 브레인 스토밍하는 워크숍

          도메인을 추출할 수 있다

          바운디드 컨텍스트를 추출할 수 있다

          에그리거트를 추출할 수 있다

          컨텍스트 맵을 추출할 수 있다.

          이벤트 스토밍 결과와 헥사고날 아키텍처 구성요소와 매핑이 가능하다

          이벤트 스토밍 방법

          왼쪽에서 오른쪽으로 시간 흐름순으로 포스트잇 붙이기

          같은 시점에 비즈니스 조건에 따라 대체적으로 발생할 수 있는 이벤트는 세로로 아래쪽에 같은 선상에 붙인다.

          1. 도메인 이벤트 찾기 - 오렌지색
          2. 외부 시스템/외부 프로세스 찾기 - 핑크색
          3. 커맨드 찾기 -파란색
          4. 핫스폿 찾기 - 보라색
          5. 액터(사용자/역할) 찾기 - 작은 노란색
          6. 애그리거트 정의하기 - 노란색
          7. 바운디드 컨텍스트 정의하기 - 마커펜 또는 라인 테이프, 정책 도출은 라일락색
          8. 컨텍스트 매핑하기

          순서는 변경될 수 있다.

          참고 자료: https://velog.io/@maketheworldwise/DevOps-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84

           

          [DevOps] 도메인 주도 설계

          🧐 Today I Learned (도메인 주도 설계, 이벤트 스토밍)

          velog.io

           

          헥사고날 아키텍처 매핑

          헥사고날 아키텍처

          • 커맨드 -> REST API
          • 애그리거트 -> 도메인 모델
          • 도메인 이벤트 -> 이벤트 메시지 처리 어댑터의 처리 대상
          • 외부 시스템 -> 외부 연계 시스템(그림에선 마이크로서비스)

          전술적 설계

          도메인 모델링 구성 요소

          기존 객체 모델링은 자유도가 높아 문제 영역을 파고들수록 여러 층의 복잡한 계층 구조를 만들게 될 가능성이 높다. 전술적 설계에서는 도메인 모델링 구성 요소의 역할에 따른 유형을 정의하고 이러한 규칙에 따라 모델링하면 단순하게 설계가 가능하다.

          1. 엔티티(Entity)
          2. 값객체(Value Object)
          3. 애그리거트(Aggregate)
          4. 레포지토리(Repository)
          5. 도메인서비스
          6. 팩토리
          7. 도메인이벤트

          엔티티(Entity)

          • 엔티티는 다른 엔티티와 구별할 수 있는 식별자를 가진 도메인의 실체 개념을 표현하는 객체이다.
          • 식별자는 고유하되 엔티티의 속성 및 상태는 계속 변할 수 있다.
          • 식별자가 있기 때문에 데이터베이스로 추적가능하다

          엔티티 구조

           

          값객체(Value Object)

          값객체는 각 속성이 개별적으로 변화하지 않는 개념적 완전성을 모델링한다.

          <도메인 주도 설계 핵심>의 저자 반 버논은 값객체의 특성을 다음과 같이 정의한다.

          • 도메인 내의 어떤 대상을 측정하고, 수량화하고, 설명한다.
          • 관련 특징을 모은 필수 단위로 개념적 전체를 모델링한다.
          • 측정이나 설명이 변경될 땐 완벽히 대체 가능하다.
          • 다른 값과 등가성을 사용해 비교할 수 있다.
          • 값 객체는 일단 생성되면 변경할 수 없다.

          그 밖에 특성

          • 밸류 타입은 불변
          • 시스템이 성숙함에 따라 데이터 값을 객체로 대체
          • 밸류 객체의 값을 변경하는 방법은 새로운 밸류 객체를 할당하는 것뿐이다.
          • 정말 String으로 우편 번호를 표현할 수 있는가?
          • 항상 equals() 메서드를 오버라이드할 것을 권고한다.

          equals를 재정의하려거든 hashCode도 재정의하라 - Effective Java
          VALUE OBJECT는 DTO가 아니다. - Martin Fowler

          애그리거트(Aggregate)

          • 관련 객체를 하나로 묶은 군집(1~2개의 엔티티와, 값객체, 표준타입(자바에서 enum)으로 구성)
          • 애그리거트는 군집에 속한 객체들을 관리하는 루트 엔티티를 갖는다.
          • 이들 간에는 비즈니스 의존관계를 맺고 있으며 비즈니스 정합성을 맞출 필요가 있다. 따라서 애그리거트 단위가 트랜잭션의 기본 단위가 된다.
          • 애그리거트로 묶어서 바라보면 좀 더 상위 수준에서 도메인 모델 간의 관계를 파악할 수 있다.
          • 애그리거트는 응집력을 유지하고 애그리거트간에는 느슨한 결합을 유지한다.
          • 애그리거트에 속한 객체는 유사하거나 동일한 라이프사이클을 갖는다.
          • 한 애그리거트에 속한 객체는 다른 애그리거트에 속하지 않는다.
          • 두 개 이상의 엔티티로 구성되는 애그리거트는 드물게 존재한다.(대부분 애그리거트 루트만 엔티티이다. 그 밖의 엔티티가 존재하면, 정말 그 객체가 엔티티가 맞는지 의심해봐야한다. 혹은 드물게 운영상 데이터 추적 혹은 성능상의 이유로 엔티티로 만들기도 한다.)

          애그리거트 구성

          애그리거트 루트(Aggregate root)

          • 애그리거트 내에 있는 엔티티 중 가장 상위의 엔티티를 애그리거트 루트로 정함.
          • 애그리거트 루트를 통해서만 애그리거트 내의 엔티티나 값 객체를 변경할 수 있다.(퍼사드 패턴과 유사)
          • 애그리거트간의 참조는 직접참조하지 않고 ID참조를 한다.(그림에서 Order가 Buyer를 직접 참조하지 않고 BuyerID로 참조하고 있다.)
          • 애그리거트는 단일 트랜잭션으로 일관성을 유지하지만 애그리거트간의 일관성이 필요하다면 도메인 이벤트를 통해 다른 애그리거트를 갱신해서 일관성을 유지한다.

          리포지토리(Repository)

          • 엔티티나 밸류가 요구사항에서 도출되는 도메인 모델이라면 리포지터리는 구현을 위한 도메인 모델
          • 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의한다.
          • 애그리거트를 구하는 리포지터리 메서드는 완전한 애그리거트를 제공해야 한다.
          • 리포지터리가 완전한 애그리거트를 제공하지 않으면, 필드나 값이 올바르지 않아 애그리거트의 기능을 실행하는 도중에 NullPointerException과 같은 문제가 발생하게 된다.
          • 리포지토리는 애그리거트(루트) 단위로 존재하며 테이블 단위로 존재하는 것이 아니다.(애그리거트 1 개 당 리포지토리 1 개)

          도메인 서비스

          여러 애그리거트가 필요한 기능

          결제 금액 계산 로직

          • 상품 애그리거트: 구매하는 상품의 가격이 필요하다. 또한 상품에 따라 배송비가 추가되기도 한다.
          • 주문 애그리거트: 상품별로 구매 개수가 필요하다.
          • 할인 쿠폰 애그리거트: 쿠폰별로 지정한 할인 금액이나 비율에 따라 주문 총 금액을 할인한다. 할인 쿠폰을 조건에 따라 중복 사용할 수 있다거나 지정한 카테고리의 상품에만 적용할 수 있다는 제약 조건이 있다면 할인 계산이 복잡해진다.
          • 회원 애그리거트: 회원 등급에 따라 추가 할인이 가능하다.

          이 상황에서 실제 결제 금액을 계산해야 하는 주체는 어떤 애그리거트일까?

          • 한 애그리거트에 넣기 애매한 도메인 개념을 구현하려면 애그리거트에 억지로 넣기보다는 도메인 서비스를 이용해서 도메인 개념을 명시적으로 드러내면 된다.
          • 응용 영역의 서비스가 용용 로직을 다룬다면 도메인 서비스는 도메인 로직을 다룬다.
          • 도메인 영역의 애그리거트나 밸류와 같은 다른 구성요소와 비교할 때 다른 점은 상태 없이 로직만 구현한다.
          • 서비스를 사용하는 주체는 애그리거트가 될 수도 있고 응용 서비스가 될 수도 있다.
          • 특정 기능이 응용 서비스인지 도메인 서비스인지 감을 잡기 어려울 때는 해당 로직이 애그리거트의 상태를 변경하거나 애그리거트의 상태 값을 계산하는지 검사해 보면 된다.
          • 응용 서비스와 구분을 위해 통상 응용 서비스에는 @Service 어노테이션을, 도메인 서비스에는 @Component를 사용하기도 한다.

          팩토리

          • 복잡한 객체를 생성해야한다면 생성 역할만 책임지는 Factory에게 그 역할을 위임할 수 있다.
          • 도메인 객체를 생성하기 위한 기존의 클라이언트 코드가 깔끔해진다.

          팩토리의 생성 위치

          1. 애그리거트 루트의 정적 팩토리 메서드 - 애그리거트를 생성하기 좋은 위치
          2. 도메인 서비스 - 다른 애그리거트를 이용하여 생성해야한다면 고려해보자
          3. 별개의 팩토리 클래스 - 구상 구현체나 생성과정의 복잡성등을 감춰야 하는 경우(?)

          Factory는 자신의 생성물과 가장 밀접한 관계에 있는 위치에 있어야 한다. (만들어내는 객체와 매우 강하게 결합돼 있으므로)

          도메인 이벤트

          • 서비스간 정합성을 일치시키기 위해 단위 애그리거트의 주요 상태 값을 담아 전달되도록 모델링한다.
          • 이벤트의 용도는 후처리, 데이터 동기화 등
          • 도메인 이벤트를 사용하면 애그리거트간, 바운디드 컨텍스트간, 외부 서비스와의 결합을 느슨하게 한다.(도메인 로직이 섞이는 것을 방지)
          • 도메인 모델에서 이벤트 주체는 엔티티, 밸류, 도메인 서비스와 같은 도메인 객체이다.
          • 도메인 객체는 도메인 로직을 실행해서 상태가 바뀌면 관련 이벤트를 발생한다.
          • 스프링에서 제공하는 AbstractAggregateRoot를 애그리거트 루트에 확장하면 애그리거트 루트 내에서 직접 이벤트를 발생할 수 있다(기존의 ApplicationEventPublisher을 사용하면 어플리케이션 레이어에서 이벤트를 발행해야한다)
          • 이벤트 핸들러는 서비스 레이어에서 구현하면 된다.

          도메인 주도 설계 아키텍처

          기존 레이어드 아키텍처의 문제점

          Layered&amp;amp;nbsp;Architecture

          • 도메인 레이어가 인프라 레이어에 의존하고 있다.
          • 이는 고수준 모듈이 저수준 모듈에 의존하는 것이다.
          • 고수준 모듈 - 어떤 의미 있는 단일 기능을 제공하는 모듈
          • 저수준 모듈 - 고수준 모듈의 기능을 구현하기 위해 필요한 하위 기능의 실제 구현
          • 여기서 의미가 있는 기능이라는 것은 무엇일까? 바로 비즈니스로직!
          • 도메인 주도 설계에서 비즈니스 로직을 담당하는 도메인 레이어가 고수준 모듈이다.
          • 나머지 저장 기능, 인증 기능 등은 비즈니스 기능에 비해 저수준 모듈이다.
          • 우리는 이 도메인 레이어를 보호해야할 필요가 있다.

          DIP(Dependency Inversion Principle, 의존 역전 원칙)

          DDD Architecture

          • 저수준 모듈이 고수준 모듈에 의존한다고 해서 이를 DIP(Dependency Inversion Principle, 의존 역전 원칙)라고 부른다.
          • 인프라스트럭처 영역에 의존할 때 발생했던 구현 교체가 어렵다는 문제와 테스트가 어려운 문제를 해소할 수 있다.
          • 고수준 모듈은 더 이상 저수준 모듈에 의존하지 않고 구현을 추상화한 인터페이스에 의존한다.
          • DIP를 적용할 때 하위 기능을 추상화한 인터페이스는 고수준 모듈 관점에서 도출한다.
          • 추상화한 인터페이스는 저수준 모듈이 아닌 고수준 모듈에 위치한다.

          고수준 모듈이 저수준 모듈에 의존한다

           

          참고(출처)

          https://yoonbing9.tistory.com/121

           

          도메인 주도 설계란? DDD란?

          도메인 주도 설계(Domain-Driven Design)는 왜 필요할까요? 도메인 주도 설계란? 말 그대로 도메인을 중심으로 설계해 나가는 방법입니다. 그럼 도메인이란 무엇일까요? 소프트웨어로 해결해야할 문제

          yoonbing9.tistory.com

           

           

           

          반응형

          'Back-end > architecture' 카테고리의 다른 글

          MSA(MicroService Architecture)  (0) 2022.04.06
          반응형

          목차

            API Gateway 란?

            최근 서비스는 마이크로서비스 아키텍처 형태로 독립적인 기능을 수행하는 작은 단위의 서비스로 나누어 개발하고 있습니다.
            작은 단위의 서비스로 분리함에 따라 서비스의 복잡도를 줄일 수 있으며, 변경에 따른 영향도를 최소화하면서 개발과 배포를 할 수 있다는 장점이 있습니다.
            하지만, 여러 서비스의 엔드포인트를 관리해야 하는 어려움이 있으며 각 서비스의 API에서 공통적으로 필요한 기능을 중복으로 개발해야 하는 문제가 있습니다.

            API Gateway를 이용하면 통합적으로 엔드포인트와 REST API를 관리 할 수 있습니다.

            모든 클라이언트는 각 서비스의 엔드포인트 대신 API Gateway로 요청을 전달합니다.

            API Gateway는 사용자가 설정한 라우팅 설정에 따라 각 엔드포인트로 클라이언트를 대리하여 요청하고 응답을 받으면 다시 클라이언트에게 전달하는 프록시 역할을 합니다.

            그뿐만 아니라 API Gateway는 엔드포인트 서버에서 공통으로 필요한 인증/인가, 사용량 제어, 요청/응답 변조등의 기능을 플러그인 형태로 제공하고 있습니다.
            플러그인을 사용하면 각 엔드포인트 API 서버가 구현하지 않아도 되기 때문에 개발자 입장에서는 개발 비용을 줄일 수 있습니다.

            TOAST API Gateway 살펴보기

            TOAST API Gateway는 크게 2가지 개념으로 엔드포인트를 관리하고 있습니다.

            • 도메인(Domain): 도메인은 하나의 엔드포인트 서비스를 관리하기 위한 개념입니다. 도메인은 도메인 키와 엔드포인트 정보를 설정할 수 있습니다. 도메인 키는 각 엔드포인트를 구분하여 라우팅하기 위한 키 값으로 이용됩니다.
            • 엔드포인트(Endpoint): 엔드포인트에서 제공하는 REST API를 관리하는 역할을 합니다.

            API Gateway 생성하기

            예시: 블로그 서비스

            다음과 같이 블로그 서비스는 3개의 엔드포인트로 서비스 구성되고 있다고 가정합니다.

            • account : 블로그 사용자들의 계정 정보를 관리하는 서비스
            • post : 블로그 글을 관리하는 서비스
            • storage: 포스트의 첨부파일(이미지, 도큐먼트 파일 등)을 관리하는 서비스

            blog-account 도메인 생성

            API Gateway를 생성하기 위해서는 가장 먼저 도메인을 생성해야 합니다. 3개의 서비스 중 account 서비스의 도메인 생성 예제입니다.

            blog-account 엔드포인트 생성

            엔드포인트를 생성하여 API Gateway를 통해 제공할 REST API를 설정합니다.

            blog-account 배포

            • 도메인과 엔드포인트 설정을 완료하면, 배포를 하여 서비스에 적용할 수 있습니다.

            플러그인

            API Gateway가 클라이언트로 부터 요청을 전달받으면 설정된 플러그인의 속성 그룹 순서대로 플러그인이 동작합니다.

            • Access Control 에서 제한된 사용자의 요청, 사용 제한 초과 시 요청을 거부합니다.
            • Authentification 에서 인증되지 않은 요청, 변조된 요청에 대해 요청을 거부합니다.
            • Custom 에서 요청/응답에 대한 메시지 변조를 하거나 사용자 정의 응답을 정의할 수 있습니다.
            • Proxy 에서 사용자의 API 서버로 요청을 포워딩하고 응답 값을 전달받아 요청자에게 전달합니다.

            Access Control

            IP ACL

            • 특정 클라이언트만 요청을 허용할 수 있도록 블랙/화이트리스트 방식의 IP 접근 제어 기능을 제공합니다.

            사용량 제한(Usage Limit)

            • 단위 시간(초 단위) 동안 호출 가능한 횟수만큼만 클라이언트가 API를 호출할 수 있도록 설정할 수 있습니다.
            • QoS(Quality of Service) 또는 엔드포인트 서버의 보호 목적으로 API 사용량을 제어할 수 있습니다.

            CORS(Cross-Origin Resource Sharing)

            • 동일 출처 정책(Same Origin Policy)에 의해 브라우저에서는 다른 도메인의 리소스를 요청할 경우 보안 문제를 발생시킵니다. 이를 우회하기 위해서는 CORS 규약에 의해 웹 브라우저와 서버 간 정의된 헤더와 함께 요청과 응답 주고 받아야 합니다. CORS 플러그인을 사용하면 엔드포인트에서 구현하지 않아도 되며, 변경이 발생하는 경우에도 쉽게 설정을 변경할 수 있습니다.

            Authentication

            사전 호출 API (Pre-call API)

            • API Gateway가 클라이언트의 요청을 엔드포인트로 포워딩하기 전, 설정한 사전 호출 API를 호출합니다.
              사전 호출 API의 응답 HTTP Status Code가 200 OK가 아닌 경우 요청을 거부합니다.
            • 사전 호출 API를 통해 사용자 정의 형식의 인증을 처리할 수 있습니다. (예: 세션 토큰의 유효성 검사)

            HMAC, JWT

            • 클라이언트의 요청이 중간에 변조되진 않았는지 무결성을 검증합니다.
              • HMAC 또는 JWT 플러그인에서 비밀키를 설정합니다.
              • 클라이언트는 비밀키를 이용하여 요청정보의 해시 값을 생성하여 요청 헤더에 추가하여 API Gateway로 요청을 전달합니다.
              • API Gateway는 클라이언트의 요청 정보와 사용자가 설정한 비밀키를 이용하여 해시 값을 생성합니다.
              • 클라이언트가 전송한 해시 값과 API Gateway가 생성한 해키 값이 일치하지 않은경우, 무결성이 보장되지 않은 것으로 보아 요청을 거부합니다.

            Custom Plugin

            Modify Header

            • 엔드포인트 서버로 전달되는 요청의 헤더값을 변조하여 엔드포인트로 요청할 수 있습니다.
            • 클라이언트로 전달되는 응답의 헤더값을 변조하여 클라이언트에 응답을 전달 할 수 있습니다.

            URL Rewrite

            • 클라이언트의 요청 URL을 변조하여 사용자의 엔드포인트 서버 URL로 요청을 포워딩할 수 있습니다.

            사용자 정의 응답 (User-defined Response)

            • 사용자가 정의한 응답 헤더와 본문(Body)을 응답하도록 설정합니다.

            통계

            API Gateway 콘솔> Dashboard 에서 각 도메인별 API 통계를 확인할 수 있습니다.


            API 호출 성공 수(HTTP 400미만), 실패 수(HTTP 4XX, 5XX) 그리고 평균 응답시간(ms)과 아웃바운드 네트워크 트래픽를 확인할 수 있습니다.
            통계를 통해 특정 엔드포인트의 REST API의 이상 동작이나 품질을 쉽게 확인할 수 있습니다.

             

             

            출처

            https://meetup.toast.com/posts/201

             

            API Gateway 소개 (TOAST Service 들여다 보기) : NHN Cloud Meetup

            최근 서비스는 마이크로서비스 아키텍처 형태로 독립적인 기능을 수행하는 작은 단위의 서비스로 나누어 개발하고 있습니다.

            meetup.toast.com

             

            반응형

            'Back-end > API' 카테고리의 다른 글

            API와 ENDPOINT란?  (0) 2022.04.06
            REST / REST API / RESTful API 개념  (0) 2022.01.21
            반응형

            목차

              API

              API는 프로그램들이 서로 상호작용하는 것을 도와주는 매개체

              여기서 점원의 역할을 한 번 살펴보겠습니다. 점원은 손님에게 메뉴를 알려주고, 주방에 주문받은 요리를 요청합니다. 그다음 주방에서 완성된 요리를 손님께 다시 전달하지요. API는 점원과 같은 역할을 합니다.

              API는 손님(프로그램)이 주문할 수 있게 메뉴(명령 목록)를 정리하고, 주문(명령)을 받으면 요리사(응용프로그램)와 상호작용하여 요청된 메뉴(명령에 대한 값)를 전달합니다.

              쉽게 말해, API는 프로그램들이 서로 상호작용하는 것을 도와주는 매개체로 볼 수 있습니다

              참고자료
              http://blog.wishket.com/api%EB%9E%80-%EC%89%BD%EA%B2%8C-%EC%84%A4%EB%AA%85-%EA%B7%B8%EB%A6%B0%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8/

              역할

              1. API는 서버와 데이터베이스에 대한 출입구 역할을 한다.
                : 데이터베이스에는 소중한 정보들이 저장되는데요. 모든 사람들이 이 데이터베이스에 접근할 수 있으면 안 되겠지요. API는 이를 방지하기 위해 여러분이 가진 서버와 데이터베이스에 대한 출입구 역할을 하며, 허용된 사람들에게만 접근성을 부여해줍니다.
              2. API는 애플리케이션과 기기가 원활하게 통신할 수 있도록 한다.
                : 여기서 애플리케이션이란 우리가 흔히 알고 있는 스마트폰 어플이나 프로그램을 말합니다. API는 애플리케이션과 기기가 데이터를 원활히 주고받을 수 있도록 돕는 역할을 합니다.
              3. API는 모든 접속을 표준화한다.
                API는 모든 접속을 표준화하기 때문에 기계/ 운영체제 등과 상관없이 누구나 동일한 액세스를 얻을 수 있습니다. 쉽게 말해, API는 범용 플러그처럼 작동한다고 볼 수 있습니다.

              API 사용하면 뭐가 좋을까?

              API를 사용하면 많은 이점들이 있는데요. Private API를 이용할 경우,

              개발자들이 애플리케이션 코드를 작성하는 방법을 표준화함으로써, 간소화되고 빠른 프로세스 처리를 가능하게 합니다.

              EndPoint

              A web service endpoint is the URL where your service can be accessed by a client application.

              Difference

              API vs Endpoint
              An API refers to a set of protocols and tools that allow interaction between two different applications. In simple terms, it is a technique that enables third-party vendors to write programs that can easily interface with each other.
              On the other hand, an endpoint is the place of interaction between applications. API refers to the whole set of protocols that allows communication between two systems while an endpoint is a URL that enables the API to gain access to resources on a server.

              결국 API란 두 시스템, 어플리케이션이 상호작용(소통) 할 수 있게 하는 프로토콜의 총 집합이라면 ENDPOINT란 API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL이다

              반응형

              'Back-end > API' 카테고리의 다른 글

              API GateWay  (0) 2022.04.06
              REST / REST API / RESTful API 개념  (0) 2022.01.21
              반응형

              목차

                MSA란?

                MSA는 MicroService Architecture의 줄임말로, 소프트웨어 개발 기법 중 하나입니다.
                MSA는 작고, 독립적으로 배포 가능한 각각의 기능을 수행하는 서비스들로 구성된 프레임워크입니다.
                경량화되고 독립적인 여러 개의 서비스를 조합하여 애플리케이션을 구현하는 방식으로 서비스마다 자체 데이터베이스를 가지고 동작하기 때문에 개발부터 빌드, 배포까지 효율적으로 수행할 수 있습니다.

                 MSA 등장 배경

                애플리케이션 개발 초기에는 전체 소스 코드를 하나의 배포 유닛 (war 또는 ear)으로 내장시키는 'Monolithic' 방식을 사용하였습니다. 하지만 기존 애플리케이션의 사소한 변경사항이 있더라도 자체적인 QA(Quality Assurance) 주기에 따라 업데이트를 하거나 일부 서비스 업데이트로 오류가 발생한 경우 전체 시스템을 중단하고 오류를 해결하는 등의 다운타임이 발생하는 일이 빈번하였습니다. 이러한 문제점을 해결하기 위해 애플리케이션의 핵심 서비스를 분할하는 MicroService Architecture라는 방식이 생겨났으며 각 서비스들을 독립적으로 구축하고 배포할 수 있게 되었습니다.

                Monolithic이란?

                Monolithic은 소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태이며, 모듈별로 개발을 하고 개발이 완료된 하나의 결과물로 패키징 하여 배포되는 형태를 의미합니다.

                장점

                • 개발 초기에는 단순한 아키텍처 구조와 개발 용이함

                단점

                • 서비스 규모가 커짐에 따라 전체 시스템 구조 파악 및 유지보수가 어려워짐
                • 부분 장애가 전체 서비스의 장애로 확대될 수 있음
                • 배포 시간이 오래 걸림
                • 한 Framework와 언어에 종속적
                • 부분적인 Scale-out(여러 서버로 나누어서 일을 처리 방식)이 어려움

                 MSA 장점

                • 분산형 개발을 통해 개발 주기가 단축되기 때문에 빠르고 유연한 배포가 가능 (출시 기간 단축)
                • 서비스가 독립적이기 때문에 다른 서비스에게 영향을 주지 않음 (뛰어난 복구 능력)
                • 서비스별 기술 도입 및 확장이 자유로움 (높은 확장성)
                • 모놀리식 방식에 비해 애플리케이션이 모듈화 되고 규모가 작기 때문에 우려사항이 줄어듦 (손쉬운 배포)
                • 다중 언어 지원(Polyglot) API를 사용 (향상된 개방성)
                • 하나의 애플리케이션을 여러 부분으로 분할했기 때문에 각 서비스 업데이트 및 개선 용이 (편리한 액세스)

                 MSA 단점

                • 각 서비스들은 API를 통해 통신하므로 네트워크 통신에 의한 오버헤드 발생
                • 서비스별로 로그가 생성되므로 중앙 로그 모니터링이 존재 X
                • 하나의 프로젝트에 수많은 서비스들이 존재하므로 모든 서비스 모니터링 오버헤드 증가
                • 하나의 서비스에서 다른 서비스를 호출하므로 장애 발생 시 경로 및 장애 추적이 힘듦
                • 서비스가 분산되어 있기 때문에 모놀리식에 비해 상대적으로 많이 복잡

                 

                MSA 사례 (bingle)

                • 기존 인프라 구조
                  • Elastic Load Balancer : 둘 이상의 가용 영역에서 EC2 인스턴스, 컨테이너, IP 주소 등 여러 대상에 걸쳐 수신되는 트래픽을 자동으로 분산합니다.
                  • EC2로 트래픽 분산
                  • AWS Opsworks로 배포, 관리
                • 기존 인프라 구조의 문제점
                  레파지토리 하나에 기능이 전체 포함되어 있었다.
                  그의 문제는, commit이 복잡하고 테스트에 시간이 너무 걸린다는 것.
                  • 언제나 모든 서비스를 함께 디플로이, 스케일 하는것
                  • 새로운 기술 도입이 어려움(기능 추가)
                  • 바로 시도해 볼 수 있는 상황이 아니기때문에, 기술적 자유로운 사고가 어렵다.

                 

                • Bingle의 혁신목표
                  • 독립적 스케일링
                  • 독립적 배포
                  • 독립적인 기술 스택
                  • 독립적인 개발 언어
                  • 독립적인 테스트, 모니터링
                • 마이크로서비스를 위한 AWS 템플릿 준비
                  • API게이트웨이 - Lambda - DB
                    (예전에 했던 프로젝트도 이런느낌)
                  • 인프라를 코드로 관리
                  • 이상의 기능들은 무한, 자동 스케일링이 가능하기때문에 서버 안정성이 확보
                  • Lambda 업로드, 끊기지않고 바로 업로드, 배포 가능
                  • 스팸 필터 마이크로 서비스 구조 만들기
                    DynamoDB의 스팸 URL, 단어등을 추가 시켜서 필터 Lambda에서 해당 필터조건을 가지고 필터링 기능을 구현시킨 것
                    (이것의 장점은 다양한 기능에 적용시킬 수 있다는 것이고, DynamoDB에 스팸 URL추가하기도 쉽고, 배포, 테스트하는 것이 모두 코드로 자동화 할 수 있다는 것이다. 그리고 얼마나 많은 스팸체크를 했는지 확인 할 수 도 있다.)
                • 마이크로서비스로의 마이그레이션
                  • 새로 추가되거나 변경이 필요한 기능부터 하나씩 분리
                  • BusinessDomain 단위로 서비스 구성(search, feed, tracking등)
                  • 다른 개발자가 쓰기 쉽도록 인터페이스화, Swagger 문서화
                  • AWS에서 제공하는 managed서비스 활용
                    CloudSearch, KinesisStream등

                 

                 

                배민 사례

                https://techblog.woowahan.com/2523/

                 

                배민 API GATEWAY – spring cloud zuul 적용기 | 우아한형제들 기술블로그

                {{item.name}} 서비스를 운영하고 개발하는 팀이라면, LEGACY라는 거대한 괴물이 얼마나 다루기가 힘든 일인지 동감 할 것이다. 이 괴물이 오래되면 될수록, 크면 클수록… 제가 운영하고 개발하고 있

                techblog.woowahan.com

                 

                11번가 사례

                https://www.youtube.com/watch?v=J-VP0WFEQsY 

                 

                반응형

                'Back-end > architecture' 카테고리의 다른 글

                도메인 주도 설계(Domain-Driven Design)  (0) 2022.04.06
                반응형

                목차

                Memcached란?

                • 무료로 사용할 수 있는 오픈소스이며 분산 메모리 캐싱 시스템이다. 
                • 데이터 베이스의 부하를 줄여 동적 웹 어플리케이션의 속도개선을 위해 사용되기도 함
                • DB나 API호출 또는 렌더링 등으로부터 받아오는 결과 데이터를 작은 단위의 key - value 형태로 메모리에 저장하는 방식
                • Memcached는 필요량보다 많은 메모리를 가졌을 때, 시스템으로부터 메모리를 사용하고 필요로하는 메모리가 부족한 경우 이를 더 쉽게 가져다 사용할 수 있도록 만들어 줌
                • Memcached 사용여부에 따른 메모리 운영방식

                Memcached를 사용하지 않을 경우

                각 노드는 완벽하게 독립적임

                이 경우 고전적으로 사용되던 방식으로 총 캐시 크기가 웹팜(여러 대를 사용해서 웹사이트를 구축한 형태)의 실제 용량의 일부분으로만 사용이 가능하다는 점에서 낭비가 심하다. 각각의 서버에 할당된 캐시 크기만큼 사용할 수 있으므로 웹팜의 캐시 사이즈는 128MB이지만 각 서버에서 사용할 수 있는 사이즈는 65MB이다.

                Memcached를 사용할 경우

                Memcached를 사용할 경우 Memcached로 묶인 모든 서버는 동일한 가상 메모리 풀을 공유한다. 이것은 특정한 항목이 주어졌을 때, 전체 웹 클러스터에서 항상 동일한 위치에 저장되고 검색되어짐을 뜻한다. 또한 응용프로그램에 대한 수요가 증가하여 서버증설에 대해 필요성을 느낄 때, 정기적으로 접근되어져야 하는 데이터의 관점에서도 수요가 증가한다고 볼 수 있다.

                Memcached를 적용하면 분산 메모리 캐시를 적용하게 되는 것이므로 캐싱을 통해 DB나 API 호출에 대한 횟수를 줄일 수 있고 이로 인해 응용프로그램의 수요나 DB 데이터 접근에 대한 부하를 줄여 성능을 향상할 수 있다.

                Redis란

                redis는 오픈소스로서 데이터베이스(NOSQL DBMS)로 분류가 되기도 하고 Memcached와 같이 인메모리 솔루션으로 분류되기도 한다.

                성능은 memcached에 버금가면서 다양한 데이터 구조체를 지원함으로써 Message Queue, Shared memory, Remote Dictionary 용도로도 사용될 수 있으며, 이런 이유로 인스타그램, 네이버 재팬의 LINE 메신져 서비스, StackOverflow,Blizzard,digg 등 여러 소셜 서비스에 널리 사용되고 있다. 

                 

                NoSQL관점에서 봤을 때 redis는 가장 단순한 키-밸류 타입을 사용하고 있다. 데이터 모델을 복잡할수록 성능이 떨어지므로 redis는 단순한 구조를 통해 높은 성능을 보장한다고 할 수 있다.

                NoSQL에는 다양한 제품이 있지만 이 중, redis가 주목받는 이유는 다음과 같다.

                • 데이터 저장소로 가장 입/출력이 빠른 메모리를 채택
                • 단순한 구조의 데이터 모델인 키- 밸류 방식을 통해 빠른 속도를 보장
                • 캐시 및 데이터스토어에 유리
                • 다양한 API지원

                redis, memcached, 구아바 라이브러리등 인메모리 캐시방식을  적용한 제품 중 redis는 global cache 방식을 채택하였다. global cache 방식은 네트워크 트래픽이 발생하기 때문에 java heap영역에서 조회되는 local cache의 성능이 더 낫지만, WAS 인스턴스가 증가할 경우엔 캐시에 저장되는 데이터 크기가 커질수록 redis 방식이 더 유리하다.

                redis는 급격한 사용자가 집중되는 상황이나 대규모의 확장이 예정되어 있는 환경에 적합하다. global cache 방식이 적용되어 was 인스턴스 확장에는 유리하지만 cache 및 redis 세션 등 관리 포인트가 늘어난다는 단점이 존재한다.

                 

                  Redis vs Memcached

                  Redis (Remote Dictionary Storage, 레디스)와 Memcached(맴캐시드)는 유명한 오픈소스인, 인메모리 데이터 저장소이다. 둘 모두 고성능이고 쉽다. 하지만 엔진으로 사용할 때 차이를 반드시 고려야한다.  맴캐쉬드는 명료하고 단순함을 위하여 개발한 반면, 레디스는 다야한 용도에 효과적으로 사용할 수 있도록 많은 특징을 가지고 개발되었다.

                    Redis Memcached
                  공통점 1. 빠른 응답 시간(1ms이내)
                  2. 개발의 용이성
                  3. 데이터 파티셔닝 : 데이터를 노드에 분산 하여 저장가능, 수요가 증가 할 때 더 많은 데이터 효과적으로 처리하기 위하여 스케일아웃이 가능하다.
                  4. 다양한 프로그래밍 언어 지원
                  차이점 1. 더욱 다양한 데이터 구조 : List, Set, 정렬된 Set, Hash, Bit배열 등 다양한 자료구조 제공
                  2. SnapShots : 레디스는 트겆ㅇ시점에 데이터를 저장하여 파일 보관이 가능하여 장애상황시 복구에 용이
                  3. 복제 : Master -Salve 구조로, 여러개의 복제본을 만들 수 있다. 따라서 데이터베이스 읽기를 확장가능
                  4. 트랜잭션 : 트랜잭션이란 데이터베이스 상태를 변경시키는 작업 단위이며, 원자성, 일관성, 독립성, 지속성의 특징을 가지고 있다. Redis는 이러한 특징을 지원한다.


                  멀티스레드를 지원하기 때문에, 멀티프로세스코어를 사용할 수 있다. 따라서 스케일업을 통해 더욱 많은 작업처리를 할 수 있다.
                  주의점 위의 특징만 보면, 모든 상황에서 Redis를 선택해야할 것 같습니다.
                  하지만, Redis는 싱글 쓰레드이기 때문에, 1번에 1개의 명령어만 실행할 수 있습니다. Keys(저장된 모든키를 보여주는 명령어)나 flushall(모든 데이터 삭제)등의 명령어를 사용할 때, 맴캐쉬드의 경우 1ms정도 소요되지만, 레디스의 경우 100만건의 데이터 기준 1초로 엄청난 속도 차이가 있습니다.
                  또한, RDB 작업(특정 간격마다 모든 데이터를 디스크에 저장)이 매우 오래걸립니다. AWS, 60기가 메모리 기준으로 10분이나 소요됩니다. Redis 장애에 원인의 대부분이 해당 기능 때문에 발생하기 때문에 사용할 때 주의해야합니다.

                  단, 공통점의 스케일 아웃은  Redis에 해당된다. 즉, Memcached의 확장성은 Scale up(vertial)을 통해서 얻을 수 있는 반면, Redis는 Scale out(horizontal) 왜냐하면 레디스는 복제가 가능하며 Memcached 복제가 불가능하다. 

                  Data Eviction 전략

                  캐시는 유한한 리소스를 지니므로, 결국 메모리에 자리잡은 자원을 언젠가 삭제해야한다. Memcache 같은 경우 LRU(Least Recenly Used) 알고리즘만을 채택하고 있다. 반면에 Redis의 경우 보다 다양하고 미세한 방법을 제공한다.

                  Redis 알고리즘 전략

                  참고

                  https://brownbears.tistory.com/43

                   

                  Memcached, Redis

                  Memcached Memcached란? 무료로 사용할 수 있는 오픈소스이며 분산 메모리 캐싱 시스템 데이터 베이스의 부하를 줄여 동적 웹 어플리케이션의 속도개선을 위해 사용되기도 함 DB나 API호출 또는 렌더링

                  brownbears.tistory.com

                   

                  반응형

                  'Back-end > cache' 카테고리의 다른 글

                  Simple Spring Memcached(SSM) ... 작성중  (0) 2022.04.05
                  [Server] Cache(캐시)  (0) 2021.12.10

                  + Recent posts