728x90
반응형

세타조인 (Theta Join)

  • 조인에 참여하는 두 릴레이션의 속성 값을 비교하여 조건을 만족하는 튜플만 반환
  • 조건은 (=, !=, >=, <=, >, <) 중 하나
  • 조인에서 ON 키워드로 사용함

동등조인 (Inner Join)

  • 세타조인의 하나. 세타조인 중 = 연산자를 사용하는 조인
  • 동등조인의 결과 릴레이션의 차수는 첫번째 릴레이션과 두번째 릴레이션의 차수를 합한 것
    • 3 + 2 = 5 차수

자연조인

  • 동등조인에서 조인에 참여한 속성이 두 번 나오지 않도록, 중복된 속성 제거 결과 반환
  • 차수는 (두 릴레이션의 차수의 합) - (중복된 속성 수)

외부조인

왼쪽 외부 조인 (left outer join)

  • 왼쪽 투플 기준으로, 자연조인 시 실패한 튜플을 모두 보여주되 값이 없는 대응 속성에는 NULL 값으로 채워 반환

오른쪽 외부 조인 (right outer join)

  • 오른쪽 튜플 기준으로, 자연조인 시 실패한 튜플을 보여주되 값이 없는 대응 속성에는 NULL 값을 반환

완전 외부 조인 (full outer join)

  • 양쪽 튜플 기준으로 자연조인 시 실패한 튜플을 모두 보여주되 값이 없는 대응 속성에는 NULL 값을 채워서 반환
728x90
반응형
728x90
반응형

역정규화

  • 비정규화: 시스템 성능 향상을 위해 의도적으로 중복을 허용하는 과정
  • 쿼리 성능 최적화를 위한 의도적 중복

장점

  • 대용량 데이터 처리 시스템 / 읽기 연산이 많은 시스템에서 유리
  • 데이터 접근 시간 단축

단점

  • 그러나 데이터 중복으로 인해, 일관성을 위지하기 위한 방법이 필요
728x90
반응형
728x90
반응형

DataBase 설계 시 고려해야 하는 것 중엔 정규화와 비정규화(역정규화)가 있다.

정규화

  • 데이터 중복을 최소화하고 무결성을 유지하는 과정

장점

    • 데이터 모델을 여러 작은 테이블로 분해
  • 각 테이블이 하나의 주제에 집중하도록 설계
  • 데이터 중복 줄이고, 업데이트 이상 현상 방지
    • 저장 공간 효율적, 데이터 무결성 보장
    • 데이터베이스 구조의 단순화
    • 데이터 간의 관계가 명확해짐

단점

  • 그러나 과도한 정규화는 쿼리 복잡도 증가시킴 (JOIN)
  • 성능 저하도 가능

정규화 과정

제 1 정규화 (1NF)

  • 테이블의 칼럼이 원자값(Atomic Value: 하나의 값)을 갖도록 테이블 분해
    • 각 칼럼이 하나의 속성만을 가져야 함
    • 하나의 칼럼은 같은 종류나 타입의 값을 가져야 함
    • 각 칼럼이 유일한 이름을 가져야 함
    • 칼럼의 순서가 상관없어야 함
이름 나이 수강과목
홍길동 20 C,C++
이순신 21 Java
이도 34 DB, 운영체제

에서

이름 나이 수강과목
홍길동 20 C
홍길동 20 C++
이순신 21 Java
이도 34 DB
이도 34 운영체제

제 2정규화(2NF)

  • 1 정규화를 진행한 테이블에 대해 완전 함수 종속을 만족하도록 분해하는 것
  • 부분적 종속: 기본키 중에 특정 칼럼에 종속되는 것
  • 완전 함수 종속: 기본키의 부분집합이 결정자가 되어선 안됨을 의미
  • 조건
    • 제 1 정규화를 만족해야함
    • 모든 칼럼이 부분적 종속이 없어야 함.
    • 모든 칼럼이 완전 함수 종속을 만족해야 함
