주소 검색 API 요금이 예상보다 많이 나왔다는 말을 들었다. 고지서에는 총액만 찍혀 있어서 무엇 때문에 늘었는지는 알 수 없었다.
Table of contents
Open Table of contents
상황 — 무엇이 얼마나 부르는지 셌다
부르는 자리마다 로그를 남기게 했다.
error_log('[api] addr search: ' . $keyword);
하루 돌리고 세어 봤다.
$ grep "addr search" /var/log/app.log | wc -l
41,882
wc -l 로 세니 하루 4만 번이었다. 회원 가입이 하루 200건인데 4만 번은 이상했다.
무엇이 부르는지도 봤다.
$ grep "addr search" /var/log/app.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head
8,220 서울
5,104 경기
3,882 부산
uniq -c 로 묶어 보니 같은 검색어가 반복되고 있었다. jQuery 쪽을 열어 보니 글자를 칠 때마다 부르고 있었다.
$('#keyword').keyup(function() { searchAddress(this.value); });
keyup 마다 부르니 「서울시청」을 치면 네 번 나간다. 가입한 사람 수보다 호출 수가 훨씬 많았던 이유가 거기 있었다.
부르는 횟수를 줄였다
입력이 멈춘 뒤에 한 번만 부르게 했다.
var timer;
$('#keyword').keyup(function() {
clearTimeout(timer);
var v = this.value;
if (v.length < 2) return;
timer = setTimeout(function() { searchAddress(v); }, 400);
});
clearTimeout 으로 앞의 예약을 지우고 400밀리초 뒤에 부른다. 두 글자 미만은 아예 안 부른다. 이것만으로 4만 번이 6천 번이 됐다.
같은 검색어가 반복되니 결과도 담아 뒀다.
$key = 'addr:' . md5($keyword);
$hit = $cache->get($key);
if ($hit !== false) return $hit;
$result = callAddressApi($keyword);
$cache->set($key, $result, 86400);
return $result;
md5 로 키를 만들고 86400 초를 뒀다. 주소는 자주 안 바뀌기 때문이다. 담아 둔 것에서 답하면 그 요청은 밖으로 안 나가고 6천 번이 900번이 됐다.
안에서 답할 수 있는 것
900번 중에서도 흔한 것이 있었다. sort -rn 으로 본 상위 20개가 전체의 40%였고 시·도 이름 같은 것이었다.
시·도와 시·군·구 목록은 우리가 갖고 있어도 되는 것이었다.
CREATE TABLE region (
code varchar(10) NOT NULL,
sido varchar(30) NOT NULL,
sigungu varchar(30),
PRIMARY KEY (code)
);
region 에서 시·도 단계를 답하고 상세 주소만 외부를 불렀다. 900번이 540번이 됐다.
우리가 들고 있으면 낡는다. 행정구역은 가끔 바뀌기 때문이다.
분기에 한 번 원본과 대조한다.
대조는 전체를 다시 받아 우리 것과 비교하는 방식으로 한다.
날짜를 정해 두지 않으면 안 하게 되므로 달력에 넣었다.
줄인 것이 유지되는지 봤다
다시 늘 때 알 수 있게도 했다.
$today = $db->count("SELECT COUNT(*) FROM api_call_log WHERE api='ADDR' AND at >= ?", $todayStart);
if ($today > 1000) {
error_log('[api] 주소 검색 호출이 오늘 ' . $today . '건. 평소 500건 안팎.');
}
api_call_log 를 세어 평소 값을 알고 있으니 이상한 것을 안다. 고지서를 받고 나서 아는 것은 한 달이 지난 뒤의 일이다.
한 달 뒤에 다시 셌다.
6월 540건/일
7월 620건/일
region 을 넣은 뒤로 조금 늘었지만 회원이 는 만큼이라 정상 범위였다. 줄이고 끝내지 않고 유지되는지 본 것인데 화면을 고치다가 담아 두는 것을 빠뜨리면 다시 는다.
정리
- 요금이 나오면 무엇을 얼마나 부르는지 센다. 고지서 총액으로는 모른다
- 같은 것을 반복해서 부르고 있는지 본다
- 화면에서
keyup마다 부르는 자리가 있는지 본다 clearTimeout으로 멈춘 뒤에 한 번만 부르고 짧은 것은 안 부른다- 결과를 담아 둔다. 자주 안 바뀌는 것은 오래 둬도 된다
- 안에서 답할 수 있는 것을 가른다. 흔한 것 몇 개가 큰 비중을 차지한다
- 들고 있으면 낡는다. 언제 갱신할지 정해서 달력에 넣는다
- 평소 값을 알고 있으면 늘어난 것을 바로 안다
- 줄이고 나서 유지되는지 다시 센다