본문 바로가기
golang

Go 언어를 활용한 분산 서비스 개발

by marble25 2023. 7. 23.

프로토콜 버퍼

장점

  • type safety 보장
  • 스키마 위반 방지
  • 보일러플레이트 코드 감소: 인코딩/디코딩 메소드가 자동으로 만들어진다.
  • 빠른 직렬화: JSON보다 직렬화가 6배나 빠르다.
  • 하위 호환성 제공

→ 마이크로서비스 같은 두 시스템 사이에서 통신하기 좋다.

로그

  • 추가만 할 수 있는 레코드의 연속
  • 순서가 있는 데이터를 저장, 공유, 처리할 때 사용
  • 데이터베이스 복제, 분산 서비스 조율, 애플리케이션 상태 관리 등에 사용한다.

원리

  • 여러 개의 세그먼트로 나눔: 무한한 용량의 디스크는 없기 때문
  • 세그먼트: 저장 파일(store file) + 인덱스 파일(index file)
    • 저장 파일: 레코드 데이터 저장
    • 인덱스 파일: 레코드들의 인덱스를 메모리 맵 파일로 만들어 메모리 데이터를 다루는 속도로 빠르게 만들 수 있다.
      • 메모리 맵 파일은 생성한 다음 크기를 바꿀 수 없기에 미리 필요한 크기로 만들어야 한다.
  • 세그먼트 리스트는 항상 하나의 활성 세그먼트를 포함
    • 활성 세그먼트: 유일하게 레코드를 쓸 수 있는 세그먼트

gRPC

과거 분산 서비스의 문제

  • 호환성 유지
    • API 버저닝으로 해결
  • 서버-클라이언트 사이의 성능 관리
    • 데이터베이스 쿼리 최적화
    • 알고리즘 최적화
    • 직렬화/역직렬화 빠르게
    • 요청마다 연결을 만들지 말고 하나의 연결을 오래 사용

☝️internal 패키지는 마법과 같은 패키지로, 가까운 코드에서만 임포트 가능!

☝️ex) /a/b/c/internal/d/e/f의 코드는 /a/b/c 디렉터리와 그 아래에서만 임포트 가능

서비스 보안

  • 주고받은 데이터 암호화 → 중간자 공격 대비
    • TLS 핸드셰이크
  • 클라이언트 인증(authentication)
    • 일반적으로 서버 인증에만 TLS 사용, 클라이언트는 사용자명-비밀번호와 토큰으로 구현
    • 내부 분산 서비스의 경우 TLS 상호 인증 사용
  • 클라이언트 권한 결정(authorization)
    • 리소스의 접근을 공유하고, 소유권의 레벨이 다양할 때 필요
    • 가장 간단하게는 Access List를 이용해서 구현

시스템 관측

메트릭

시간의 경과에 따른 데이터 수치 측정

→ 저장공간과 쿼리 시간을 줄이기 위해 해상도를 줄일 수 있다.

종류

  • 카운터: 이벤트 발생 횟수나 시스템 처리한 전체 바이트와 같은 숫자 추적
  • 히스토그램: 요청의 기간과 크기 같은 데이터 분포
  • 게이지: 현재 값을 추적

중요 메트릭

  • 레이턴시
  • 트래픽
  • 에러
  • 포화도: 서비스 용량

로그

시스템에 발생한 이벤트를 기록

문제 해결, 감사, 프로파일링에 도움

너무 적으면 디버깅이 어렵고, 많으면 무엇이 중요한지 찾기 어렵다.

→ 많이 로깅해 보고, 로그를 줄여나가는 방식 추천

트레이스

요청의 라이프사이클을 수집해서 요청이 시스템 내부로 흘러가는 것을 추적

하나 이상의 스팬으로 구성

  • 스팬: 요청 처리의 일부
  • 스팬은 부모/자식 또는 형제 관계를 가진다.

서비스 디스커버리

서비스에 연결하는 방법을 알아내는 과정

레지스트리 목록을 항상 최신으로 유지

  • 레지스트리: 서비스, 서비스의 위치, 서비스의 이상 유무를 가짐
  • 다운스트림 서비스가 레지스트리에 질의하여 업스트림 서비스의 위치를 알아내고 연결

문제점

  • 클러스터 내 서버들이 어떻게 서로를 찾아낼 것인가?
  • 클라이언트는 어떻게 서버를 찾아낼 것인가?

서프(Serf) 라이브러리

  • 주키퍼나 콘술 등과 달리 중앙 레지스트리 아키텍처 X
  • 각각의 서비스 인스턴스가 서프 노드로 작동
  • 새로운 노드를 만들어 클러스터에 추가한다면, 새 노드는 이미 클러스터에 있는 노드 중 하나 이상을 가리켜야 한다.
    • 각각의 서프 노드가 레지스트리를 관리
    • 노드가 클러스터에 조인하거나 떠나면 서프는 모든 노드에 이벤트를 보낸다.