이름 수강과목 강사명 성적
홍길동 C 광해군 95
홍길동 C++ 선조 100
이순신 Java 선조 70
이도 DB 세종 80
이도 운영체제 태종 85
  • 특정 학생의 성적을 알기 위해선 이름과 수강과목을 알아야 함
  • 특정 과목의 강사는 과목명만 알면 알 수 있다.
  • 위 테이블의 기본키는 이름과 과목으로, 복합키이다.
  • 반면 지도교수 칼럼은 과목에만 종속되므로, 제 2정규화를 만족하지 않음
이름 수강과목 성적
홍길동 C 95
홍길동 C++ 100
이순신 Java 70
이도 DB 80
이도 운영체제 85
강사명 수강과목
광해군 C
선조 C++
선조 Java
세종 DB
태종 운영체제

으로 테이블을 나눈다는 의미


제 3정규화

  • 이행적 종속(Transitive Dependencies) 을 없애도록 테이블을 분해함
  • 이행적 종속: A -> B, B -> C이 성립할 때, A -> C이 성립함을 의미함
  • 조건
    • 제 2 정규화를 만족해야 함
    • 기본키를 제외한 속성들 간의 이행 종속성이 없어야 한다.
ID 등급 할인율
101 VIP 70%
102 Gold 40%
103 Bronze 20%
  • 이렇게 데이터가 있으면, ID 를 통해 할인율을 알 수 있다
    • 따라서 제 3정규형을 만족하지 않는다.
ID 등급
101 VIP
102 Gold
103 Bronze
등급 할인율
VIP 70%
Gold 40%
Bronze 20%

BCNF (Boyce-Codd Normal Form)

  • 제 3정규형을 좀 더 강화한 버전
  • 조건
    • 제 3정규형을 만족해야 함
    • 모든 결정자가 후보키 집합에 속해야 함
      • 후보키 집합에 없는 칼럼이 결정자가 되어선 안된다는 의미
이름 수강과목 지도교수
홍길동 C 광해군
홍길동 C++ 선조
이순신 Java 선조
이도 DB 세종
이도 운영체제 태종
* 강사의 이름을 이름과 과목으로 조회할 수 있다.
* 그러나 같은 과목을 다른 강사가 가르칠 수 있기 때문에, 수강과목 -> 지도교수 이란 종속은 성립하지 않음
* 하지만 지도교수 -> 수강과목이라는 종속은 성립
이름 지도교수
홍길동 광해군
홍길동 선조
이순신 선조
이도 세종
이도 태종
지도교수 수강과목
광해군 C
선조 C++
선조 Java
세종 DB
태종 운영체제
으로 나눌 수 있다.

제 4정규화

  • 일반적으로 BCNF 정규화까지만 함
728x90
반응형
728x90
반응형
  • 디자인 패턴은 코드를 잘 작성할 수 있도록 하는 지침서. 레시피라고 말할 수 있다.

생성 패턴

싱글톤 패턴 Singleton

  • 하나의 클래스 인스턴스를 전역에서 접근 가능하게 함
  • 따라서 해당 인스턴스가 한 번만 생성되도록 보장

팩토리 메서드 패턴 Factory Method

  • 객체를 생성하기 위한 인터페이스를 정의하고 서브 클래스에서 어떤 클래스를 인스턴스를 생성할지 결정하는 패턴

추상 팩토리 패턴 Abstract Factory

  • 관련된 객체들의 집합을 생성하는 인터페이스 제공
  • 구체적인 팩토리 클래스를 통해 객체 생성을 추상화하는 패턴

빌더 패턴 Builder

  • 복잡한 객체의 생성 과정을 단순화하고, 객체를 단계적으로 생성하며 구성하는 패턴

프로토타입 패턴 Prototype

  • 객체를 복제하여 새로운 객체를 생성하는 패턴
  • 기존 객체를 템플릿으로 사용
728x90
반응형
728x90
반응형

