From 31a5ff8ba64d505c3c01ee0c6b4d55bd06c167d5 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Wed, 30 Sep 2026 07:06:52 +0100 Subject: Say what the TPC-C comparison decides, before running it (106) --- docs/research/106-tpcc-conditions-first.md | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/research/106-tpcc-conditions-first.md diff --git a/docs/research/106-tpcc-conditions-first.md b/docs/research/106-tpcc-conditions-first.md new file mode 100644 index 0000000..a0eae9d --- /dev/null +++ b/docs/research/106-tpcc-conditions-first.md @@ -0,0 +1,44 @@ +# 106 — 조건을 먼저 정한 TPC-C: 묶어 커밋하는 SQLite, 창고 넷 + +2026-09-30. [외부 리뷰 004](../outside-feedback/feedback-004.md)의 넷째 권고에서 시작한다. [092](092-tpcc.md)의 비교는 +창고 하나(W=1)였고, SQLite는 트랜잭션마다 커밋했다. 리뷰는 SD 카드에서의 약 90배가 대부분 그룹 커밋과 로그 쓰기 구조에서 +온다고 읽었다. 그래서 SQLite도 묶어 커밋하게 하고, 창고를 넷으로 늘려 다시 잰다. 아래는 측정 행렬을 돌리기 전에 정했다 +(하니스를 확인하려고 5초짜리 시험을 몇 번 돌린 뒤다). + +착수 기준: + +- **바꿀 결정.** + 1. **SD 카드에서의 주장.** SQLite도 묶어 커밋할 때 Pure와의 처리량 차이가 2배 안으로 줄면, 092의 SD 비교를 "묶어 커밋하는 + 구조를 앱 코드 없이 얻는다"로 고쳐 쓴다. 2배 넘게 남으면, 거래당 장치에 쓴 바이트로 차이가 어디서 오는지 적는다. + 2. **소유자 하나.** W=4에서 Pure의 소유자 스레드가 코어 하나의 90% 이상을 쓰는데도, 64터미널의 처리량이 16터미널보다 10% + 넘게 늘지 않으면 소유자가 병목이다. 그러면 키(창고)로 나눈 소유자 여럿을 다음 설계로 올린다. 아니면 지금은 하지 않는다. + 3. **체크포인트.** SD 카드에서 W=4의 Pure 처리량이 W=1의 절반 아래면, 목록의 이미지를 통째로 다시 쓰는 체크포인트가 + 다음 일이다(092의 "덧붙는 목록의 이미지"). +- **정합성 통과 조건.** W마다 시간 잰 실행 전에, 한 씨앗에서 뽑은 같은 거래 2만 건을 Pure, SQLite, 묶어 커밋하는 SQLite에 + 돌린다. 모든 표의 모든 행이 같아야 하고(시각 제외), 실패한 거래가 없어야 한다(되돌린 New-Order는 규격대로 성공이다). + 시간 잰 실행마다 그 뒤에 clause 3.3.2.1–4가 성립해야 한다. 하나라도 어긋난 실행은 결과로 싣지 않는다. +- **허용 메모리.** 실행이 모두 끝난 뒤 Pure의 상주 메모리가 상태 바이트의 2.5배 이하여야 한다([104](104-where-memory-goes.md)에서 + 최고가 약 2배였다). 넘으면 그 차이가 어디로 가는지가 다음 일이다. W는 RAM(tmpfs)에서 저장소와 데이터베이스까지 메모리에 + 들고도 1 GB가 남게 고른다. 이 Pi(8 GB, 쓸 수 있는 것 약 4.8 GB)에서는 W=4다. +- **저장 완료와 지연.** 두 쪽 모두 커밋이 장치에 닿은 뒤 답한다. Pure는 저장마다 로그에 쓰고 `fdatasync`한다. SQLite는 WAL, + `synchronous=FULL`이다. 지연은 같은 수의 터미널이 기다릴 때(16, 64) 비교한다. +- **SQLite 설정.** 신중한 엔지니어가 고를 설정으로 겨룬다. 행렬 전에 조율 실행으로 고른다. RAM에서는 기본값과 + `mmap_size` 1 GiB, 연결마다 캐시 64 MiB, `temp_store=MEMORY`(SAVEPOINT의 하위 저널을 메모리에)를 견준다. SD 카드에서는 + 페이지 크기 4,096 B와 1,024 B를 견준다. 묶어 커밋하는 실행의 처리량이 높은 쪽을 쓴다. + +## 방법 + +[`benchmarks/tpcc/run.py`](../../benchmarks/tpcc/run.py)와 [`sqlite-tpcc.c`](../../benchmarks/tpcc/sqlite-tpcc.c)에 SQLite의 +묶음 모드를 더했다. + +- **묶어 커밋하는 SQLite.** 터미널들이 쓰는 거래(New-Order, Payment, Delivery)를 작성자 스레드 하나에 넘긴다. 작성자는 + 기다리는 것을 모두 한 트랜잭션(`BEGIN IMMEDIATE`)으로 돌리고, 거래마다 `SAVEPOINT`를 둔다. 실패하거나 되돌릴 거래는 제 + SAVEPOINT까지만 되돌린다. 한 번의 `COMMIT`(동기화 한 번) 뒤에 각 터미널을 깨운다. +- **읽기 거래.** Order-Status와 Stock-Level은 각 터미널이 제 연결에서 마지막 커밋을 읽는다. pure-serve가 보기를 소유자에게 + 넘기지 않고 연결 스레드에서 마지막 저장의 스냅숏으로 답하는 것과 같다. +- **잰 것.** 실행마다 초당 거래, 종류별 p50/p99, 거래당 CPU(Pure는 서버 프로세스, SQLite는 제 프로세스), 소유자 스레드가 + 쓴 코어의 몫(pure-serve의 소유자 스레드 이름을 `pure-owner`로 붙였다), 메모리(Pure는 서버의 상주, SQLite는 최고 상주), + 거래당 쓴 바이트(프로세스의 `write_bytes`, 그리고 장치의 쓴 섹터)다. 끝에 Pure의 상태 바이트와 두 쪽의 파일 크기를 적는다. +- **행렬.** RAM(`/dev/shm`)과 SD 카드(ext4), 각각 W=1과 W=4. Pure 16·64터미널, SQLite 1·4스레드, 묶어 커밋하는 SQLite + 16·64터미널. RAM은 20초, SD 카드는 30초씩이다. SD 카드는 상태에 따라 흔들리므로 세 번 돌려 범위를 적는다. +- 서버와 SQLite는 코어 0–2, Pure의 부하 생성기(HTTP/1.1, JSON)는 코어 3이다. SQLite는 프로세스 안에서 돈다. -- cgit v1.2.3