# 동기화 성능과 서버 배려

v1.10.0 신규 기능

이 페이지는 **WCPOS v1.10.0**에서 도입된 동기화 엔진을 설명합니다. 엔진이 기술적으로 어떻게 작동하는지는 [동기화 엔진의 작동 방식](/ko/reference/sync-engine.md)에서 먼저 확인하세요.

대부분의 WCPOS 스토어는 공유 PHP 호스팅에서 실행됩니다. 소수의 PHP 워커, 모든 REST 요청마다 이루어지는 전체 WordPress 부트스트랩, 순간적인 요청 폭주를 제한하는 보안 플러그인이 있는 환경입니다. 클라이언트가 공짜라고 여기는 요청은 스토어프런트를 느리게 만들고, 속도 제한에 걸리며, 계산원 자신의 트래픽과 경쟁합니다. 게다가 이는 운영 중인 모든 계산대와 브라우저 탭의 수만큼 곱해집니다.

v1.10.0 동기화 엔진은 이를 나중에 고려할 사항이 아니라 설계 제약으로 취급합니다. **판매자의 호스팅을 보호하는 것은 동기화 엔진의 업무 중 하나입니다.** 이 페이지에서는 엔진이 따르는 규칙과 그 근거가 되는 측정값을 설명합니다.

## 네 가지 상시 규칙[​](#the-four-rules "네 가지 상시 규칙으로 직접 링크")

엔진의 모든 예약 동기화 동작은 네 가지 불변식의 지배를 받습니다:

1. **비용은 카탈로그 크기가 아니라 변경된 양에 비례합니다.** 대량 가져오기 전에는 언제나 저렴한 다이제스트나 조기 종료 확인이 선행됩니다. 변경 사항이 없는 제품 50,000개 스토어를 동기화 상태로 유지하는 비용은 변경 사항이 없는 제품 500개 스토어와 거의 같습니다.
2. **무제한 확산은 없습니다.** 모든 백그라운드 레인은 실행당 요청 상한을 선언하며, 이는 자동화된 테스트로 강제됩니다. 큰 작업은 재개 가능한 커서와 함께 제한된 배치로 실행되므로, 일괄 처리가 한꺼번에 몰리지 않고 일정에 걸쳐 분산됩니다.
3. **유지 관리는 계산원을 방해하지 않습니다.** 계산대가 판매를 시작할 수 있게 만드는 요청이 먼저 실행되고, 무결성 감사와 백그라운드 사전 준비 작업은 그 이후 유휴 시간에 실행됩니다.
4. **부하가 걸리면 유지 관리가 먼저 물러납니다.** 서버가 부하 신호를 보내면 엔진은 계산원이 사용하는 기능에 손대기 전에 자신의 백그라운드 작업부터 늦춥니다.

## 동기화가 서버에 미치는 비용[​](#request-budgets "동기화가 서버에 미치는 비용으로 직접 링크")

정상 상태의 비용은 **스토어 상태 → 성능**에서 기기별로 선택하는 **동기화 프리셋**이 결정합니다:

| 프리셋       | 확인 간격 | 요청당 레코드 수 | 하루 명목 확인 횟수 |
| ------------ | --------- | ---------------- | ------------------- |
| 에코         | 5분       | 25               | 288                 |
| 균형(기본값) | 60초      | 50               | 1,440               |
| 실시간       | 10초      | 75               | 8,640               |

두 항목 모두 중요하며, 공유 호스팅에서 실제로 비용을 발생시키는 것은 대개 페이지 크기입니다. 레코드가 많은 페이지는 실제 서버 시간을 소모하고, 간격은 그 비용을 곱할 뿐입니다. 최대치인 100개 레코드 페이지를 사용하는 프리셋은 없으며, 이는 사용자 지정 슬라이더(간격 5초~~5분, 레코드 10~~100개)로만 도달할 수 있습니다.

프리셋 외에 다음 사항이 적용됩니다:

* **유휴 상태의 확인은 비용이 낮습니다.** 엔진이 조건부 요청을 보내므로 변경이 없는 확인은 본문 없는 `304 Not Modified` 하나로 응답됩니다. 여전히 요청 한 건이지만 페이로드가 없고 서버 작업도 최소입니다.
* **확인 간격에는 ±20%의 지터가 적용되므로**, 여러 대의 계산대가 한꺼번에 몰리지 않고 요청을 분산합니다.
* **유휴 계산대는 감쇠합니다.** 10분 동안 조작이 없으면 주기가 느려지고, 바코드 스캔을 포함한 어떤 활동이든 발생하면 즉시 원래대로 돌아옵니다.
* **백그라운드 유지 관리에는 상한이 있습니다.** 편차가 없는 무결성 확인은 저렴한 집계 페이지 몇 건만 사용하고 상세 조회는 **전혀** 하지 않습니다. 서버와 일치함이 입증된 버킷은 아예 건너뜁니다. 편차가 발견되면 상세 조회는 **실행당 두 건**으로 제한되며, 한꺼번에 처리하는 대신 저장된 커서로 이어서 진행합니다. 전체 삭제 감사는 **실행당 11건**, 다이제스트 사전 준비는 실행당 5개 청크로 제한됩니다. 이 상한들은 코드에 선언되어 있고 CI에서 강제됩니다.

앱에 표시되는 “하루 요청 수”는 명목값입니다

스토어 상태는 설정된 간격을 바탕으로 *하루 약 N건의 요청* 추정치를 산출합니다. 이를 상한이나 예측이 아니라 명목 확인 빈도로 이해하세요. ±20% 지터는 실제 횟수를 양방향으로 움직이고, `304`도 요청 한 건으로 계산됩니다. 유휴 감쇠는 60초 하한보다 빠른 프리셋에서만 횟수를 줄이며, 기본값인 균형 프리셋을 더 느리게 만들지는 않습니다.

## 서버가 힘들어할 때의 백오프[​](#server-pressure "서버가 힘들어할 때의 백오프으로 직접 링크")

엔진이 받는 모든 응답은 스토어별 부하 모니터로 전달됩니다. 모니터는 다음에 반응합니다:

* HTTP `429`(즉시),
* 반복되는 `5xx` 오류 또는 전송 실패(1분 이내 3회),
* 지속적인 지연(응답 시간 중앙값 2초 초과),
* `Retry-After` 헤더(다음 확인의 하한값으로 강제 적용됨).

이 중 하나라도 발생하면 엔진은 **변경 확인 간격을 한 단계씩 두 배로 늘리고**, 유지 관리 레인은 실행을 완전히 건너뜁니다. 검색, 바코드 조회, 결제 등 계산원이 유발하는 요청은 절대 제한되지 않습니다. 목표는 미뤄도 되는 부하를 덜어내는 것이지 판매를 늦추는 것이 아니기 때문입니다.

복구는 의도적으로 비대칭입니다. 백오프는 즉시 이루어지지만, 간격은 **연속 10회의 정상 응답** 이후에야 한 단계씩 원래대로 돌아옵니다. 불안정한 서버에서 빠른 주기와 느린 주기 사이를 오가지 않도록 하기 위해서입니다. 부하 상태는 판매자가 더 빠른 프리셋을 선택해도 유지됩니다. 이 보호 장치는 설정된 등급 아래에서 작동하며, 끄는 방법은 없습니다.

## 기기의 응답성 유지[​](#device-responsiveness "기기의 응답성 유지으로 직접 링크")

성능의 나머지 절반은 계산대 자체입니다. 백그라운드 동기화가 UI를 버벅이게 해서는 안 됩니다.