솔리드 (SOLID) 원칙

  • 솔리드 원칙은 코드를 올바르게 사용할 수 있게 하는 지침서이다
  • 여담으로 디자인패턴은 코드를 잘 만들 수 있게 하는 레시피이다.

단일 책임 원칙 (Single Responsiblity Principle; SRP)

  • 소프트웨어의 컴포넌트는 단 하나의 책임만을 가져야 한다.

개방 폐쇄 원칙 (Open Close Principles; OCP)

  • 확장에 대해선 열려 있어야 하고 수정에 대해선 닫겨 있어야 한다.

리츠코프 치환 원칙 (Liskov Substitution Principle; LSP)

  • 자식 클래스는 부모클래스에서 가능한 행위를 수행할 수 있어야 한다.

인터페이스 분리의 원칙 (Interface Segregation Principle; ISP)

  • 하나의 일반적인 인터페이스 보단 여러 개의 구체적인 인터페이스가 낫다.

*의존관계 역전 원칙 (Dependency Inversion Principle; DIP) *

  • 의존 관계를 맺을 때, 변화하기 쉬운것 보단 변화하기 어려운 것에 의존해야 한다.
728x90
반응형

'백엔드 Backend' 카테고리의 다른 글

[결합도/응집도] 결합도와 응집도란  (0) 2024.10.24
악성코드 종류  (0) 2024.10.16
비동기 Asynchronous 란?  (0) 2024.10.04
[백엔드] REST API 란?  (0) 2024.09.27
[백엔드] gRPC란  (3) 2024.09.26
728x90
반응형

CI / CD

  • CI (Continuous Integration): 지속적 통합
    • 코드에 대한 통합
    • 다수의 개발자들의 코드 베이스를 계속해서 통합한다는 의미
    • 즉 여러 개발자들의 코드를 빠르게 배포함을 의미
  • CD (Continuous Deployment): 지속적 배포
    • 코드 베이스를 사용자가 사용하는 환경에 코드 베이스 배포를 자동화하는 것
  • 즉 CI/CD는 여러명의 개발자들이 개발 환경을 통합하여 사용자가 사용하는 환경에 전달하는 모든 일련의 과정들을 자동화하는 것
    • 여기에는 코드 빌드, 테스트, 배포가 포함됨

젠킨스?

  • Java Runtime Environment에서 동작
    • 플러그인 사용하여 자동화 작업 파이프라인을 설계
    • 파이프라인 마저도 플러그인의 일부
  • Credentials 플러그인을 사용해서 민감정보를 보관

젠킨스 파이프라인

  • Section - 가장 큰 개념
    • Agent Section
      • 오케스트레이션 처럼 slave node에 일 처리 지정
    • Post Section
      • 스테이지가 끝난 이후의 결과에 따른 후속 조치
      • 즉 작업 결과에 따른 행동 조치
    • Stage Section - 카테고리
      • 어떠한 일을 처리할 것인지 stage를 정의
      • Dockerfile의 스테이지를 정의하는 것과 같음
    • Step Section - 카테고리 내부의 동작들
      • 한 스테이지 안에서의 단계
      • 여러 작업들 실행 가능

Declaratives

  • Environment, Stage, Options, Parameters, Triggers, When
  • 각 Stage 안에서 어떠한 일을 할 것인지 정의
  • Environment
    • 환경변수들 정의
  • Parameter
    • 파이프라인 실행시 파라미터를 받음
  • Triggers
    • 파이프라인이 실행되는 트리거 정의
    • 예시: 특정 브랜치에 머지가 감지되었을 때
  • When
    • 수행되는 조건문
    • 예시: 환경변수 BUILD_BRANCH가 dev일 때

예시

  • 깃허브 특정 레포 dev(개발)/main(운영) 브랜치에 머지 인식
    • 미리 Credentials에 등록해 둔 각각 환경에 따라 다른 환경 변수 로드
    • 각각 환경에 따른 이미지 명으로 도커 이미지 빌드
    • 개인 도커 레지스트리에 이미지 푸시
    • 각각 개발/운영 서버에 배포할 서비스 경로 생성
      • docker-compose.yml 파일 복사
      • 빌드하여 푸시한 이미지 가져와서 컨테이너 구동