Consensus

합의 알고리즘은 분산 서비스가 몇몇 실패를 겪더라도 상태에 대해 동의하는 도구

→ 서버를 리더와 팔로워 관계로 나누어 팔로워가 리더의 데이터만을 복제하도록 해야한다.

래프트

  • 리더 선출
    • 팔로워들이 일정 시간 이상 리더의 하트비트 요청을 받지 못하면, 팔로워들은 candidate가 되고 선출을 시작
    • 후보는 자신에게 한 표를 행사하고, 다른 팔로워에게 투표를 요청
    • 다수의 득표를 받은 후보가 리더가 되고, 하트비트 요청을 보내면서 지위를 얻는다.
  • term
    • 논리 시계
    • 후보가 선거를 시작하면 자신의 term을 하나 증가시킨다.
    • 후보가 리더로 선출되면 팔로워들은 term을 똑같이 만들고, 다음 선거까지 변하지 않는다.
  • 로그 복제
    • 클라이언트가 요청을 보내면 리더가 받는다.
    • 리더는 각 요청을 로그에 추가하고, 팔로워들에게 전달한다.
    • 리더가 명령이 실행되었다고 생각하면 리더는 finite-state machine을 이용해 명령을 실행 후 클라이언트에 결과 회신
  • 적절한 서버 수
    • 3개 혹은 5개가 적당
    • 래프트는 (N-1)/2 실패에 대처 가능 → 홀수가 유리

스냅샷

  • 전체 로그를 복제하는 것에 비해 로그를 최소한으로 가질 수 있다.
  • 새 서버를 부트스트랩할 때 효율적

다중화

  • 하나의 포트에서 여러 서비스 제공 가능
  • 첫 바이트에서 서비스 넘버를 전달한다.

로드 밸런싱

로드 밸런싱 전략

  • 서버 프록시: 로드 밸런서가 자체적으로 서비스 레지스트리에 질의하여 해당 요청을 백엔드 서비스로 전달
  • 외부 로드 밸런싱
  • 클라이언트 로드 밸런싱: 클라리언트가 서비스 레지스트리에 질의한 후, 어디에 요청을 보낼지 결정하여 바로 서버로 전달

라운드 로빈 로드 밸런서

  • 첫 번째 호출을 1번 서버에게, 두 번째 호출을 2번 서버에게 전달하는 방식으로 작동한다.
  • 각각의 요청, 클라이언트, 서버에 대한 정보를 고려하지 않는다.
    • 읽는 것은 replicas, 쓰기는 primary에게 요청해야 하는 경우
    • 지리적으로 가까운 서버와 통신하는 경우
    • 레이턴시에 민감한 경우

쿠버네티스

오픈소스 오케스트레이션 시스템으로 컨테이너에서 자동 배포, 확장, 서비스 운영에 사용

  • Pod
    • 쿠버네티스에서 배포할 수 있는 가장 작은 단위
    • 모든 컨테이너는 파드 안에서 실행하고, 네트워크 네임스페이스, IPC 네임스페이스, 볼륨 등을 공유
  • Controller
    • 제어 루프로, 리소스의 상태를 지켜보고 필요하면 수정
  • Statefulset
    • 다음 경우에 필요(ex: PostgresSQL)
      • 안정적이고 고유한 네트워크 ID
      • 안정적으로 유지되는 저장소
      • 순서가 있는 배포와 확장
      • 순서가 있는 자동 무중단 업데이트
  • Probe: 서비스의 신뢰성을 향상하고자 컨테이너에 작업해도 되는지 여부를 판단
    • liveness probe
      • 컨테이너가 살아있는지 확인
      • 컨테이너 생애 내내 호출
    • readiness probe
      • 트래픽을 받을 준비가 되었는지 확인
      • 컨테이너 생애 내내 호출
    • startup probe
      • 컨테이너 애플리케이션이 시작됐는지, liveness와 readiness를 호출해도 되는지 확인
      • 스타트업이 되고 나면 다시 호출하지 않는다.
  • 서비스: 애플리케이션을 네트워크 서비스로 노출
    • ClusterIP: 클러스터 내부 IP로 노출
    • NodePort: 노드의 정적 포트로 노출
    • LoadBalancer: 클라우드 프로바이더의 로드밸런서를 이용해서 노출
    • ExternalName: DNS명을 별칭으로 제공하는 특별한 서비스

'golang' 카테고리의 다른 글

goroutine 파헤치기  (0) 2023.09.23
Formatting in golang  (0) 2023.09.03
Internal package in golang  (0) 2023.09.03
실무에 바로 쓰는 Go 언어 핸즈온 가이드  (0) 2023.07.12
[후기] entgo 두달 사용 후기  (0) 2022.07.23