From da4f48630a756279f62b3c452800d69267c30761 Mon Sep 17 00:00:00 2001 From: seo Date: Thu, 2 Jul 2026 12:50:04 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EB=9F=89=20=EC=9B=94=EB=B3=84=20=EB=B3=B4=EC=A0=95=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9D=84=20=EB=B3=B4=EA=B0=95=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- monitor.php | 68 +++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4b981ef..3fc6adf 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,9 @@ Worker 교체나 예외 종료로 `processing`, `ui_timeout_pending` 상태가 - 차량 TCP 실패 reason과 마지막 수신 지연을 확인합니다. - 명령별 rate limit과 감사 로그를 유지합니다. - 통신사 기준 데이터 사용량 보정값을 주기적으로 확인합니다. 2026-06-30 15:15 T world 실측 114.5MB(117,250.5KB) 기준 2026-06 보정값은 통신사 누적 120,064,512 bytes, 통신사 과금 단위 추정 누적 129,148,416 bytes, 배율 0.929663입니다. -- 해당 기준 시각의 로컬 계측 범위는 2026-06-01 00:00:00부터 2026-06-30 15:15:00 직전까지이며, 마지막 로컬 사용량 기록은 2026-06-30 15:14:59입니다. +- 2026-07-02 12:42 T world 실측 6.25MB(6,396KB) 기준 2026-07 보정값은 통신사 누적 6,549,504 bytes, 통신사 과금 단위 추정 누적 7,169,536 bytes, 배율 0.913519입니다. +- 해당 월의 T world 기준점이 있으면 그 월 배율을 우선 사용하고, 아직 기준점이 없는 새 달은 가장 최근 월 배율을 임시로 사용합니다. 새 기준점이 기록되면 해당 월 배율로 다시 계산합니다. +- 2026-06 기준 시각의 로컬 계측 범위는 2026-06-01 00:00:00부터 2026-06-30 15:15:00 직전까지이며, 마지막 로컬 사용량 기록은 2026-06-30 15:14:59입니다. - 데이터 사용량은 TCP payload 합계도 보존하지만 화면의 현재 사용량, 잔여 사용량, 예상 사용량, 예상 요금은 0.5KB 과금 단위로 올림 처리한 통신사형 누적값을 우선 사용합니다. 순수 연결 실패와 마지막 성공 이후 60초를 넘긴 수신 공백은 기존처럼 제외합니다. - 데이터 사용량 집계는 성공 응답 평균을 SQL로 먼저 구하고, 월간/일간 행은 PHP에서 한 줄씩 스트리밍 처리합니다. 기존 보정 조건은 유지하면서 `fetchAll()` 메모리 사용을 제거해 PHP-FPM `memory_limit=128M`에서도 동작하도록 합니다. - 4.95초 timeout 직후에는 사용량 기록이 즉시 생기지 않을 수 있으며, 최대 60초 뒤 늦은 정산 행이 추가될 수 있습니다. diff --git a/monitor.php b/monitor.php index b5b49ac..f7a3d84 100644 --- a/monitor.php +++ b/monitor.php @@ -28,6 +28,7 @@ const RECEIVE_GAP_LIMIT_SEC = 60; // carrier_total_bytes / meter_adjusted_bytes 로 보정 배율을 역산해 통신사 과금 단위 계측값에 적용한다. const DATA_CURRENT_BILLING_USAGE_BYTES = [ '2026-06' => ['total_bytes' => 120064512, 'meter_adjusted_bytes' => 129148416, 'included_bytes' => 104857600, 'coupon_registered_at' => null], + '2026-07' => ['total_bytes' => 6549504, 'meter_adjusted_bytes' => 7169536, 'included_bytes' => 104857600, 'coupon_registered_at' => null], ]; function car_db(): PDO @@ -245,13 +246,14 @@ function monthly_data_usage(PDO $pdo): array } $measuredSeconds = max(1, $now->getTimestamp() - $projectionStart); $currentBilling = current_billing_usage($monthStart->format('Y-m')); - $billingScale = billing_meter_scale($currentBilling); + $billingScaleInfo = billing_meter_scale_info($monthStart->format('Y-m'), $currentBilling); + $billingScale = $billingScaleInfo['scale']; $billingCurrentBytes = (int)round($carrierAdjustedTotalBytes * $billingScale); $projectedBytes = (int)round($carrierAdjustedTotalBytes / $measuredSeconds * $monthSeconds); $billingProjectedBytes = $carrierAdjustedTotalBytes > 0 ? max((int)round($projectedBytes * $billingScale), $billingCurrentBytes) : 0; - $calibration = billing_calibration($currentBilling, $billingScale); + $calibration = billing_calibration($currentBilling, $billingScaleInfo); if ($billingProjectedBytes <= 0) { $billingProjectedBytes = $calibration['projected_total_bytes']; } @@ -315,6 +317,8 @@ function monthly_data_usage(PDO $pdo): array 'projected_service_fee_krw' => floor_krw_10($fixedFeeKrw + $projectedOverFeeKrw), 'billing_estimated_current_bytes' => $billingCurrentBytes, 'billing_meter_scale' => round($billingScale, 6), + 'billing_meter_scale_source' => $billingScaleInfo['source'], + 'billing_meter_scale_source_month' => $billingScaleInfo['source_month'], 'billing_remaining_bytes' => max(DATA_MONTHLY_INCLUDED_BYTES - $billingCurrentBytes, 0), 'billing_over_bytes' => $billingCurrentOverBytes, 'billing_over_fee_raw_krw' => round($billingCurrentOverFeeKrw, 2), @@ -551,17 +555,67 @@ function billing_meter_scale(?array $currentBilling): float return (int)($currentBilling['total_bytes'] ?? 0) / $meterAdjustedBytes; } -function billing_calibration(?array $currentBilling, float $billingScale): array +function billing_meter_scale_info(string $month, ?array $currentBilling): array +{ + $currentScale = billing_meter_scale($currentBilling); + if ($currentBilling && $currentScale > 0) { + return [ + 'scale' => $currentScale, + 'source' => 'current_month_anchor', + 'source_month' => $month, + 'source_billing' => $currentBilling, + ]; + } + + $fallbackMonth = null; + $fallbackBilling = null; + foreach (DATA_CURRENT_BILLING_USAGE_BYTES as $billingMonth => $row) { + if ($billingMonth >= $month || ($row['meter_adjusted_bytes'] ?? 0) <= 0) { + continue; + } + if ($fallbackMonth === null || $billingMonth > $fallbackMonth) { + $fallbackMonth = $billingMonth; + $fallbackBilling = current_billing_usage($billingMonth); + } + } + + $fallbackScale = billing_meter_scale($fallbackBilling); + if ($fallbackBilling && $fallbackScale > 0) { + return [ + 'scale' => $fallbackScale, + 'source' => 'previous_month_anchor', + 'source_month' => $fallbackMonth, + 'source_billing' => $fallbackBilling, + ]; + } + + return [ + 'scale' => 1.0, + 'source' => 'meter_adjusted_usage', + 'source_month' => null, + 'source_billing' => null, + ]; +} + +function billing_calibration(?array $currentBilling, array $billingScaleInfo): array { $estimatedCurrentBytes = $currentBilling ? (int)$currentBilling['total_bytes'] : 0; - $source = $currentBilling ? 'carrier_scaled_meter_usage' : 'meter_adjusted_usage'; + $billingScale = (float)($billingScaleInfo['scale'] ?? 1.0); + $source = $billingScaleInfo['source'] ?? 'meter_adjusted_usage'; + $sourceBilling = $billingScaleInfo['source_billing'] ?? null; + $note = match ($source) { + 'current_month_anchor' => 'T world 현재월 사용량으로 0.5KB 올림 TCP 세션 누적값의 보정 배율을 역산합니다. TCP payload 계측값도 별도로 유지합니다.', + 'previous_month_anchor' => '현재월 T world 기준점이 아직 없어서 가장 최근 월 보정 배율을 임시로 사용합니다. 현재월 기준점이 기록되면 그 배율로 다시 계산합니다.', + default => '통신사형 사용량은 과금 대상 TCP 세션을 0.5KB 단위로 올림 처리합니다. 순수 연결 실패와 긴 수신 공백은 제외합니다.', + }; return [ 'mode' => $source, - 'note' => $currentBilling - ? 'Carrier portal current usage is used to reverse-calculate a billing scale for 0.5KB rounded TCP session usage. Payload metered usage remains available separately.' - : 'Carrier-like usage rounds each billable TCP session to the 0.5KB billing unit. Pure connect failures and longer receive gaps are excluded.', + 'note' => $note, 'current_billing' => $currentBilling, + 'scale_source_billing' => $sourceBilling, + 'billing_meter_scale_source' => $source, + 'billing_meter_scale_source_month' => $billingScaleInfo['source_month'] ?? null, 'billing_meter_scale' => round($billingScale, 6), 'projected_total_bytes' => 0, 'projected_total_mb' => 0.0,