// 브랜치별 배포 위치

def getDeployTargets(envName) {

targets = [:]



// dev 브랜치

targets['prod'] = [[

    COMPOSE_ENV: 'dev',

    SSH_MODE: 'KEYONLY',

    SSH_IP: '<Server IP>',

    SSH_KEY_ID: 'Key Id From Jenkins Credentials',

    COPY_DIR: '도커 컴포즈 파일 배포할 서버 상의 경로'

]]

    return targets[envName]
}



// 브랜치별 환경 정보

def getBuildBranch(branchName) {
    branches = [
        'origin/main': 'prod',
    ]

    return branches[branchName]
}



pipeline {
    agent any

    //환경변수
    environment {

        //브랜치 선택

        BUILD_BRANCH = getBuildBranch(env.GIT_BRANCH)

        // 도커 설정
        DOCKER_IMAGE = ''
        DOCKER_IMAGE_NAME = '빌드 할 도커 이미지 명'

        // Git, Docker private 레지스트리 로그인 정보 설정    
        GIT_KEY_ID = '깃허브 인증 SSH 키 ID - Credentials에서 관리;'
        REGISTRY_LOGIN_INFO_ID = 'donghquinn_registry'
    }



                        stages {

                            stage('체크아웃') {
                                steps {
                                    echo "작업 브랜치: ${env.GIT_BRANCH}"

                                    git branch: BUILD_BRANCH, credentialsId: GIT_KEY_ID, url: 'git@github.com:donghquinn/<레포 명>.git'

                            }

                        }



                        stage('도커 이미지 빌드') {
                            steps {
                                script {

                                    // 브랜치에 따라 이미지 이름 변경
                                    DOCKER_IMAGE = docker.build(DOCKER_IMAGE_NAME + '-' + BUILD_BRANCH)

                                }

                                echo "Built: ${DOCKER_IMAGE_NAME}-${BUILD_BRANCH}"

                            }
                        }



                        stage('도커 이미지 Push') {
                            steps {
                                script {
                                    // 개발서버 내부 Docker private 레지스트리에 업로드
                                    docker.withRegistry('https://registry.donghyuns.com', REGISTRY_LOGIN_INFO_ID) {

                                    DOCKER_IMAGE.push(env.BUILD_NUMBER)
                                    DOCKER_IMAGE.push('latest')
                                }

                            }
                            echo "Pushed: ${DOCKER_IMAGE_NAME}-${BUILD_BRANCH}:${env.BUILD_NUMBER}"

                            }

                        }



                        stage('도커 컨테이너 배포') {

                        steps {

                            script {

                                def deployTargets = getDeployTargets(BUILD_BRANCH)

                                def deployments = [:]



                                // 배포 타깃별로 병렬 배포

                                for (item in deployTargets) {

                                def target = item



                                deployments["TARGET-${BUILD_BRANCH}"] = {

                                def remote = [:]
                                remote.name = target.SSH_IP
                                remote.host = target.SSH_IP
                                remote.allowAnyHosts = true

                                if (target.SSH_MODE == 'KEYONLY') {

                                    withCredentials([

                                    // DOTENV 파일과 SSH KEY를 가져옴
                                    sshUserPrivateKey(credentialsId: target.SSH_KEY_ID, keyFileVariable: 'SSH_PRIVATE_KEY', usernameVariable: 'USERNAME')
                                    ]) {

                                    // 가져온 키로 ssh 정보 설정
                                    remote.user = USERNAME

                                    remote.identityFile = SSH_PRIVATE_KEY

                                    sshCommand remote: remote, command: """
                                        mkdir -p ${target.COPY_DIR}-${BUILD_BRANCH}/
                                    """

                                    // docker compose 파일 전송
                                    sshPut remote: remote, from: "docker-compose.${BUILD_BRANCH}.yml", into: "${target.COPY_DIR}-${BUILD_BRANCH}/docker-compose.yml", failOnError: 'true'

                                    // 각 상황에 맞는 .env.* 파일 전송

                                   // 각 상황에 맞는 .env.* 파일 전송
                                  sshPut remote: remote, from: DOTENV, into: "${target.COPY_DIR}/.env", failOnError: 'true'

                                    // 도커 이미지 Pull 및 재시작
                                    sshCommand remote: remote, command: """
                                        cd ${target.COPY_DIR}-${BUILD_BRANCH}/
                                        BUILD_BRANCH=${BUILD_BRANCH} docker compose pull
                                        BUILD_BRANCH=${BUILD_BRANCH} docker compose up -d
                                    """
                                }
                            }
                        }

                        parallel deployments

                    }

                }

            }

        }

    }

}
728x90
반응형
728x90
반응형

