/v1-health-check

시스템 및 각종 서비스의 상태를 주기적으로 확인하여 기록하고, 원할한 운영을 위한 최적의 상태를 유지해주는 plug-in 개념의 시스템

Primary LanguageGo

SMS-Health-Check

대덕소프트웨어마이스터고등학교 SMS(학교 지원 시스템) 서버 Health Check 서비스



INDEX



SMS Health Check란?

  • SMS(School Management System)는 대덕소프트웨어마이스터고등학교 전공 동아리 DMS에서 개발하여 현재 운영하고 있는 학교 지원 시스템입니다.

  • SMS Health Check는 SMS 서버를 운영중인 환경과 서버를 구성중인 여러 서비스들의 상태를 주기적으로 관리하는 플러그인 식의 서비스입니다.

  • 특정 서비스의 상태 확인 결과가 특정 기준을 통해 정상적이지 않다고 판단이 되면 해당 서비스의 상태 회복을 위한 작업을 수행합니다.



Health Check 종류

모든 Health Check는 수행 결과를 Elasticsearch에 저장하여 관리합니다.

  • disk check
    • 디스크 사용 용량 특정 수치 초과 시 알람 발행 후 Docker Prune 실행
    • 디스크 사용의 주요 원인에는 로그 및 DB 데이터 또한 존재하지만, 해당 데이터를 건드는건 위험하다 판단하여 Docker Prune만 실행
  • memory check
    • 총 메모리 사용량 특정 수치 초과 시 알람 발행 후 메모리 과다 사용 프로세스 재부팅
    • 프로세스 메모리 사용 조회 및 재부팅은 Docker Engine API를 통해 수행
    • 참고로, 서버 구성에 있어서 부재가 발생하면 안되는 서비스들은 재부팅하지 않음
  • elasticsearch check
    • Elasticsearch Shard 갯수 특정 수치 초과 시 알람 발행 후 Jaeger Index 삭제
    • Jaeger에서 매일 새로운 Index를 생성하여 데이터를 저장하기에 주기적으로 관리 필요
    • 예전에 생성된 Index부터 삭제를 진행하며, 최근 한 달 내에 생성된 Index는 삭제되지 않음
  • swarmpit check
    • Swarmpit App 컨테이너 메모리 사용량 특정 기준 초과 시 알람 발행 후 해당 서비스 재부팅
    • Swarmpit App의 경우, 메모리 사용량이 지속적으로 증가하기 때문에 특정 수치에 도달할 때 마다 재부팅이 필요함
  • consul check
    • Consul에 작동되지 않는 노드가 등록되었다면 알람 발행 후 해당 노드 등록 해제
    • 또한, MSA 상의 서비스별로 등록된 노드가 존재하지 않는 경우 알람 발행 후 해당 서비스 재부팅
    • 작동되지 않는 노드인지는 해당 노드와 gRPC 연결 시도를 통해 판별
    • 노드 부재시에는, 서비스 재부팅을 함으로써 재시작 시점에 스스로 노드를 등록하게 함


Clean한 코드에 대해

Clean한 코드의 기준은 무엇일까요? 제가 생각하는 기준은 다음과 같습니다.

1. 의존적인 관계에서 서로의 계층을 명확하게 분리하였고, 그 관계가 느슨하게 결합되었는가?

-> 모든 의존 관계 추상화 완료시, mocking을 이용한 business logic 단위 테스트 가능

  • 기능에 따라 계층을 분리하고, 분리된 계층별로 패키지를 생성하여 해당 패키지에 구현
  • 직접적인 타입의 명시가 아닌 인터페이스 추상화를 통해 느슨한 상하위 계층 간의 의존 관계 형성
  • 상위 계층에서, 하위 계층의 처리 방식을 모른채로 데이터 처리의 책임을 빌려주는 구조
  • 따라서 계층끼리의 의존성을 편리하게 관리하기 위해서 모든 의존성 주입main에서 발생

2. 하위 계층과의 의존 관계를 표현하는 추상화(인터페이스)를 상위 계층이 소유하고 있는가?

-> DIP 패턴 적용 완료시, domain을 제외한 모든 패키지의 임포트가 main 패키지에서만 발생

  • 만약 인터페이스를 하위 계층이 소유하고 있다면, 여전히 하위 계층에 명시적으로 결합된 상태
  • 따라서 인터페이스 소유권을 사용하는 계층으로 옮김으로써, 하위 계층과의 명시적인 결합을 완전히 끊을 수 있다.
  • SOLID 중 DIP(의존성 역전) 원칙으로, 사용할 메서드들만 추상화하여 의존성을 생성할 수 있다는 장점 또한 존재한다.
  • 예외) domain model 관련 패키지(repo, use case)들에 대한 추상화는 domain 패키지에 묶어서 관리


패키지 종류 및 구조

프로젝트를 구성하는 패키지들을 크게 세 가지 종류로 나누어 설명합니다.

1. App

프로세스를 시작하고, main문에서 사용하는 설정 값들을 관리하기 위한 패키지입니다.

  • app
    • main function을 가지고 있는 main package로, Health Check를 실행시키는 시작점
    • 모든 의존성 객체 생성 및 주입이 여기서 일어나며, domain 패키지를 제외한 다른 패키지를 명시적으로 import하는 유일한 패키지
  • app/config
    • app(main) 패키지에서 사용하는 config value들을 관리하고 반환하는 패키지
    • 싱글톤 패턴으로 구현되어 있으며, environment variable 또는 fixed value 반환
    • 특정 인터페이스의 구현체가 아니라, 단순히 app 패키지에서 명시적으로 불러와서 사용하는 객체이다.

