Space amplification
- Disk에 있는 데이터크기와 실제 DB 사이즈의 비율
만약 DB에 10MB를 넣었는데 100MB의 디스크 공간을 사용했다면 이때 space amplification은 10이다.
1. Load & Run TPC-C data
$ cd tpcc-mysql
$ vi load.sh
export LD_LIBRARY_PATH=/home/koh/mysql-5.7.33/lib
DBNAME=$1
WH=$2
HOST=127.0.0.1
STEP=100
./tpcc_load -h $HOST -d $DBNAME -u root -p "yourPassword" -P3306 -w $WH -l 1 -m 1 -n $WH >> 1.out &
x=1
while [ $x -le $WH ]
do
echo $x $(( $x + $STEP - 1 ))
./tpcc_load -h $HOST -d $DBNAME -u root -p "yourPassword" -P3306 -w $WH -l 2 -m $x -n $(( $x + $STEP - 1 )) >> 2_$x.out &
./tpcc_load -h $HOST -d $DBNAME -u root -p "yourPassword" -P3306 -w $WH -l 3 -m $x -n $(( $x + $STEP - 1 )) >> 3_$x.out &
./tpcc_load -h $HOST -d $DBNAME -u root -p "yourPassword" -P3306 -w $WH -l 4 -m $x -n $(( $x + $STEP - 1 )) >> 4_$x.out &
x=$(( $x + $STEP ))
done
for pid in `jobs -p`
do
echo wait for $pid
wait $pid
done
$ sudo chmod 777 load.sh
$ ./load.sh tpcc 20
./tpcc_start -h 127.0.0.1 -S /tmp/mysql.sock -d tpcc -u root -p "yourPassword" -w 20 -c 8 -r 10 -l 1200
benchmark 파라미터 값의 의미는 다음과 같다.
Host: 127.0.0.1
MySQL Socket: /tmp/mysql.sock
DB: tpcc
User: root
Password: yourPassword
Warehouse: 20
Connection: 8
Rampup time: 10 (sec)
Measure: 1200 (sec)
2. Calculate User Data size in B+tree nodes
tpcc benchmark가 끝난 후에, 다음 command를 쳐준다.
$ innodb_space -f /path/to/test_data/tpcc/history.ibd space-index-pages-summary | tee innodb_space.txt
innodb_space
: InnoDB의 extent, 파일 segment 및 free space 관리 구조 확인 (innodb_ruby
설치해야함)
/path/to/test_data/tpcc/history.ibd
: test_data 디렉토리에 저장되어있는 history.idb table (tpcc benchmark 후 생김)
space-index-pages-summary
: 이 모드를 사용하면 모든 index 페이지의 공간 사용관련 데이터를 볼 수 있음.
tee innodb_space.txt
: txt파일로 저장
총 11773개의 page에 대한 데이터를 볼 수 있다.
여기서 space amplification
= tpcc DB size
/ user data size
로 구할 수 있다.
tpcc DB size : innoDB의 page는 16KB로 설정되어있으므로 16 * 11773 = 188,368KB
user data size : txt 파일에서 아래 awk
명령어로 data 총 합을 구해준다. 143,128,979 ≅ 143,129KB
단순 계산으로 45,239KB가 낭비되고있고,
Space amplification 은 188,368 / 143,129 ≅ 1.316이다.
InnoDB는 B+ tree기반 자료 구조를 사용해 인덱스 페이지를 관리한다.
Leaf 노드페이지에 많은 업데이트가 발생하게 되면 분할 현상
이 발생하여 space amplification이 발생한다. 분할 현상이 많이 발생하면 page 수가 늘어나기 때문에 해당 페이지를 모두 사용하지 않아 공간을 낭비할 확률이 높아진다.
그렇다면 분할 현상이 왜 발생할까?
OLTP 벤치마크인 TPC-C는 order-delivery
와 stock-exchange
같은 트랜잭션을 logging하는데 별도의 테이블(History, Orders, Order-Line 등등)을 사용한다.
이 중 Order-Line 테이블은 전체 DB 용량 중 많은 비중을 차지하기 때문에 OLTP성능에 많은 영향을 미친다.
Order-Line 테이블
의 리프노드 분할은 주로 new-order
, delivery
트랜잭션에 의해 발생한다.
new-order transaction은 Order-Line 테이블에 61바이트 튜플을 삽입하고,
delivery transaction은 Order-Line 테이블의 datatime 튜플을 업데이트한다.
TPC-C 벤치마크 수행 시, new-order transaction으로는 튜플이 순차적으로 삽입되기 때문에 분할이 발생하지 않는다. 하지만 delivery 트랜잭션 수행 시엔 페이지마다 미리 부여된 여유공간(default로 6.25%가 부여돼있다.)이 부족해 페이지 분할이 발생한다.
이렇게 분할 된 페이지 중 왼쪽 리프 페이지는 더이상 업데이트가 발생하지 않아 frozen 페이지가 되고, 약 50%만 차 있는 상태로 space amplification이 발생하는 것이다.
그렇기 때문에 B+tree의 리프노드에 여유공간을 미리 추가적으로 할당해, 트랜잭션 수행 시 불필요한 분할 발생은 없애는 것이 좋은 해결책이 될 수 있다.
Reference
- "Optimizing Space Amplification in MySQL/InnoDB",Bo-Hyun Lee, Mijin An, Sang-Won Lee
- https://github.com/LeeBohyun/mysql-tpcc/blob/master/innodb_b%2Btree/measure_space_utilization.md
- https://blog.jcole.us/2013/01/03/a-quick-introduction-to-innodb-ruby/