현장 장비에서 측정값을 주기적으로 받아 저장하고 그래프로 보여 주고 있었다. 값은 잘 들어오는데 그래프가 이상했다.
선이 앞으로 가다가 뒤로 갔다가 다시 앞으로 오는 구간이 있었다.
Table of contents
Open Table of contents
값이 순서대로 안 온다
받은 순서대로 저장하고 있었는데 저장된 것을 보니 이랬다.
받은 순서 측정 시각
1 10:00:00
2 10:00:10
3 10:00:30 ← 20초 뒤
4 10:00:20 ← 앞의 것보다 이르다
5 10:00:40
넷째가 셋째보다 이른 시각인데 나중에 도착했다. 그 구간을 ORDER BY 로 다시 뽑아 보니 값 자체는 멀쩡하고 도착 순서만 뒤섞인 것이었다.
원인이 하나가 아니었다. 현장 통신이 잠깐 끊기면 장비가 값을 안에 쌓아 뒀다가 복구된 뒤 한꺼번에 보낸다.
장비가 여러 대인데 각자 RTC 가 조금씩 다른 것도 있었다. 중간 장비를 거치면서 순서가 섞이기도 했다.
원인 — 받은 순서와 잰 순서
받은 순서와 측정 시각은 다르다. 받은 시각을 그대로 INSERT 하도록 짠 것이 문제의 뿌리였다.
받은 순서대로 들어오는 것이 정상이고 뒤집힌 것이 예외라고 생각했다. 실제로는 현장 통신이 끊기는 것이 예외가 아니라 일상이었다.
한 값에 시각이 두 개 붙는다는 것도 그때 정리됐다.
| 뜻 | |
|---|---|
| 측정 시각 | 장비가 잰 시점 |
| 수신 시각 | 서버에 도착한 시점 |
둘이 다를 수 있다는 것을 코드가 알아야 했다. 그래서 measured_at 과 received_at 으로 열을 나눠 두 값을 따로 들고 있게 했다.
어느 시각을 기준으로 쓸 것인가
처음에는 received_at 하나만 썼다. 서버 시계 하나만 보면 되니 다룰 것이 적다.
그런데 통신이 30분 끊겼다가 복구되면 30분치가 전부 지금으로 기록된다. 그래프에는 30분짜리 공백이 생기고 한 지점에 값이 뭉친다.
그래서 장비가 RTC 에서 읽어 보내는 measured_at 을 기준으로 바꿨다. 대신 그 시계가 틀리면 값이 틀린 자리에 들어가는데 그것은 감수하기로 했다.
received_at 도 버리지 않고 함께 저장한다. TIMESTAMPDIFF 로 두 열의 차이를 재면 얼마나 늦게 왔는지가 나오므로 그것으로 통신 상태를 본다.
차이가 큰 장비를 세어 보면 어느 현장의 망이 불안정한지가 나온다. 원래 목적과 무관하게 붙여 둔 값이 감시 지표가 됐다.
늦게 온 값을 언제까지 받을지 정했다
시간 순으로 저장하는 구조라 뒤늦게 온 값을 중간에 끼워 넣게 된다. 그러면 한 시간 뒤에 온 값도 받을 것인지 하루 뒤에 온 값도 받을 것인지를 정해야 한다.
정하지 않으면 언제 온 값이든 계속 받아야 하고 이미 만든 통계를 계속 다시 만들게 된다.
측정 시각 기준 1시간 이내 → 정상 저장
1시간 ~ 24시간 → 저장하되 늦음 표시
24시간 초과 → 버리고 기록만 남김
숫자에 확실한 근거가 있는 것은 아니다. 현장 통신이 끊겨도 대개 한 시간 안에 복구되고 하루가 넘은 값은 지금 넣어도 쓸 데가 없다고 봤다.
버리는 쪽도 기록은 남긴다. 그런 값이 얼마나 오는지를 알아야 나중에 이 선을 다시 정할 수 있다.
요약은 지난 구간부터 만든다
원본 값이 10초에 하나씩 쌓이므로 한 달치면 26만 개다. 그대로 그리면 화면이 느려서 AVG() 로 1분 단위 평균을 미리 만들어 두기로 했다.
여기서 늦게 오는 값과 부딪혔다. 10시에서 10시 1분까지의 평균을 만들어 뒀는데 그 구간 값이 나중에 도착하면 그 평균은 틀린 값이 된다.
지금은 이렇게 하고 있다.
- 요약은 10분 지난 구간부터 만든다. 그 사이에 오는 값은 원본에만 들어간다
- 늦게 온 값이 이미 요약된 구간이면 그 구간만
DELETE하고 다시 넣는다 - 다시 계산했다는 것을 기록에 남긴다
10분이라는 값도 근거가 약하다. 관찰해 보니 늦게 오는 값의 대부분이 10분 안에 들어와서 그렇게 잡았다.
다시 계산한 것을 기록에 남기는 이유는 통계가 바뀐 시점을 알아야 해서다. 어제 본 숫자와 오늘 본 숫자가 다르면 그 기록을 보고 설명할 수 있다.
주의 — 아직 못 푼 것
장비의 RTC 를 어떻게 맞출지가 남았다. 지금은 장비가 보내는 시각을 그냥 믿고 있어서 그 RTC 가 틀어져 있으면 값도 틀린 자리에 간다.
값이 아예 안 온 것과 늦게 오는 것을 구분하기 어려운 것도 남았다. 지금은 둘 다 빈 구간으로 보이고 시간이 지나야 하나는 채워지고 하나는 안 채워진다는 것을 안다.
다시 계산이 계속 늘어나면 어떻게 되는지도 모르겠다. 지금은 늦게 오는 값이 적어서 견디는데 현장이 늘면 다시 계산이 계속 돌 것 같다.
정리
- 받은 순서와 측정 시각은 다르다
- 통신이 끊겼다 복구되면 값이 몰아서 온다
- 한 값에
measured_at과received_at둘이 붙는다는 것을 코드가 알아야 한다 - 수신 시각으로 저장하면 공백과 뭉침이 생겨 실제와 달라진다
measured_at을 기준으로 쓰고received_at도 같이 저장한다TIMESTAMPDIFF로 잰 두 열의 차이가 통신 상태 지표가 된다- 늦게 온 값을 언제까지 받을지 세 구간으로 정한다
- 요약은 지난 구간부터 만들고 늦은 값이 오면 그 구간만
DELETE하고 다시 넣는다 - 다시 계산한 기록을 남겨야 바뀐 숫자를 설명할 수 있다