* **감사는 이벤트 루프에 양보합니다.** 무결성 감사는 작업을 청크로 나누고 청크 사이에 양보하여, 중단 없이 실행되는 가장 긴 구간을 약 **30ms**로 유지합니다. 이는 사람이 지연을 느끼는 약 100ms 기준보다 짧습니다. 로컬 제품 10,000개에서 측정했을 때 전체 감사 1회는 17회 이상의 양보에 걸쳐 약 **68ms**의 연산을 소모했고, 제품 50,000개에서는 300ms 미만이었습니다.
* **부하 상황에서도 첫 결과는 빠릅니다.** 대량 적용이나 전체 감사가 동시에 실행되는 중에도 첫 결과까지의 시간 계약이 CI에 고정되어 있습니다. 벤치마크 환경의 일반적인 카탈로그 크기에서는 한 자릿수 밀리초입니다.
* **화면에 보이는 페이지만 앱으로 전달됩니다.** 필터, 정렬, 페이지네이션 같은 쿼리 작업은 저장소 계층 내부에서 실행되므로, 화면 갱신 시 만 개가 아니라 열 개의 행만 이동합니다.

이 수치들은 CI에서 격리 실행되는 엔진의 고정 성능 계약 스위트에서 나온 것이며, 예산은 측정된 정상 상태보다 대략 한 자릿수 크게 설정되어 있습니다. 느린 실행기에서 실패하도록 만든 것이 아니라, 자릿수 단위의 성능 저하를 잡아내기 위한 설계입니다.

## 실제 스토어에서의 검증[​](#live-verification "실제 스토어에서의 검증으로 직접 링크")

이 배려 규칙들은 단위 테스트로만 확인되지 않습니다. 실제 WordPress 스토어를 대상으로 한 라이브 종단 간 점검이 실제 호스팅에서 가장 중요한 불변식들을 검증합니다:

* 스토어를 열 때 제품 카탈로그가 렌더링되기 전의 유지 관리 요청(무결성 또는 다이제스트 트래픽)은 **0건**입니다.
* 개점 직후 대기 시간이 지난 뒤에도 저렴한 집계 페이지 몇 건과 상세 조회 두 건 이하만 발생합니다.

이 시나리오는 실제 회귀에서 만들어졌습니다. 초기 개발 빌드의 감사는 기기마다 스토어를 열 때마다 약 41건(1.2MB)의 요청을 보냈습니다. 이를 대체한 다이제스트 기반 설계는 편차가 없는 감사를 집계 페이지만으로 줄였습니다. 이제 이러한 유형의 버그는 검토자의 주의력이 아니라 CI에 선언된 상한으로 방지됩니다.

## 주장하지 않는 것[​](#honest-limits "주장하지 않는 것으로 직접 링크")

이 페이지가 의도적으로 언급하지 않는 몇 가지가 있습니다. 아직 근거를 댈 수 있는 수치가 없기 때문입니다:

* **“초기 동기화에 X분 걸린다”는 종단 간 수치는 없습니다.** 초기 다운로드 시간은 서버의 응답 시간과 카탈로그 크기에 압도적으로 좌우됩니다. 레코드를 적용하는 기기 측 비용은 작으며(제품 10,000개 대량 적용은 연산 시간 10ms 미만으로 측정됨), 네트워크와 서버가 대부분을 차지합니다.
* **“v1.9보다 X% 빠르다”는 주장은 없습니다.** 두 아키텍처의 차이가 커서 하나의 비교 수치는 정보를 주기보다 오해를 낳습니다. 구조적 차이는 [v1.10.0에서 달라진 점](/ko/reference/sync-engine.md#what-changed-in-v1100)에 정리되어 있습니다.
* 위의 벤치마크 수치는 엔진의 테스트 환경(인메모리 저장소, 격리된 실행기)에서 얻은 것입니다. 실제 기기와 실제 스토어는 제각각입니다. 그렇기 때문에 **스토어 상태 → 성능**은 예측이 아니라 지난 24시간 동안 이 계산대에서 측정된 요청 수와 일반적인 응답 시간을 보여줍니다. 여기 표시되는 데이터 양은 하한값입니다. 크기가 명시되지 않은 응답은 0으로 계산되기 때문입니다.

호스팅 요구 사항, HPOS, 캐싱, 느린 응답 진단 등 서버 측 튜닝은 [서버 성능](/ko/support/performance/server.md)을 참조하세요.