무중단 배포 전략이란 무엇일까? 각 전략에 대해 개인적 명칭을 붙여봤다.

무중단 배포란?

무중단 배포란 서비스의 중단 없이 새로운 버전을 배포하는 것을 의미한다. 이용자의 서비스 이용에 지장을 주지 않는 것과 동시에 새로운 버전을 배포하는 것이 핵심인 것이다.

이를 위해선 로드 밸런서와 두 대 이상의 서버가 필요하다.

Blue/Green 배포 - 단순 배포 전략?

이전 버전 서버와 새로운 버전 서버를 두고,
공통 로드 밸런서를 통해 새로운 버전을 배포하는 전략이다.

  • Blue 서버: 이전 환경 서버
  • Green 서버: 새로운 배포 환경

Blue/Green 전략

장점

트래픽을 새로운 버전쪽으로 옮기기 때문에 호환성 문제가 발생하지 않는다.

단점

실제 운영에 필요한 리소스보다 2배의 리소스를 확보해야 한다.(서버가 두 대이고, 일질적인 트래픽이 통하는 서버는 이전 환경이기 때문)

Rolling 전략 - 순차 배포 전략?

운영중인 복수개의 인스턴스들을 하나씩 돌아가며(Rolling) 로드 밸런서로부터 트래픽을 끊고 새로운 버전 배포를 하는 전략이다.
즉, 새로운 버전 배포가 완료가 되면 다시 로드 밸런서에 연결을 하고, 그 다음 인스턴스를 로드 밸런서로부터 끊고 새로운 버전을 배포하는 것을 반복하는 것이다.

장점

  • 많은 서버 자원을 배포하지 않아도 무중단 배포 가능
  • 인스턴스마다 차례로 돌아가며 배포를 진행하므로, 배포로 인한 위험이 줄어든다.

단점

  • 새 버전을 배포할 때마다 서비스 중인 인스턴스의 개수가 줄어, 서버 부담이 증가한다.
  • 배포가 진행되는 동안 새로운 버전과 이전 버전의 호환성 문제가 발생할 수 있다.

Canary 배포 - 위험 감지 전략?


Canary 전략

이전 버전과 새로운 버전이 동시에 가동되는 방식으로, 새 버전 인스턴스는 일부 사용자에게만 서비스 하는 방식이다.
새 버전이 정상적으로 작동함을 확인하면, 전체 트래픽을 새 버전으로 전환한다.
오류가 발생한다면, 일부 사용자에게만 발생하므로 오류 방지에 효과적이다.

참고 (개인적 의견)

Canary 전략이라는 이름이 붙은 이유는 탄광에서 위험 감지용으로 데려가던 것에서 유래한 것 같다.

장점

  • 사용자 테스트와 무중단 배포가 동시에 가능함
  • 새로운 버전으로 인한 위험을 감소시킬 수 있다.

단점

  • Rolling 전략과 마찬가지로 이전과 새로운 버전이 동시에 존재하므로 호환성 문제가 발생 가능하다.

참고 링크

728x90
반응형

'데브옵스 devOps > Server' 카테고리의 다른 글

