MSA (Micro Service Architecture) 운영 시에 Eureka에 등록된 서비스 중 일부를 중지했음에도 해당 서비스의 프로세스가 시스템에서 정상적으로 종료되지 않는 경우, 시스템 안정성과 서비스 관리에 문제가 생길 수 있다. 일종의 좀비 프로세스인데 이를 해결하기 위해 프로세스 관리 및 Eureka의 Service Registry에 대해서 같이 알아보자.
Eureka에 등록된 서비스의 중지 및 좀비 프로세스 관리
1. 좀비 프로세스란?
- 서비스 중단 이후에도 해당 프로세스가 정상적으로 종료되지 않고 메모리에 남아있는 상태
- 이러한 좀비 프로세스는 시스템 자원을 불필요하게 소비하며, 서비스 재시작이나 Eureka의 Service Registry와의 불일치 문제를 초래할 수 있다.
2. 프로세스 확인 및 종료 방법
docker stop container를 통해 서비스 중지 이후에도 Eureka Service Registry에 프로세스가 남아있는지 확인해야 하며 만약 남아 있다면 강제로 종료(kill)해야 한다.
(강제 종료하면 Eureka를 다시 실행해도 다시 Eureka 서비스 레지스트리에 등록되지 않을 겁니다.)
리눅스 명령어를 이용한 확인 및 종료
- 프로세스 검색:
ps aux | grep <service-name>
<service-name>
을 실행 중인 서비스 이름으로 대체합니다.- 관련된 프로세스 목록이 출력됩니다.
- 프로세스 종료:
kill -TERM <PID>
<PID>
는 종료할 프로세스 ID입니다.-TERM
은 정상적인 종료를 시도하며, 종료되지 않을 경우-KILL
옵션을 사용할 수 있습니다:kill -KILL <PID>
Python 스크립트를 활용한 자동화
생각보다 이런 버그가 잘 일어나고 이런 상황이 발생하면 빠르게 처리해야 하기 때문에 이를 대비해서 미리 스크립트를 짜서 자동화하는 것이 필요하다. 저는 Python 스크립트를 애용해서 해당 부분은 Python 스크립트로 짜봤다.
import os
import signal
import subprocess
# 특정 서비스 이름으로 실행 중인 프로세스 찾기
service_name = "my_service_eco"
processes = subprocess.check_output(['ps', 'aux']).decode('utf-8')
matching_processes = [line for line in processes.split('\n') if service_name in line]
# 프로세스 종료
for line in matching_processes:
try:
pid = int(line.split()[1]) # PID 추출
os.kill(pid, signal.SIGTERM) # 정상 종료 시도
print(f"프로세스 {pid} 종료 성공")
except Exception as e:
print(f"프로세스 종료 실패: {e}")
Eureka 서비스 레지스트리 정리
Eureka의 Service Registry에 등록된 서비스는 기본적으로 각 인스턴스에서 정기적으로 heartbeat를 전송하여 상태를 유지한다. 하지만 말씀 드렸다시피 서비스가 중단되었음에도 유레카 레지스트리에 정보가 남아있어 자원을 엉뚱하게 소비하는 경우가 있다. 이번에는 운영 체제 명령어가 아닌 어플리케이션 단에서 처리할 수 있는 방법을 얘기해보겠다.
1. Eureka의 자동 정리 메커니즘 활용
- Eureka는 기본적으로 일정 시간 동안 heartbeat를 수신하지 않으면 해당 인스턴스를 “DOWN” 상태로 변경하고 제거한다.
- 이를 가속화하려면
application.properties
또는application.yml
에 다음 설정을 추가:eureka.instance.lease-expiration-duration-in-seconds=30 eureka.instance.lease-renewal-interval-in-seconds=10
lease-expiration-duration-in-seconds
: 인스턴스가 제거되기까지의 대기 시간(초).lease-renewal-interval-in-seconds
: 인스턴스가 heartbeat를 전송하는 주기(초).
2. REST API를 통한 수작업 삭제
서비스가 자동으로 제거되지 않을 경우, Eureka의 REST API를 통해 Service Registry에서 인스턴스를 수동으로 삭제할 수 있다. 이 방법이 간편하면서도 확실해서 보통 MSA 운영시 이 방법을 가장 많이 사용했던 것 같다.
REST 요청 형식
DELETE http://<EUREKA-SERVER>:<PORT>/eureka/apps/<APP-ID>/<INSTANCE-ID>
<EUREKA-SERVER>
: Eureka 서버 주소.<APP-ID>
: 삭제할 애플리케이션의 이름.<INSTANCE-ID>
: 삭제할 인스턴스 ID.
예시
DELETE http://localhost:8761/eureka/apps/FIRST-SERVICE/FIRST-SERVICE-007
3. Eureka 재실행과 Service Registry
Eureka를 재시작하더라도, 중단된 서비스가 다시 등록되지 않으며, 기존에 남아있는 좀비 레지스트리는 제거되지 않을 수 있기에 따라서, 서비스 중단 시 프로세스 종료와 Service Registry 정리를 동시에 수행하는 것이 중요함을 강조한다. 이를 위해 앞서 말한 대로 정상으로 종료 되었는지 확인하고 만약 제거되지 않았을 경우 운영단이든 어플리케이션단이든 간에 어느 한 곳을 선택해서 반드시 제거 하여Eureka를 관리하길 바란다.
권장 관리 프로세스
- 서비스 중지 시
- 서비스 프로세스를 확인하고 정상 종료되었는지 검증.
- 종료되지 않은 프로세스는
kill
명령어 또는 스크립트를 사용하여 종료.
- Eureka 정리
- 서비스 종료와 동시에 Eureka REST API를 사용해 관련 인스턴스를 제거.
- 자동 제거가 필요한 경우
lease-expiration-duration
설정을 최적화.
- 주기적 점검
- 시스템 상태를 정기적으로 점검하고, 남아있는 좀비 프로세스와 Eureka 레지스트리를 확인.
결론
- 좀비 프로세스는 서비스 중단 이후 시스템 안정성을 저하시키는 요인이며, 이를 방지하려면 서비스 프로세스 종료와 Eureka 레지스트리 정리를 신속히 수행한다.
- Eureka의 자동 메커니즘과 REST API를 활용하여 레지스트리를 효과적으로 관리한다.
- 주기적인 모니터링과 설정 최적화를 통해 시스템의 성능과 신뢰성을 유지하여 반드시 원활한 서비스에 지장이 없도록 하여야한다.
이러한 내용이 포함된 관리 프로세스를 도입하면, 서비스 중단 및 관련 이슈를 보다 체계적으로 처리할 수 있다. MSA 운영을 하면서 겪었던 이슈 중 하나를 중심으로 적었는데 갑자기 드는 생각이 MSA 아키텍쳐는 장점은 참 많은데 참 손이 많이 가는 것 같다. 사실 이 뿐 아니라 Docker 자체 좀비 프로세스 이슈도 있으며 Gateway 이슈도 있었다. 결국 시스템이 완전히 안정화 되기까지 제품 완성 이후에도 상당히 시간이 필요할 것으로 보인다. 이 번 내용은 그 과정에서 반드시 필요한 상황일 것이다.