Skip to content
isdnetworks
Go back

단계마다 숫자를 냈다

상품을 ElasticSearch 2.x에 넣는 PHP 배치가 있었다. 조회하고 걸러 내고 변환하고 색인하는 네 단계로 돌았다.

Table of contents

Open Table of contents

증상 — 끝에만 숫자가 있었다

배치가 끝나고 로그에 남는 것은 마지막 줄 하나뿐이었다. indexed: 48,213 같은 형태였다.

색인된 수가 MySQLCOUNT(*)보다 적을 때 어디서 빠졌는지 알 수 없었다. 걸러 낸 것인지 변환에서 죽은 것인지 색인이 거절한 것인지를 구분할 방법이 없었다.

가능한 방법들

어떻게 볼지를 두고 방법이 둘 보였다. 하나는 단계마다 들어온 수와 나간 수를 로그에 남기는 것이고, 다른 하나는 상품별 처리 상태를 테이블에 적어 두고 나중에 대사하는 것이었다.

MySQL 테이블 방식은 어느 상품이 어느 단계에서 빠졌는지까지 그대로 남길 수 있다. 대신 5만 건마다 쓰기가 생기고 테이블이 하나 늘어난다.

Monolog로 남기는 쪽은 붙이기 쉽고 배치에 주는 부하도 거의 없다. 대신 어느 상품인지는 모르고 몇 건인지만 안다.

고른 것과 이유

두 방법 중 로그 방식을 골라 먼저 붙여 보기로 했다. 지금 알고 싶은 것이 「어느 단계에서 새는가」이지 「어느 상품인가」가 아니었다.

CodeIgniter 배치가 매일 도는데 MySQL에 매번 5만 행을 쓰는 것도 걸렸다. 단계를 특정한 뒤에 필요하면 그때 상세를 붙이기로 했다.

검증 — 앞뒤 숫자를 맞춰 본다

PHP 배치의 각 단계에 들어온 수와 나간 수를 찍게 했다. 앞 단계의 나간 수와 뒤 단계의 들어온 수가 같아야 한다.

fetch    in=52,410 out=52,410
filter   in=52,410 out=50,102
transform in=50,102 out=49,980
index    in=49,980 out=48,213

한 번 돌려 보니 transform 단계에서 122건, index 단계에서 1,767건이 사라지고 있었다. filter는 의도한 제외라 정상이었다.

두 곳 중 index 쪽에서 사라지는 양이 훨씬 컸다. _bulk 응답의 errors: true와 항목별 error를 안 보고 넘기고 있었다.

실패분의 식별자와 사유

건수만으로는 왜 실패했는지 몰라서 실패 항목의 상품 ID와 사유를 Guzzle 응답에서 뽑아 로그에 남겼다. 전체가 아니라 실패한 것만 남기므로 Monolog 파일 양이 크게 늘지 않았다.

사유를 모아 보니 대부분 mapper_parsing_exception이었다. pricelong 매핑이었는데 coerce가 기본으로 켜져 있어서 "12345" 같은 숫자 문자열은 그대로 통과하고, 쉼표가 든 값이나 빈 문자열처럼 숫자로 못 읽는 것만 걸리고 있었다.

정상일 때 각 단계의 숫자가 어떤 모양인지도 README에 적어 뒀다. 그것이 없으면 다음 사람이 48,213을 보고 정상인지 판단할 수 없다.

정리


Share this post on:

Previous Post
스무 곳에 있던 같은 등록 기능
Next Post
전용 테이블을 공용으로 바꾸는 일