Rails 요청 SLI (서비스 레벨 지표)

참고: 이 SLI는 서비스 모니터링에 사용됩니다. 그러나 기본적으로 stage 그룹 오차 예산에 대한 SLI로 사용되지 않습니다.

요청 Apdex SLI와 오류율 SLI는 응용 프로그램에서 정의된 SLI입니다.

요청 Apdex는 응용 프로그램 성능의 지표로써 성공적인 요청의 기간을 측정합니다. 이에는 REST 및 GraphQL API, 그리고 일반 컨트롤러 엔드포인트가 포함됩니다.

오류율은 서버의 잘못된 동작을 나타내는 실패한 요청의 지표로써 측정됩니다. 이에는 REST API 및 일반 컨트롤러 엔드포인트가 포함됩니다.

  1. gitlab_sli_rails_request_apdex_total: 이 카운터는 5xx 상태 코드로 응답되지 않은 모든 요청에 대해 증가합니다. 느린 실패가 두 번 계산되지 않도록 하기 위해, 이미 요청이 오류 SLI에 포함되어 있기 때문입니다.

  2. gitlab_sli_rails_request_apdex_success_total: 이 카운터는 엔드포인트의 긴급도에 따라 정의된 대상 기간에서 더 빨리 실행된 모든 성공한 요청에 대해 증가합니다.

  3. gitlab_sli_rails_request_error_total: 이 카운터는 5xx 상태 코드로 응답된 모든 요처에 대해 증가합니다.

  4. gitlab_sli_rails_request_total: 이 카운터는 모든 요청에 대해 증가합니다.

이러한 카운터들은 다음과 같이 라벨이 지정됩니다:

  1. endpoint_id: Rails 컨트롤러 또는 Grape-API 엔드포인트의 식별

  2. feature_category: 해당 컨트롤러 또는 API 엔드포인트에 지정된 피처 카테고리

요청 Apdex SLO

이러한 카운터들은 성공 비율로 결합될 수 있습니다. 이 비율을 위한 목표는 서비스 카탈로그에서 서비스 별로 정의됩니다. 이 SLI가 SLO를 충족하기 위해서, 기록된 비율은 다음보다 높아야 합니다:

예를 들어: 웹 서비스의 경우, 우리는 요청의 최소 99.8%가 대상 기간보다 빠르게 실행되기를 원합니다.

우리는 이러한 목표를 경고 및 서비스 모니터링에 사용합니다. 경고를 일으키지 않도록 이러한 목표를 고려하여 지속 기간을 설정하므로 사용자들의 요구를 충족시킬 수 있습니다.

성공적인 측정과 그렇지 못한 측정 모두 stage 그룹의 오차 예산에 영향을 미칩니다.

요청의 긴급도 조정

모든 엔드포인트가 동일한 유형의 작업을 수행하는 것은 아니기 때문에, 각각의 엔드포인트에 대해 서로 다른 긴급도 수준을 정의하는 것이 가능합니다. 낮은 긴급도를 가진 엔드포인트는 높은 긴급도를 가진 엔드포인트보다 더 긴 요청 기간을 가질 수 있습니다.

긴 실행되는 요청은 우리의 인프라에게 더 많은 비용을 지불하게 됩니다. 한 요청을 처리하는 동안 스레드는 해당 요청의 기간 동안 점유된 채로 남아 있습니다. 이 스레드는 다른 어떤 작업도 수행할 수 없습니다. Ruby의 Global VM Lock으로 인해, 스레드가 잠기고 동일한 Puma 워커 프로세스에서 처리되는 다른 요청들에게 지체를 유발할 수 있습니다. 실제로, 이 요청은 워커가 처리하는 다른 요청에게 떠들썩한 이웃입니다. 이러한 이유로, 대상 기간의 상한선을 5초로 제한합니다.

긴급도를 낮추는 경우(더 높은 대상 기간 설정)

기존 엔드포인트의 긴급도를 경우에 따라 낮출 수 있습니다. 다음을 고려하십시오:

  1. Apdex는 지각된 성능과 관련이 있습니다. 사용자가 요청의 결과를 미루고 기다리고 있다면, 5초를 기다리는 것은 받아들여질 수 없을 수 있습니다. 그러나 엔드포인트가 많은 데이터를 필요로 하는 자동화에 의해 사용된다면, 5초는 받아들여질 수 있습니다.

    제품 관리자는 엔드포인트의 사용 방법을 확인해주실 수 있습니다.

  2. 몇몇 엔드포인트의 워크로드는 호출자가 지정한 매개변수에 따라 크게 달라질 수 있습니다. 긴급도는 이러한 차이를 수용해야 합니다. 몇몇 경우에는 엔드포인트가 no-op으로 바뀌면, 해당하는 빠른 요청을 대상으로 설정할 때 이러한 빠른 요청을 무시해야 합니다. 예를 들어, MergeRequests::DraftsController가 모든 병합 요청을 보는 데 사용되지만 거의 렌더링하지 않을 경우에는 여전히 엔드포인트가 수행하는 작업을 수용하는 대상을 선정해야 합니다.

  3. 엔드포인트에 의해 소비되는 종속 리소스를 고려해야 합니다. 엔드포인트가 Gitaly나 데이터베이스에서 많은 데이터를 불러오고 이로 인해 충분하지 않은 성능이 발생하는 경우, 긴급도를 낮추어 대상 기간을 증가시키기보다 데이터 로드 방식을 최적화하는 것이 좋습니다.

    이러한 경우에는 인프라가 이를 견딜 수 있다면, 임시로 긴급도를 낮춰서 엔드포인트가 SLO를 충족시키도록 할 수 있습니다. 이러한 경우에는 이슈에 링크된 코드 코멘트를 만들어주십시오.

    엔드포인트가 많은 CPU 시간을 소비하는 경우, 이 또한 고려해야 합니다: 이러한 종류의 요청은 가능한 짧게 유지해야 하는 떠들썩한 이웃입니다.

  4. 트래픽의 특성 역시 고려되어야 합니다. 엔드포인트로의 트래픽이 가끔씩 폭발적으로 발생하는 경우, 동일한 엔드포인트를 차지하는 작업의 여섯 큰 모음을 호출하는 CI 트래픽처럼, 이러한 엔드포인트가 5초 동안 실행되면 인프라적으로 받아들여질 수 없습니다. 일반 트래픽과 함께 들어오는 느린 요청을 수용하기 위해 우리는 충분히 빠르게 플릿의 규모를 확장할 수 없습니다.

