애플리케이션 제한 개발
GitLab v19.4요약
이 문서는 GitLab에 애플리케이션 제한을 추가하려는 기여자를 위한 개발 가이드입니다. 먼저 GitLab 티어별로 어떤 제한이 설정되는지 정보를 모으고 결정해야 합니다. 제한 유형에 맞는 페이지에 문서를 추가합니다. 애플리케이션 제한 도입에 관한 가이드도 있습니다.
이 문서는 GitLab에 애플리케이션 제한을 추가하려는 기여자를 위한 개발 가이드입니다.
문서화#
먼저 GitLab 티어별로 어떤 제한이 설정되는지 정보를 모으고 결정해야 합니다. 다른 구성원과 협의해 그 제한을 문서화하고 공유합니다.
제한 유형에 맞는 페이지에 문서를 추가합니다.
- 플랜 제한 및 기타 인스턴스 전역 제한.
- 다음과 같은 속도 제한:
애플리케이션 제한 도입에 관한 가이드도 있습니다.
플랜 제한 구현#
plan_limits 테이블은 셀 범위 구성입니다. 각 셀은 이 테이블의 사본을 따로 가지며 제한은
셀 간에 이전되지 않습니다. 새 셀은 각 제한의 칼럼 기본값으로 시작하고, 관리자는
관리자 Plan Limits API로 셀별 제한을 조정합니다. 따라서 모든
새 플랜 제한은 그 API로 설정할 수 있어야 합니다. 그렇지 않으면
새 제한은 각 셀에서
칼럼 기본값만 갖게 됩니다.
셀 간에 값이 일관되게 유지되어야 하는 플랜 제한은 도입하지 않습니다.
plan_limits는 셀 로컬이므로 동기화를 유지할 방법이 없습니다.
데이터베이스 플랜 제한 삽입#
plan_limits 테이블에 새 칼럼을 만들고 제한 값을 삽입합니다.
마이그레이션 스크립트 파일은 두 개로 나누어 만들기를 권장합니다.
-
plan_limits테이블에 원하는 제한을 나타내는 null 이 아닌 기본값을 가진 새 칼럼을 추가합니다. 예를 들면 다음과 같습니다.add_column(:plan_limits, :project_hooks, :integer, default: 100, null: false)플랜 제한 항목이
0이면 제한이 활성화되지 않았다는 뜻입니다. 이 설정은 특별하고 문서화된 상황에서만 사용합니다. -
(선택 사항)
create_or_update_plan_limit마이그레이션 헬퍼를 사용해 각 수준을 원하는 제한으로 조정하는 데이터베이스 마이그레이션을 만듭니다. 이 마이그레이션의 플랜은 GitLab.com의 플랜과 일치해야 합니다. 플랜이 누락되면 해당 플랜 고객은 기본 제한을 적용받게 되며, 그 값은0(무제한)일 수 있습니다.예를 들면 다음과 같습니다.
class InsertProjectHooksPlanLimits < Gitlab::Database::Migration[2.1] def up create_or_update_plan_limit('project_hooks', 'default', 0) create_or_update_plan_limit('project_hooks', 'free', 10) create_or_update_plan_limit('project_hooks', 'premium', 30) create_or_update_plan_limit('project_hooks', 'premium_trial', 30) create_or_update_plan_limit('project_hooks', 'ultimate', 100) create_or_update_plan_limit('project_hooks', 'ultimate_trial', 100) create_or_update_plan_limit('project_hooks', 'ultimate_trial_paid_customer', 100) create_or_update_plan_limit('project_hooks', 'opensource', 100) end def down create_or_update_plan_limit('project_hooks', 'default', 0) create_or_update_plan_limit('project_hooks', 'free', 0) create_or_update_plan_limit('project_hooks', 'premium', 0) create_or_update_plan_limit('project_hooks', 'premium_trial', 0) create_or_update_plan_limit('project_hooks', 'ultimate', 0) create_or_update_plan_limit('project_hooks', 'ultimate_trial', 0) create_or_update_plan_limit('project_hooks', 'ultimate_trial_paid_customer', 0) create_or_update_plan_limit('project_hooks', 'opensource', 0) end end일부 플랜은 GitLab.com 에만 존재합니다. 존재하지 않는 플랜에 대해서는 아무 동작도 하지 않습니다.
마이그레이션에서 GitLab.com 에만 제한을 설정하고 다른 인스턴스는 기본 제한을 사용하게 하려면
#up과#down메서드 시작 부분에return unless Gitlab.com?을 추가해 다른 인스턴스에서는 마이그레이션이 아무 동작도 하지 않도록 합니다. -
관리자 Plan Limits API를 통해 새 칼럼을 노출합니다.
- 관리자가 셀별로 제한을 조정할 수 있도록
PUT /application/plan_limits(lib/api/admin/plan_limits.rb)에optional파라미터로 추가합니다. - 제한 값을 다시 읽을 수 있도록 응답 엔티티
(
lib/api/entities/plan_limit.rb)에 추가합니다. - Plan Limits API 페이지에 해당 속성을 문서화합니다.
- 관리자가 셀별로 제한을 조정할 수 있도록
플랜 제한 유효성 검사#
현재 제한 가져오기#
현재 제한은 프로젝트나 네임스페이스를 통해 확인할 수 있습니다. 예를 들면 다음과 같습니다.
project.actual_limits.project_hooks
현재 제한 확인#
현재 제한을 초과했는지 확인하는 메서드로 PlanLimits#exceeded?가 있습니다.
ActiveRecord 객체나 Integer 중 하나를 사용할 수 있습니다.
레코드 수가 정의된 제한을 초과하지 않는지 확인합니다. 예를 들면 다음과 같습니다.
project.actual_limits.exceeded?(:project_hooks, ProjectHook.where(project: project))
숫자가 정의된 제한을 초과하지 않는지 확인합니다. 예를 들면 다음과 같습니다.
project.actual_limits.exceeded?(:project_hooks, 10)
Limitable concern#
Limitable concern
을 사용하면 모델이 제한을 초과하지 않는지 검증할 수 있습니다. 현재 모델의 레코드 수가
정의된 제한을 초과하지 않도록
보장합니다.
검증 대상 객체의 제한 범위를 지정해야 하며, 제한 이름이 모델 이름의 복수형과 다르면 제한 이름도 지정해야 합니다.
class ProjectHook
include Limitable
self.limit_name = 'project_hooks' # Optional as ProjectHook corresponds with project_hooks
self.limit_scope = :project
end
모델을 테스트하려면 공유 예제를 포함할 수 있습니다.
it_behaves_like 'includes Limitable concern' do
subject { build(:project_hook, project: create(:project)) }
end
인스턴스 전역 제한 테스트#
인스턴스 전역 기능에는 라이선스가 할당되지 않으므로 항상 default 플랜을
사용합니다.
class InstanceVariable
include Limitable
self.limit_name = 'instance_variables' # Optional as InstanceVariable corresponds with instance_variables
self.limit_scope = Limitable::GLOBAL_SCOPE
end
구독 플랜#
GitLab Self-Managed:
default: 모든 사용자.
GitLab.com:
default: 시스템 전역 기능 전체.free: Free 구독을 사용하는 네임스페이스와 프로젝트.premium: Premium 구독을 사용하는 네임스페이스와 프로젝트.premium_trial: Premium Trial 구독을 사용하는 네임스페이스와 프로젝트.ultimate: Ultimate 구독을 사용하는 네임스페이스와 프로젝트.ultimate_trial: Ultimate Trial 구독을 사용하는 네임스페이스와 프로젝트.ultimate_trial_paid_customer: Premium 구독 상태에서 Ultimate를 30일간 체험 중인 네임스페이스와 프로젝트.opensource: GitLab Open Source 프로그램에 참여 중인 네임스페이스와 프로젝트.
GitLab.com에는 구독이 없는 early_adopter 플랜이 있습니다.
test 환경에는 플랜이 없습니다.
Rack::Attack을 사용한 속도 제한 구현#
GitLab은 Rack 요청을 스로틀링하기 위해 Rack::Attack 미들웨어를 사용합니다.
이는 Rails 컨트롤러, Grape 엔드포인트, 그 밖의 모든 Rack 요청에 적용됩니다.
새 스로틀을 추가하는 과정은 대략 다음과 같습니다.
ApplicationSetting모델의 rate_limits JSONB 칼럼에 새 필드를 추가합니다.- rate_limits 칼럼의 JSON 스키마 검증기를 갱신합니다.
Gitlab::RackAttack과Gitlab::RackAttack::Request를 확장해 새 속도 제한을 구성하고, 대상 요청에 적용합니다.app/views/admin/application_settings/_ip_limits.html.haml의 Admin 영역 양식에 새 설정을 추가합니다.- User and IP rate limits와 Application settings API에 새 설정을 문서화합니다.
- GitLab.com의 속도 제한을 구성하고 GitLab.com의 속도 제한에 문서화합니다.
구현 세부 사항은 다음 과거 이슈를 참고합니다.
Gitlab::ApplicationRateLimiter를 사용한 속도 제한 구현#
이 모듈은 특정 동작을 스로틀링하는 데 사용할 수 있는 사용자 지정 속도 제한기를 구현합니다.
미들웨어 수준에서 동작하는 Rack::Attack 및 Rack::Throttle과 달리,
컨트롤러나 API 수준에서 사용할 수 있습니다.
컨트롤러에서의 사용법은 CheckRateLimit concern을 참고합니다. 코드의 다른 부분에서는
Gitlab::ApplicationRateLimiter 모듈을 직접 호출할 수 있습니다.
새 제한을 문서화하는 것을 잊지 않습니다.
차기 속도 제한 아키텍처#
2022년 5월부터 미래 지향적인 속도 제한 아키텍처를 사용하는 애플리케이션 제한 프레임워크의 다음 반복 작업을 시작했습니다.
현재 새 요구 사항을 정의하고 차기 아키텍처를 설계하고 있습니다. 새 제한을 추가하기 위한 새로운 기능이 필요하다면 지금 직접 구현하기보다 Rate Limiting Architecture Working Group에 기여하는 방안을 검토합니다.
차기 속도 제한 아키텍처에 넣을 수 있는 기능의 예는 다음과 같습니다.
- 네임스페이스별·플랜별로 제한을 정의하고 재정의할 수 있게 합니다.
- 어떤 제한이 구현되어 있고 기본값이 무엇인지에 관한 문서를 자동으로 생성합니다.
- 찾아보고 살펴볼 수 있는 한곳에서 제한을 정의합니다.
- 소프트 제한과 하드 제한을 두고, 제한에 가까워지면 사용자에게 알리는 기능을 지원합니다.