Elixir Backend Monitoring

brave·2022년 11월 1일
0

동기

블로그 주도 개발이라는 좋은 단어에 영감을 받아 블로그를 열었고..

잘쓰지도 못하는 데 잘쓰려고 노력하다간 한글자도 못쓸거같아(라는 밑밥을 뿌려놓고..)
우선 가보겠습니다 뇌의 필터링을 거치지 않은 문체에 대해 미리 죄송한 말씀드립니다

현 회사에서 dev, sandbox 클러스터를 제외한 상용 k8s환경에서만해도
Elixir로 된 백엔드 서버 파드가 50개 정도 됩니다

22년 초만 해도 장애나면 사용자(=직장동료)를 통해 인입되어
키바나를 뒤져 이슈를 해결하는게 다반사였고
어떤 이슈인지 알수없는 경우에는 모든 시니어들이 문제해결에 투입되는 경우가 많았는데요

담당 서비스가 아닐 경우엔 너무나도 소중한 우리 시니어 개발자분들의 리소스 낭비가 크기도했고
장애를 고객 통해서 알아야 된다는 것도 당면한 큰 이슈라 생각되어
인프라/서버 담당자분들과 함께 작업을 진행하게 되었습니다

목표

생각했던 1차적인 목표는

1. 장애 터지기전에 알람을 통해 미리 경고한다
2. 어디가 문제인지 적당한 알람을 줄수 있어야한다
3. 전반적인 서비스 상황을 나타내는 모니터링 대시보드를 제공한다

과정

현재 엘릭서 서버에서는 Logger를 통해 주요한 로그들이 수집하고 있는 상황이었기 때문에
처음에는 현재 개발자들이 익숙하게 쓰고 있는 EFK 스택에서 해결해볼 생각이었습니다

실제로도 동료분이 키바나 대시보드를 깔끔하게 작업해주어
대형 모니터에 전시하여 잘 쓰고 있습니다

다만 키바나는 알람 제공이 유료라
편리하긴 하겠지만 유료로 인해 생기는 귀찮은 점들이 꺼려져서
알람은 그라파나로 알아보게 되었구요

그라파나로 하다 보니 자연스럽게 짝꿍인 프로메테우스를 통해
지표를 수집하는 방향으로 찾아보게되었고 (나중에 나오겠지만 결론적으론 ES도 섞어쓰게됩니다)
prometheus_ex 외의 몇개 라이브러리 추가해 exporter에 지표를 수집하도록 하였구요

EFK 스택의 경우 서버에서 로그를 직접 ES에 쏘는 구조이지만
프로메테우스는 주기적으로 앱서버의 특정 Endpoint에서 지표를 가져가는 구조였기 때문에

몇가지 추가 작업들이 필요했습니다
다행이었던것은 PhoenixInstrumenter, PipelineInstrumenter 같이
기본적인 지표를 떨궈주는 아이가 있어 잘썼구요
아래와 같이 application.ex에 호출해두었습니다

defmodule Rikotan.Application do
  use Application
  
  def start(_type, _args) do
  
  	...
    
	RikotanWeb.MetricsExporter.setup()
    RikotanWeb.PhoenixInstrumenter.setup()
    RikotanWeb.PipelineInstrumenter.setup()
    RikotanWeb.CustomInstrumenter.setup()
    
    ...
    
    Supervisor.start_link(children, opts)
  end 
end

그외 CustomInstrumenter를 추가하여 기본지표와 더불어 몇몇 정보를 같이 수집하였습니다

defmodule RikotanWeb.CustomInstrumenter do
  use Prometheus.Metric

  def setup() do
    Counter.declare(name: :count1, help: "help", labels: [:a, :b], registry: :default)
    Histogram.new(name: :graph1, labels: [], buckets: [], help: "help")
    :telemetry.attach("execute_fun", [:foo, :bar, :fun], &handle/4, %{})
  end

  defp handle(_, _, _, _) do
    Counter.inc(name: :count1, labels: [])
    Histogram.observe([name: :graph1, labels: []], 1_234_321)
  end
end

위의 코드에서는 Counter와 Historam을 사용하여 지표를 떨굽니다
setup() 함수를 앱 시작시에 지표들을 선언하고
:telemetry.attach를 통해 특정함수가 실행되면 콜백으로 불려지는 함수를 통해
지표 값이 변경되는 구조입니다

여기서 알람으로 필요한 지표로 쓰려면 그래프형태인 Histogram으로 하시는 것이 편리합니다
추후 설명할 기회가 있을진 모르겠지만(없겠지만)
그라파나의 알람이 rate/irate로 된 것에만 만들도록 되어있어
counter로는 추가가 어렵더라구요 (실은 방법이 있는데 제가 부족해서 모를 가능성도 큽니다)

정상적으로 작업이 되었다면 exporter endpoint를 찔러보면 다음과 같은 결과가 나옵니다

curl rikotan-service.namespace.svc/metrics
# TYPE http_requests_total counter
# HELP http_requests_total Total number of HTTP requests made.
http_requests_total{status_class="success",method="GET",host="rikotan.com",scheme="http"} 6
http_requests_total{status_class="success",method="POST",host="rikotan2.com",scheme="http"} 63

# TYPE http_request_duration_microseconds histogram
# HELP http_request_duration_microseconds The HTTP request latencies in microseconds.
http_request_duration_microseconds_bucket{status_class="success",method="GET",host="rikotan.com",scheme="http",le="10"} 0
http_request_duration_microseconds_bucket{status_class="success",method="POST",host="rikotan2.com",scheme="http",le="25"} 0

상용 서비스의 경우 해당 endpoint막아 두시는것 잊지마시구요
저는 ingress 설정을 통해 막고 내부 서비스들만 접근할 수 있도록 했습니다

해당 글 잘 정리하는게 먼저 일 것 같지만...
이어서는 Helm을 통해 프로메테우스 스택 추가하고 거기에 지표를 수집하였는지
알람은 어떻게 추가하였는지 적어보겠습니다

profile
one step

1개의 댓글

comment-user-thumbnail
2022년 11월 8일

잘 읽었습니다!

답글 달기