엔드포인트의 긴급도를 줄일 때, 확장성 팀 구성원을 리뷰에 참여시키십시오. 로그에서 사용 가능한 요청률과 기간을 사용하여 권고사항을 도출할 수 있습니다. 서비스의 SLO를 위한 기간보다 더 높은 기간을 정하기 위한 프로세스가 동일하게 사용될 수 있도록, 임계치를 선택할 수 있습니다.

우리는 아직 데이터를 지원하기에, Merge Requests에 이러한 긴 기간의 엔드포인트에 가장 긴 기간을 설정해서는 안될 것입니다.

긴급도 증가 (낮은 대상 기간 설정)

긴급도를 높일 때, 요청을 처리하는 플릿에 대한 SLO를 여전히 충족하는지 확인해야 합니다. 다음과 같은 방법으로 로그의 정보를 사용하여 확인할 수 있습니다:

  1. Kibana의 이 테이블 열기

  2. 테이블은 기본적으로 가장 바쁜 엔드포인트에 대한 정보를 로드합니다. 응답을 빠르게 하려면 다음을 추가하세요:

    • json.meta.caller_id.keyword에 대한 필터
    • 관심 있는 식별자, 예를 들어:

      Projects::RawController#show
      

      또는:

      GET /api/:version/projects/:id/snippets/:snippet_id/raw
      
  3. 엔드포인트를 처리하는 서비스에 대한 적절한 백분위 지속 기간을 확인하세요. 전체 기간은 목표로 하는 대상 기간보다 짧아야 합니다.

  4. 전체 지속 기간이 목표로 하는 대상 기간보다 낮다면, Kibana의 이 그래프에서 시간별 피크를 확인하세요. 이 경우, 해당 백분위는 설정하려는 대상 기간을 초과해서는 안 됩니다.

임계값을 너무 많이 줄이면 Apdex 저하로 인해 경고가 발생할 수 있으므로 병합 요청에 Scalability 팀 구성원을 참여시키세요.

긴급도 조정하는 방법

엔드포인트가 기능 범주를 받는 방법과 유사하게 긴급도를 지정할 수 있습니다. 특정 대상이 없는 엔드포인트는 기본 긴급도(1초 지속)를 사용합니다. 다음 구성이 가능합니다:

긴급도 초 단위 지속 기간 주의사항
:high 0.25초  
:medium 0.5초  
:default 1초 아무것도 지정하지 않았을 때 기본값
:low 5초  

Rails 컨트롤러

컨트롤러의 모든 동작에 대해 긴급도를 지정할 수 있습니다:

class Boards::ListsController < ApplicationController
  urgency :high
end

또한 컨트롤러의 특정 동작에 대해 긴급도를 지정할 수도 있습니다:

class Boards::ListsController < ApplicationController
  urgency :high, [:index, :show]
end

컨트롤러 스펙에서 엔드포인트의 요청 긴급도를 확인하는 사용자 정의 RSpec 매처도 사용할 수 있습니다:

specify do
   expect(get(:index, params: request_params)).to have_request_urgency(:medium)
end

Grape 엔드포인트

API 클래스 전체에 대해 긴급도를 지정할 수 있습니다:

module API
  class Issues < ::API::Base
    urgency :low
  end
end

또한 API 클래스의 특정 동작에 대해 긴급도를 지정할 수도 있습니다:

module API
  class Issues < ::API::Base
      urgency :medium, [
        '/groups/:id/issues',
        '/groups/:id/issues_statistics'
      ]
  end
end

또는 엔드포인트마다 긴급도를 지정할 수도 있습니다:

get 'client/features', urgency: :low do
  # 엔드포인트 로직
end

커스텀 RSpec 매처는 grape 엔드포인트 스펙과도 호환됩니다:

specify do
   expect(get(api('/avatar'), params: { email: 'public@example.com' })).to have_request_urgency(:medium)
end

경고: 네임스페이스 수준에서 긴급도를 지정할 수 없습니다. 이렇게 하면 지시문이 무시됩니다.

오류 예산 할당 및 소유권

이 SLI는 서비스 레벨 모니터링에 사용됩니다. 이는 stage 그룹의 오류 예산에 공급됩니다.

더 많은 정보는 사용자 정의 SLI 정의 및 오류 예산에 편입하는 에픽에서 확인할 수 있습니다. SLI의 엔드포인트는 선언된 기능 범주를 기반으로 한 그룹의 오류 예산에 공급됩니다.

소속된 그룹의 엔드포인트를 확인하려면, 해당 그룹의 그룹 대시보드에서 요청률을 확인할 수 있습니다. 예산 할당 행에서 Puma Apdex 로그 링크를 통해 1초 또는 5초 대상을 충족하지 못하는 요청이 얼마나 있는지 볼 수 있습니다.

대시보드의 내용에 대한 자세한 정보는 스테이지 그룹을 위한 대시보드를, 오류 예산 자체에 대한 정보는 이슈 1365를 확인하세요.