[STANDALONE] Standalone 프로그램이란?  (1) 2024.12.26
[파일전송] Rsync  (0) 2024.12.11
728x90
반응형

_Async/Await_

 

비동기란 무엇일까?

비동기

비동기는 하나의 동작이 완료되는 것을 기다리지 않고, 동시에 다른 작업을 처리하는 방식이다.

 

자바스크립트는 싱글 스레드 언어이기 때문에 필수 불가결적으로 비동기 함수를 선택하게 되었다.

하나의 스레드를 가지고 다른 작업이 마칠때까지 대기해야 한다면, 작업이 너무나도 느려지기 때문이다.

비동기 처리를 지원하는 방식으로는 Promise와 async/await이 있다.

 

예시

비동기 함수는 에어프라이어에 음식 넣고 돌린 후, 다른 재료를 손질하면서 틈틈이 에어프라이어를 체크하는 것과 유사하다.

에어프라이어가 음식을 조리하는 것이 완료될 때 까지 기다리는 것이 아닌, 동시에 다른 작업을 진행하는 것이다.

 

동기

동기는 하나의 동작이 완료된 후에 다음 동작으로 실행하는 순차적 방식이다.

 

개인적인 헷갈림 정리

처음에 비동기와 동기의 개념을 반대로 생각하고 있었다.

오히려 동기를 "병렬 처리"와 개념적으로 혼동하고 있었던 것 같다.

 

동기는 "순차적", 비동기는 "동시에"라고 외워야 겠다.

 

참고 링크

- 주니어 웹 개발자가 알아야 할 "비동기 통신" (https://yozm.wishket.com/magazine/detail/1982/)

728x90
반응형

'백엔드 Backend' 카테고리의 다른 글

[결합도/응집도] 결합도와 응집도란  (0) 2024.10.24
악성코드 종류  (0) 2024.10.16
SOLID 원칙  (0) 2024.10.08
[백엔드] REST API 란?  (0) 2024.09.27
[백엔드] gRPC란  (3) 2024.09.26
728x90
반응형

계기

컨테이너를 구동하였을 때,
해당 컨테이너가 정상적으로 올라간 것으로 보였지만 로그를 확인하거나 exec 명령어로 컨테이너 내부에 접근하고자 했을 때 문제가 발생하고 있는 것을 확인한 적이 여러번 있었다.

때문에 컨테이너의 정상 여부(Health) 를 주기적으로 체크하며 모니터링 할 필요가 있다.

healthcheck 옵션

  • docker compose 설정
    • healthcheck 라는 설정을 함으로써 가능하다.
      • test: 헬스체크 시도 시에 실행할 동작을 정의한다. 단순 curl/wget 으로 요청을 날려볼 수 있고, CLI를 넣을 수도 있으며, 함수를 실행시킬 수도 있다.
      • interval: 말 그대로 체크 실행 주기를 의미한다.
      • timeout: 실행된 헬스체크 동작에 대한 리턴을 기다리는 시간(timeout)을 의미한다.
      • retries: 타임아웃이 걸려 체크 실패 시 재시도 횟수를 의미한다. 재시도까지 전부 실패하면 unhealthy 상태가 된다.
      • start_period: 컨테이너 구동을 기준으로, 헬스체크를 시작할 때까지의 시간을 의미한다. 처음 구동 시, 초기 세팅에 시간이 많이 걸리는 경우가 있기 때문
    • 상태값
      • 0 : healthy. 즉 건강한 상태이다.
      • 1 혹은 다른 숫자: unhealthy. 비정상적인 문제가 발생하고 있다.
services:
    app:
        expose:
            - ${APP_PORT}
        healthcheck:  
            // 헬스체크를 위해 실행할 함수
            test: curl --fail http://localhost:5000/ || exit 1  

            // REDIS 체크의 경우
            test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]

            // 체크 실행 주기
            interval: 40s 
            // 타임아웃 
            timeout: 30s  
            retries: 3  
            // 컨테이너 구동 후 체크 시작할 시점
            start_period: 60s
  • DockerFile 설정

    • 도커 파일 설정은 Dockerfile의 이미지 빌드 과정에 입력된다.
    • 이외 헬스 체크 주기 등의 옵션은 컨테이너 구동 시 입력한다.
    FROM asdcasdcas
    # ... 빌드 내용
    
    # 컨테이너에서 구동하는 어플리케이션의 /health 엔드포인트에 요청을 날리는 것이 헬스체크 방식이다.
    HEALTHCHECK CMD curl --fail http://localhost/health
    docker container run -d -p 8080:80 --health-interval 5s app_image/stable/latest

    결과

    • 헬스체크가 완료되면 아래처럼 보이게 된다.

