This page contains information related to upcoming products, features, and functionality. It is important to note that the information presented is for informational purposes only. Please do not rely on this information for purchasing or planning purposes. The development, release, and timing of any products, features, or functionality may be subject to change or delay and remain at the sole discretion of GitLab Inc.
Status Authors Coach DRIs Owning Stage Created
proposed devops secure -

GitLab Secret Detection ADR 003: 서브프로세스 내에서 스캔 실행

맥락

spike에서 Pre-receive Secret Detection을 위해 정규식을 평가하기 위해 수행된 과정에서 Ruby에서 RE2 라이브러리를 사용한 결과가 가장 뛰어났습니다. Ruby는 수용할 수 있는 정규식 성능을 가지고 있지만, 언어 제한으로 인해 메모리 소비가 늘어나며, 언어는 멀티 스레딩 및 Ractors(3.1+)를 지원하나 I/O 바운드 작업을 병렬로 실행하기에 적합하지만 CPU 바운드 작업에는 적합하지 않습니다.

임계 경로에서 Pre-receive Secret Detection 기능을 실행하는 것 중 하나는 스캔에 관여되는 정규식 작업으로 인한 메모리 소비, 특히 300개 이상의 정규식 기반 규칙 패턴을 커밋 블롭의 각 라인에서 실행할 때, 메모리가 커밋 블롭의 크기의 약 2-3배로 증가할 수 있습니다1. 스캔 작업이 완료되더라도 차지한 메모리가 가비지 콜렉터를 트리거할 때까지 해제되지 않으며, 결국 서버에서 메모리 부족 현상이 발생할 수 있습니다.

원래의 논의 이슈는 이러한 우려 사항과 더 많은 배경을 다루고 있습니다.

접근 방법

우리는 스캔을 메인 프로세스에서 fork된 별도의 프로세스 내에서 실행함으로써 메모리 소비 문제를 어느 정도 해결할 수 있습니다. 스캔이 완료되면 생성된 프로세스를 종료하여 메모리가 가비지 콜렉터를 트리거하는 대기를 기다리지 않고 즉시 OS로 반환되도록 합니다.

기술적 해결책

프로세스의 라이프사이클을 관리하는 동안 여러 시나리오를 고려해야 합니다. 그러지 않으면 제어할 수 없는 고아 프로세스가 생기며, 메모리를 보존하는 전체 목적을 무너뜨릴 수 있습니다. 우리는 부모 및 자식 프로세스 간의 통신, 종료 신호 처리 및 프로세스 수 제한을 쉽게 제어할 수 있는 Ruby 라이브러리인 Parallel를 통해 이 부담을 완화시킵니다. 또한 병렬성을 지원하여 별도의 문제를 해결하는데에도 이 해결책이 적합합니다.

서브프로세스 내 작업 범위

새 프로세스를 생성하는 것에는 OS에서 추가적인 대기 시간이 발생하므로 어떤 작업이 서브프로세스에서 실행될지 결정하는 것이 중요합니다(파일 디스크립터 복사 등). 예를 들어, 각 블롭에서 스캔을 새로운 서브프로세스에서 실행하는 것은 주 프로세스에서 실행하는 것보다 약 2.5배 느립니다. 그러나 모든 블롭에서 스캔을 단워크플로에서 실행하는 것은 메모리가 빨리 해제되지 않기 때문에 실행이 어렵습니다.

Bucket Approach: 두 가지 극단 사이의 타협점은 누적 크기가 일정한 청크 크기(2MiB in our case) 이상인 모든 블롭을 그룹화한 후 아래에 설명된 것처럼 각 그룹을 별도의 서브프로세스에서 실행하는 것입니다.

Bucketed Subprocesses

추가 내용

  • 서브프로세스 내에서 작업을 실행하는 것은 위에서 언급된 문제에 대한 마법같은 해결책은 아닙니다. 메모리를 가비지 콜렉터를 통해 일반적인 프로세스보다 빠르게 해제함으로써 서버가 메모리에 찔려들지 않도록 지연시킨다고 할 수 있습니다. 심지어 이 접근 방법도 처리해야 할 요청이 너무 많아서 실패할 수 있습니다^.

  • 프로세스 생성에는 항상 라이프사이클의 대기 시간 부담이 따릅니다. 더 작은 커밋에 대해서는 스캔 작업의 대기 시간이 주 프로세스에서 실행될 때보다 느릴 수 있습니다.

  • 현재 요청당 생성되는 프로세스의 병렬성 요소 또는 생성된 프로세스의 수는 현재 5 processes)로 제한되어 있으며, 이상의 대기 중인 요청은 리소스 고갈을 피하기 위해 대기열에 있습니다.

^참조용 임계값이 곧 여기에 추가될 예정입니다.