2. Domain

기능을 기준으로 domain을 분리하고, 그에 따라 model을 정의하고 추상화를 진행하는 패키지입니다.

  • domain
    • 특정 domain에서 사용할 model 정의와 그와 연관된 계층들(repo, use case)을 추상화하는 것이 필요
    • 따라서 이와 관련된 것을 해당 패키지에서 묶어서 관리하며, 추상화에 대한 구현domain 이름으로 된 패키지 내부에서 진행한다.
    • 결론적으로 도메인에 대한 model struct, repository와 usecase interface를 정의한다.
    • 현재 추상화 및 구현이 완료된 domain에는 syschecksrvcheck가 있다.
  • syscheck
    • system check 기능의 domain에 대한 추상화를 실제로 구현 하는 패키지
    • domain 패키지에서 정의한 추상화에 의존하고 있으며, 네 가지의 하위 패키지로 구성되어있다.
    • repository
      • domain 패키지에서 추상화system check 관련 repository들을 구현하는 패키지
      • domain 패키지에 정의된 model struct에 의존하고 있으며, 데이터를 명령 혹은 조회하는 기능의 계층이다.
      • 현재로써는 elasticsearch를 저장소로 사용하는 구현체만 존재한다.
    • usecase
      • domain 패키지에서 추상화system check 관련 usecase들을 구현하는 패키지
      • domain 패키지에 정의된 repository 추상화에 의존하고 있으며, 실질적인 business logic을 처리하는 기능의 계층이다.
      • 또한 외부 서비스들에 대해 추상화한 agency 인터페이스에도 의존하고 있으며, 해당 추상화에 대한 소유권은 해당 패키지가 가지고 있다.
      • 외부 서비스들의 추상화에 대한 구현체는 아래의 Agent 패키지에서 확인할 수 있다.
    • delivery
      • 특정 API로부터 들어온 데이터를 usecase layer으로 전달하는 기능의 계층
      • 따라서, domain 패키지에 정의된 usecase 추상화에 의존하고 있다.
      • 해당 프로젝트 내에서 최상위 계층으로, 어떠한 추상화에 대한 구현체가 아니다.
    • config
      • syscheck의 모든 하위 패키지에서 사용하는 config value들을 관리하고 반환하는 패키지
      • 싱글톤 패턴으로 구현되어 있으며, config.yaml 파일에 설정된 값 또는 기본 값 반환
      • repository, usecase, delivery 패키지에서 추상화된 인터페이스들을 모두 구현하고 있음.
    • 같은 도메인 내에서도 기능들끼리의 연관성을 없애기 위해, 모든 기능들에 대한 추상화와 구현체들이 서로 다른 타입으로 분리되어있다.
  • srvcheck
    • syscheck 패키지와 비슷하게, service check 기능의 domain에 대한 추상화구현하는 패키지이다.
    • syscheck 패키지와 하위 구성 또한 동일하지만, 서로 간의 결합이 전혀 존재하지 않다.

3. Agent

모든 Agent 관련 패키지들은 usecase 패키지에서 정의된 agency 인터페이스를 구현하기 위한 패키지입니다.

  • consul
    • consul API를 이용하여 consul agency 인터페이스를 구현하는 agent 객체를 정의하는 패키지
    • consul에 등록된 노드 조회, 노드 등록 해제 등의 기능이 있다.
  • docker
    • docker engine API를 이용하여 docker agency 인터페이스를 구현하는 agent 객체 정의
    • 특정 컨테이너의 ID 및 메모리 사용량 조회, 컨테이너 삭제 등의 기능이 있다.
  • elasticsearch
    • elasticsearch API를 이용하여 elasticsearch agency 인터페이스를 구현하는 agent 객체 정의
    • cluster 정보 조회, indices 조회 및 삭제 등의 기능이 있다.
  • grpc
    • gRPC SDK를 이용하여 gRPC agency 인터페이스를 구현하는 agent 객체 정의
    • connection check를 위한 gRPC ping을 발행하는 기능이 있다.
  • slack
    • slack API를 이용하여 slack agency 인터페이스를 구현하는 agent 객체 정의
    • slack app을 이용하여 특정 채널에 메시지를 전송하는 기능이 있다.
  • system
    • linux kernel API를 이용하여 각종 system agency 인터페이스를 구현하는 agent 객체 정의
    • cpu 및 memory 사용량 조회, disk 잔여 용량 조회 등의 기능이 있다.
  • json
    • reqBodyWriter 인터페이스json 형식으로 구현하는 객체를 정의하는 패키지
    • 위의 패키지들과는 달리, 외부 서비스를 추상화한 인터페이스에 대한 구현체는 아니다.
    • 구현체인 mapWriter는 key값에 dot으로 depth가 구분된 map 타입의 변수를 json 형식으로 변환해준다.
    • Ex) map["a.b": "c", "a.b": "d"] -> map["a": map["b": []string{"c", "d"}]]


패키지 의존성 그래프

의존성 그래프는 godepgraph에서 제공하는 툴을 통해 생성하였습니다.

Domain 패키지간의 의존성 그래프

godepgraph2

Agent 패키지 의존성 그래프

godepgraph1