주기 설정에 관하여

  • healthcheck 는 어찌 되었건 cpu 등 서버 리소스를 사용하기 때문에 적당한 주기(interval)로 실행시켜야 한다.
  • 또한 실제로 헬스체크 동작을 실행시켰을 때 받아올 수 있는 정도의 주기로 실행해야 한다.
    • 만약 헬스체크 대상 어플리케이션의 특정 함수 동작 주기가 1분인데, 10초마다 헬스체크를 한다면, 이는 자원 낭비일 것이다.
728x90
반응형
728x90
반응형

Golang은 뛰어난 동시성 지원이 장점이라고들 한다.

일반적으로 쓰레드를 활용하여 동시성 프로그래밍을 하지만, Golang은 고루틴 goroutine으로 가능하다.

 

고루틴 Goroutine

공시적인 설명으로는 경량 쓰레드이다. 실제 OS의 쓰레드를 사용하는 것이 아닌, golang의 런타임에서 관리되는 논리적 / 가상적 쓰레드이다.

 

사용법

go func() {

    // 대충 코드

  }()

이게 끝이다.

 

thread VS goroutine

1. 메모리 사용량

  • goroutine: 생성시 약 2KB의 스택 메모리 혹은 힙 메모리 공간만을 사용한다.
  • thread: 약 1MB 의 메모리 공간을 사용한다.
  • P.S. Guard Page: 쓰레드가 사용할 메모리 공간과 각 메모리 간의 경계 역할
  • 따라서 스레드 기반의 동시성 처리는 결국 메모리 부족 현상(OutOfMemory) 문제 발생할 수 있으므로, 스레드를 미리 생성해 재활용하는 형태가 될 수 있음.

 

2. 비용

  • goroutine: 런타임에서 논리적으로(하드웨어와 상관 없이) 생성되고 소거되기 때문에 가볍다.
  • thread: OS 에 스레드 생성을 요청해 사용하고 작업 완료 시 다시 OS에 반환해야 한다.
  • 따라서 쓰레드 생성시마다 OS에 요청해 생성하고 다시 반환하는 방식이 더 리소스 사용량이 많다.

 

3. Context Switching 비용

  • 하나의 스레드가 특정 작업 처리를 위해 사용(Blocking)된다면, 다른 쓰레드가 대신하여 처리하도록 스케쥴링 됨
  • goroutine: 3개의 레지스터(PC(Program Counter)), SP(Stack Pointer), DX)만 save/restore 작업을 함
  • thread: 스레드가 스케쥴링고 교체되는 동안 스케쥴러에서는 모든 레지스터들을 save/restore 해야함
  • 일반적으로 16개의 범용 레지스터, PC, SP, Segment 레지스터, 16개의 XMM레지스터, FP coprocessor state, 16개의 AVX 레지스터, 모든 MSR들 등 save/restore 작업을 진해해야함
  • 따라서 Context Switching 할 때 save/restore 해야하는 레지스터의 개수부터가 큰 차이가 남

 

결론

golang이 메모리 사용량과 쓰레드 생성과 작업처리에 있어서의 비용 측면에서 효율적이다.

 

마지막

goroutine의 동작 방식과 쓰레드 종류에 대해선 다음에 서술하고자 한다.

 

REFERENCE

- https://velog.io/@khsb2012/go-goroutine

 

 

728x90
반응형

+ Recent posts