본문 바로가기
C.W.K.
Stream
Lesson 03 of 04 · published

듣고 있다고 그놈인 건 아니야

~14 min · firelink, responder-identity, port-owner, health-check

Level 0식은 재
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"8100 에서 뭔가 듣고 있네. 근데 그게 Ember 야, 아니면 Ember 자리를 차지한 유령이야?"

초록불에 숨은 함정

순진하게 만든 health check 는 이래. 적힌 port 로 연결해보고, 뭐라도 답하면 'running' 이라 적어. 그럴싸한데 조용히 틀렸어. 뭔가 그 port 에 붙어 있다는 것만 알려줄 뿐, 그게 네가 기다린 제품이란 얘긴 아니거든. 지난주에 완전히 안 죽은 옛 서버일 수도 있고, port 를 먼저 잡은 딴 앱일 수도, 임시로 띄운 자리끼움이거나 proxy 이거나, 아무 상관 없는 프로세스일 수도 있어. 뭐가 됐든 순진한 체크는 사실상 없는 서비스에 당당하게 초록불을 켜줘.

누가 답하는지 확인하는 두 가지

Firelink 는 속지 않으려고 두 가지를 봐. 첫째, 그 port 를 누가 쥐고 있나. office 의 launchd 멤버라면, 적힌 localhost port 를 그 job 이 띄운 프로세스가 쥐고 있어야 해. 그냥 열려 있는 것만으론 부족하고. 둘째, health 경로가 자기 이름을 대나. health 경로가 적힌 멤버라면 거기서 기대한 이름이 나와야 해. 응답이 사실상 '응, 나 Ember 야' 라고 말해줘야 하는 거지. 둘 다 통과하면 진짜 도는 거야. 하나라도 어긋나면 Firelink 는 뭐가 안 맞는지 붙여서 unknown 으로 적어. running 이라고 안 하고.

왜 'unknown' 이 정직한 답이냐면

이름 확인이 어긋났다고 'stopped' 라 적지도 않는 걸 봐. 뭔가 답은 하고 있으니까. 그게 맞는 놈이라는 증명이 안 될 뿐이지. 이건 '죽었다'가 아니라 '이게 자기가 말하는 그놈인지 확인이 안 된다' 야. running 이라 하면 거짓말이고, stopped 라 해도 거짓말이야. 뭐가 안 맞는지 붙인 unknown 만이 정직한 답이고, 사람이 '그럼 저 port 엔 대체 뭐가 앉아 있는 거야?' 하고 보러 가게 만드는 것도 그거야.

답이 왔다고 그놈인 게 증명되진 않아. 답한 쪽이 자기가 말하는 그놈인지 확인하고, 확인이 안 되면 'unknown' 으로 낮춰. '뭔가 답했다'와 '맞는 게 답했다'는 다른 사실이야. 연결만 됐다고 건강하다 치는 시스템은 언젠가 진짜 트래픽을 유령한테 보내면서 내내 초록불을 켜고 있을 거야.

Code

누가 답하는지 확인해. 듣고 있다는 걸 믿지 말고·python
def verify_service(member) -> ServiceState:
    if not tcp_listening(member.host, member.port):
        return ServiceState("stopped")            # nothing there at all

    # Something is listening. That is NOT enough. Prove it's the right thing.

    # Check 1: port-owner — is the port held by this launchd job's process tree?
    if member.launchd_owned:
        owner = port_owning_pid(member.port)
        if owner not in process_tree(member.launchd_label):
            return ServiceState("unknown", why="port owned by a foreign process")

    # Check 2: health-identity — does the health path say it's really this member?
    if member.health_check:
        body = http_get(member.health_check.path)
        if member.health_check.identity_substring not in body:
            return ServiceState("unknown", why="health response identity mismatch")

    return ServiceState("running")                 # earned it: bound AND proven

# A leftover process on :8100 fails check 1 or 2 -> reported 'unknown',
# never a green 'running'. The port being open is not the answer.

External links

Exercise

네가 믿고 쓰는 health check 를 하나 잡고 물어봐. 여기서 '살아 있음' 이 정확히 뭘 뜻해? port 가 연결을 받는다는 거야, HTTP 200 이 돌아온다는 거야, 아니면 응답이 맞는 서비스랑 버전임을 증명한다는 거야? 약한 체크는 멀쩡하다는데 진짜 서비스는 없는 상황을 구체적으로 그려봐. 안 죽은 옛 프로세스, proxy, 200 을 돌려주는 점검 페이지 같은 걸로. 그다음 그걸 잡아낼 확인 절차를 적어봐.
Hint
단계가 있어. port 열림 < 연결 받음 < HTTP 200 < 응답에 이름이나 버전이 찍혀 있음. '모니터링이 놓쳤다' 는 장애는 대개 'port 가 열려 있었다' 보다 강한 걸로 안 봤던 경우야. 그냥 있느냐가 아니라 그놈이 맞느냐까지 올라가.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.