Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby 스크립트의 프로세스 이름 변경하기 — top과 ps에 표시되는 이름 바꾸는 방법

Linux나 macOS에서 프로그램을 실행하면 항상 하나의 프로세스 안에서 동작합니다. 그리고 모든 프로세스에는 고유한 이름이 있습니다. 이 이름은 ps, top, htop 같은 명령어를 실행했을 때 화면에 표시되는 것입니다.

Ruby 스크립트의 프로세스 이름 변경하기 — top과 ps에 표시되는 이름 바꾸는 방법 htop은 가장 오른쪽 열에 프로세스 이름을 표시합니다.

기본 프로세스 이름의 한계

기본적으로 프로세스의 이름은 실행 중인 프로그램이 담긴 실행 파일의 이름에서 따옵니다. 대부분의 경우 이 방식이 잘 작동합니다. "less"를 실행하면 프로세스 이름도 "less"가 되는 것이 자연스럽기 때문입니다.

하지만 명령줄에서 Ruby 스크립트를 실행할 때는 기본 프로세스 이름이 큰 도움이 되지 않습니다. 아래 예제에서는 5초간 대기하는 Ruby 스크립트를 실행하고 있습니다. 이때 다른 터미널 창에서 "ps"를 실행해 보면 해당 프로세스의 이름이 "ruby sleep_5_seconds.rb"로 표시됩니다. 여기에 명령줄 인수를 추가하면 인수까지 모두 프로세스 이름에 포함되어, 이름만으로 프로세스를 지정하기가 매우 어려워집니다.

Ruby 스크립트의 프로세스 이름 변경하기 — top과 ps에 표시되는 이름 바꾸는 방법 전체 ruby 명령이 프로세스 이름으로 표시됩니다

프로세스 이름 변경 방법

다행히 Ruby에서는 현재 프로세스의 이름을 아주 간단하게 변경할 수 있습니다. 다음은 수정된 스크립트로, 프로세스 이름을 "sleeper"로 설정합니다.

# `Process.setproctitle()`은 Ruby 2.1 이상에서 사용 가능
# 그 이전 버전에서는 다음을 사용할 수 있습니다:
#   $PROGRAM_NAME = "sleeper"
# 또는
#   $0 = "sleeper"

Process.setproctitle("sleeper")
sleep 5

이제 프로그램을 실행한 뒤 ps로 확인해 보면 프로세스 이름이 "sleeper"로 표시됩니다.

Ruby 스크립트의 프로세스 이름 변경하기 — top과 ps에 표시되는 이름 바꾸는 방법 Ruby에서 프로세스 제목을 변경하면 pstop의 출력 결과가 달라집니다

더 좋은 점은 이제 이름만으로 프로세스를 손쉽게 지정할 수 있다는 것입니다. sleeper가 잠자는 것이 지겨워졌다면 killall sleeper 명령 한 줄로 종료할 수 있습니다.

Ruby 스크립트의 프로세스 이름 변경하기 — top과 ps에 표시되는 이름 바꾸는 방법 killall 명령으로 이름 기반으로 프로세스를 종료할 수 있습니다

프로세스 이름으로 서버 상태 표시하기

프로세스 제목을 변경할 수 있게 된 것의 흥미로운 활용 사례 중 하나는 장시간 실행되는 프로세스의 상태 정보를 표시하는 것입니다. Unicorn을 사용해 본 적이 있다면 다음 출력이 익숙할 것입니다:

\-+= 27185 deply unicorn master -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27210 deply unicorn worker[0] -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27211 deply unicorn worker[1] -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27212 deply unicorn worker[2] -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27213 deply unicorn worker[3] -c simple_unicorn_config.rb -l0.0.0.0:8080

네 개의 자식 프로세스를 가진 Unicorn 인스턴스입니다. 앞서 sleep_5_seconds.rb 예제와 마찬가지로 프로세스 이름에는 프로세스를 시작한 명령어만 표시됩니다.

그런데 만약 상태 줄에 각 워커가 바쁜지(BUSY) 유휴 상태인지 함께 표시된다면 훨씬 유용할 것입니다. 다음과 같이 말이죠:

\-+= 27185 deply unicorn master -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27210 deply unicorn worker[0] -c simple_unicorn_config.rb -l0.0.0.0:8080 BUSY
   |--- 27211 deply unicorn worker[1] -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27212 deply unicorn worker[2] -c simple_unicorn_config.rb -l0.0.0.0:8080
   |--- 27213 deply unicorn worker[3] -c simple_unicorn_config.rb -l0.0.0.0:8080 BUSY

사실 Rack 미들웨어를 사용하면 이 기능을 꽤 쉽게 구현할 수 있습니다. 다음은 그 구현 예시입니다:

class UpdateProcessTitle
  def initialize(app)
    @app = app
  end

  def call(env)
    title = $0
    $0 = $0 + " BUSY"
    status, headers, body = @app.call(env)
    $0 = title
    [status, headers, body]
  end
end

모든 웹 요청마다 프로세스 제목을 설정하는 것이 성능에 어떤 영향을 미치는지는 확실하지 않으므로, 이 내용은 어느 정도 걸러서 받아들이시기 바랍니다. 그래도 꽤 흥미로운 아이디어인 것은 분명합니다.

이 아이디어를 더 발전시킨 구현, 즉 실제 프로덕션 환경에서 사용된 사례를 보고 싶다면 Thomas Varaneckas의 "Overriding Unicorn Worker Process Names"라는 훌륭한 블로그 포스트를 참고해 보세요.