ARCUS 인메모리 캐시 시스템은 캐시 용도에 맞게 고성능 데이터 처리 목적으로 메모리를 저장소로 사용합니다. 휘발성 메모리를 사용함에 따라 시스템 장애나 장비 교체, 업그레이드 등의 이유로 시스템이 종료되면 저장해둔 모든 데이터가 사라지는 특징을 갖고 있습니다. 캐시 용도가 아닌 데이터 저장 용도이면서 캐시와 같은 고성능을 제공하는 저장소에 대한 요구가 있어서, ARCUS 캐시 시스템에서도 데이터를 영구히 보존할 수 있는 데이터 영속성(Persistence) 기능을 개발하였습니다. 본문에서는 ARCUS 데이터 영속성 기능을 소개해 드리고, 사용법을 간단히 알려드리겠습니다.
ARCUS Persistence 개요
ARCUS 데이터 영속성은 스냅샷(Snapshot)과 명령 로깅(Command Logging) 방식으로 디스크에 캐시 데이터를 기록해두고, 이를 이용하여 완벽하게 데이터를 복구하는 기능을 제공합니다. 데이터 영속성을 제공하기 위하여, ARCUS 인스턴스는 아래 그림과 같이 (1) 전체 데이터를 디스크에 기록하는 스냅샷을 주기적으로 수행하는 체크포인트
모듈과 (2) ARCUS 응용들이 요청하는 변경 명령에 대하여 명령 그 자체를 로깅하는 명령 로깅
모듈을 가집니다. 체크포인트 작업은 별도의 스레드를 두어 일반 응용 요청 처리를 지연시키지 않는 범위에서 전체 캐시 아이템의 일부씩 조회하면서 디스크에 기록합니다. 응용 요청을 처리하는 작업 스레드는 변경 요청인 경우에 한하여 명령 로그를 생성하여 로그 버퍼에 기록하는 오버헤드만 추가로 가지며, 그 외에 로그 버퍼에서 로그 디스크로 쓰는 작업은 별도의 스레드를 두어 병렬로 수행합니다. 따라서, 작업 스레드는 응용 요청 처리에만 집중하도록 하고 추가적인 영속성 작업의 오버헤드를 최소화하여 ARCUS의 기존 고성능을 보장하도록 구현하였습니다.
스냅샷 방식의 체크포인트
체크포인트 수행 목적은 데이터 복구 시간을 줄이는 데 있습니다. 명령 로그 파일이 커지면 그에 비례하여 데이터 복구 시간이 길어지기 때문에, 주기적으로 전체 데이터의 스냅샷을 생성하여 명령 로그 파일의 크기를 줄입니다. 체크포인트의 주요 동작과 특징은 다음과 같습니다.
별도의 체크포인트 스레드를 두어 수행합니다.
- 모든 캐시 아이템을 순차 탐색해야 하므로, 캐시 아이템 접근에 대해 작업 스레드와 경쟁이 발생할 수 있습니다.
- 응용 요청 처리에 방해되지 않기 위하여, 한번에 적은 수의 캐시 아이템만 접근하는 과정을 반복하면서 스냅샷을 수행하였습니다.
체크포인트는 새로운 명령 로그 파일을 먼저 생성한 후, 스냅샷을 시작하여 백업 복사본을 생성합니다.
- 새로운 명령 로그 파일은 현재 스냅샷 이후에 변경되는 요청을 기록하는 명령 로그 파일입니다.
- 현재 스냅샷 수행 동안에도 변경 요청 처리는 병렬로 수행됩니다. 현재 스냅샷으로 디스크에 기록된 캐시 데이터에 대한 변경 요청이면, 명령 로그를 생성하여 새로운 명령 로그 파일에도 기록합니다. 아직 스냅샷되지 않은 캐시 아이템에 대한 변경 요청이면, 새로운 명령 로그 파일에는 기록하지 않습니다.
- 참고로, 이전 체크포인트에 의해 생성된 기존 명령 로그 파일에는 모든 변경 요청의 명령 로그를 기록합니다. 현재 체크포인트 작업이 어떤 이유로 실패할 경우에는 기존 스냅샷 파일과 기존 명령 로그 파일로 복구하기 위함입니다.
모든 캐시 아이템에 대한 스냅샷 작업을 완료하면, 현재 스냅샷 파일에 대한 새로운 명령 로그 파일을 그 이후의 명령 로그를 기록하는 데 사용하고, 이전 체크포인트에 의해 생성된 스냅샷 파일과 명령 로그 파일을 제거합니다.
명령 로깅
응용의 요청을 처리하는 작업 스레드는 변경 요청인 경우에 한하여 그 요청의 재수행에 필요한 명령 로그를 생성하여 기록합니다. 명령 로깅은 아래의 처리 방식으로 로깅 성능을 최적화하였습니다.
- 원형 큐(queue) 구조의 명령 로그 버퍼를 사용합니다.
- 작업 스레드는 명령 로그를 생성하여 로그 버퍼에만 기록하며, 로그 버퍼에서 명령 로그 파일로 쓰는 작업은 별도의 로그 플러쉬 스레드가 담당합니다.
- 로그 플러쉬 스레드는 로그 버퍼에서 로그 파일에 쓰야 할 명령 로그 데이터의 위치와 크기만을 조회/변경할 경우만 로그 버퍼에서 작업 스레드와 경쟁하며, 실제 플러쉬 작업을 하는 동안에는 작업 스레드와 병렬로 수행되게 하였습니다.
명령 로깅의 동작 모드로 아래 2가지를 지원합니다.
비동기(asynchronous) 로깅 모드
- 작업 스레드는 명령 로그를 로그 버퍼에 기록하지만, 디스크에 반영하는 것을 보장하지 않은 상태로 그 변경 연산의 수행을 완료합니다. 따라서, 완료된 요청의 명령 로그가 디스크에 반영되지 않은 상태에서 ARCUS 인스턴스가 비정상 종료한다면 데이터 손실이 있게 됩니다.
- 캐시 성격의 동작에 비해 작업 스레드는 명령 로그를 생성하여 로그 버퍼에 기록하는 부담만을 가지므로, 기존 캐시 성능과 차이가 크지 않습니다.
동기(synchronous) 로깅 모드
- 작업 스레드는 명령 로그를 로그 버퍼에 기록하고 디스크에 반영된 것을 확인한 후에 그 변경 연산의 수행을 완료합니다. 따라서, 어떤 시점에 ARCUS 인스턴스가 비정상 종료하더라도 데이터를 완벽히 복구할 수 있는 장점을 가집니다.
- 동기 로깅 모드에서도 최적 성능을 도출하기 위하여, 명령 로그 파일에 기록한 데이터를 디스크에 강제 반영하는 작업을 별도의 스레드를 두어 수행하게 하였으며, 작업 스레드는 그 사이에도 다른 클라이언트의 요청들을 처리할 수 있도록 구현하였습니다. 따라서, 동기 로깅 모드에서도 상당한 수준의 성능을 보일 수가 있었습니다.
ARCUS Persistence 사용법
ARCUS 기본 캐시 엔진인 default
엔진에 persistence 기능을 추가하였습니다. ARCUS Persistence 사용법은 CentOS 환경에서 default
엔진을 사용하는 ARCUS 캐시 노드를 1개만 구동하는 경우를 기반으로 간단히 소개합니다..
Persistence Configuration
ARCUS의 default
엔진에는 엔진 동작에 관한 설정들을 가지는 default_engine.conf
파일이 있으며, 그 파일에서 아래와 같은 Persistence 관련 설정을 할 수 있습니다.
# Persistence configuration
#
# use persistence (true or false, default: false)
use_persistence=true
#
# The path of the snapshot file (default: ARCUS-DB)
data_path=/home/test/arcus/ARCUS-DB
#
# The path of the command log file (default: ARCUS-DB)
logs_path=/home/test/arcus/ARCUS-DB
#
# asynchronous logging
async_logging=false
#
# checkpoint interval (unit: percentage, default: 100)
# The ratio of the command log file size to the snapshot file size.
# 100 means checkpoint if snapshot file size is 10GB, command log file size is 20GB or more
chkpt_interval_pct_snapshot=100
#
# checkpoint interval minimum file size (unit: MB, default: 256)
chkpt_interval_min_logsize=256
Persistence 설정 항목의 설명은 다음과 같습니다.
use_persistence
- persistence 사용 여부 설정입니다.
data_path, logs_path
- data_path와 logs_path는 각각 스냅샷 파일과 명령 로그 파일이 생성되는 경로입니다.
- 두 경로는 반드시 지정하여야 하며, 두 경로가 같은 경로이어도 됩니다. 가급적 절대경로 지정을 권고합니다.
asynchronous logging
- 명령 로깅의 동작 모드 설정입니다.
- false이면 동기(synchronous) 로깅 모드, true이면 비동기(asynchronous) 로깅 모드로 동작합니다.
chkpt_interval_pct_snapshot
- 체크포인트 수행 주기 설정으로, 스냅샷 파일 크기에 대비하여 명령 로그 파일의 추가 증가된 크기 비율을 설정합니다.
- 지정한 비율만큼 명령 로그 파일이 추가로 커지면 체크포인트를 수행합니다. 예를 들어 100으로 설정하면, 스냅샷 파일이 10GB인 경우 명령 로그 파일은 100% 추가 증가한 20GB가 되면 체크포인트를 수행하게 됩니다.
chkpt_interval_min_logsize
- 체크포인트 수행 주기 설정으로, 명령 로그 파일이 지정된 최소 크기 이상인 경우만 체크포인트를 수행하게 됩니다.
- 스냅샵 파일 크기가 작은 경우에 빈번한 체크포인트 수행을 방지하기 위함입니다.
다운로드
Github arcus-memcached 저장소에서 소스코드를 다운로드 받습니다.
$ git clone https://github.com/naver/arcus-memcached.git
컴파일
Persistence 기능을 사용하기 위해서는 configure 시에 --enable-persistence
옵션을 추가하여 compile하여야 합니다. 참고로, --prefix
옵션은 make install
위치를 지정합니다.
$ ./config/autorun.sh
$ ./configure --prefix=/home/test/arcus --enable-persistence
$ make
$ make install
make install
까지 완료하면 --prefix
로 지정한 설치 경로에 ARCUS 인스턴스 구동에 필요한 파일들이 다음 디렉토리에 생성됩니다.
- bin : ARCUS 인스턴스 구동 바이너리
memcached
- conf :
default
엔진 설정 파일default_engine.conf
- lib :
default
엔진 라이브러리default_engine.so
, ARCUS 인스턴스의 logger 라이브러리syslog_logger.so
ARCUS 인스턴스 구동
ARCUS 인스턴스 구동하기 전에 스냅샵 파일과 명령 로그 파일이 생성될 디렉토리를 먼저 생성하고, 앞서 설명한 default
엔진의 설정 파일을 설정합니다.
설치 경로의 bin
디렉토리로 이동하여, ARCUS 인스턴스를 구동하겠습니다. -E
옵션으로 default
엔진의 라이브러리 위치를, -e
옵션으로 default
엔진의 설정 파일 위치를 다음과 같이 절대 경로로 지정하였습니다. 그 외의 구동 옵션에 대한 설명은 ./memcached -h
명령을 수행하여 확인할 수 있습니다.
./memcached -d -v -r -p 11500 -m 500 \
-X /home/test/arcus/lib/syslog_logger.so \
-E /home/test/arcus/lib/default_engine.so \
-e config_file=/home/test/arcus/conf/default_engine.conf
ARCUS 인스턴스 구동 시에 syslog_logger.so
를 사용하였으므로, 구동 메세지는 syslog
에서 확인할 수 있습니다. 아래와 같이 persistence 관련 모듈을 초기화하는 메세지가 반드시 나와야 합니다.
Dec 11 15:15:18 jam2in memcached[1221]: CMDLOG FILE module initialized.
Dec 11 15:15:18 jam2in memcached[1221]: CMDLOG BUFFER module initialized.
Dec 11 15:15:18 jam2in memcached[1221]: COMMNAD LOG RECORD module initialized.
Dec 11 15:15:18 jam2in memcached[1221]: SNAPSHOT module initialized.
Dec 11 15:15:18 jam2in memcached[1221]: CHECKPOINT module initialized.
Dec 11 15:15:18 jam2in memcached[1221]: There are no files needed for recovery. Do checkpoint to create checkpoint file set.
Dec 11 15:15:18 jam2in memcached[1221]: Done the snapshot action.
Dec 11 15:15:18 jam2in memcached[1221]: Group commit thread started.
Dec 11 15:15:18 jam2in memcached[1221]: Command log flush thread started.
Dec 11 15:15:18 jam2in memcached[1221]: Checkpoint thread started.
Dec 11 15:15:18 jam2in memcached[1221]: COMMAND LOG MANAGER module initialized.
ARCUS 인스턴스 구동 후에 스냅샷 파일과 명령 로그 파일이 생성된 것을 볼 수 있습니다. 스냅샷 파일이 없는 상태에서 ARCUS 인스턴스를 구동하면, 구동 과정에서 체크포인트를 수행하여 실제 데이터는 없는 스냅샷 파일과 명령 로그 파일을 생성하기 때문입니다.
[test@jam2in:ARCUS-DB *]$ ls -l
-rw-r — — — 1 test test 0 Dec 11 15:15 cmdlog_20201210174619
-rw-r — — — 1 test test 48 Dec 11 15:15 snapshot_20201210174619
Telnet 이용한 ARCUS 명령 수행
telnet
명령으로 localhost
에 있는 11500
포트의 ARCUS 인스턴스에 접속하여, ARCUS 요청을 보내도록 하겠습니다. KV 아이템과 BTree 아이템을 생성하고 BTree 아이템에 두 개의 엘리먼트를 삽입하겠습니다. ARCUS ascii 명령의 자세한 설명은 ARCUS DOCS 시스템에서 확인할 수 있습니다.
telnet localhost 11500
Trying ::1…
Connected to localhost.
Escape character is ‘^]’.
set kvkey 0 0 3
qwe
STORED
bop create btreekey 0 0 3
CREATED
bop insert btreekey 10 3
qwe
STORED
bop insert btreekey 11 3
ewq
STORED
이번에는 저장된 아이템과 엘리먼트를 확인해보곘습니다.
telnet localhost 11500
Trying ::1…
Connected to localhost.
Escape character is ‘^]’.
get kvkey
VALUE kvkey 0 3
qwe
END
bop get btreekey 10
VALUE 0 1
10 3 qwe
END
bop get btreekey 11
VALUE 0 1
11 3 ewq
END
현재 명령 로깅 모드는 엔진 설정 파일에서 async_logging=false
로 지정하였으므로 동기 모드로 동작하여 명령이 수행되는 즉시 명령 로그에 기록됩니다. 로그 경로(logs_path)에 있는 명령 로그 파일의 크기와 데이터를 보면 위 명령들이 기록된 것을 확인할 수가 있습니다.
Memtier_benchmark 이용한 ARCUS 명령 대량 수행
이번에는 Traffic Generation Tool memtier_benchmark
를 이용해서 ARCUS 인스턴스에 대량으로 명령 요청을 해보겠습니다. 이 경우, 체크포인트 수행 조건이 충족되어 체크포인트를 수행하는 것까지 확인해보겠습니다. memtier_benchmark
설치 및 사용법은 해당 Github 저장소를 참고하시기 바랍니다.
아래와 같이 memtier_benchmark
구동 파라미터를 설정하여, ARCUS 인스턴스에 각 1KB 데이터를 가지는 30만개 아이템을 삽입하도록 하겠습니다. 그러면, 총 300MB 정도의 데이터가 삽입됩니다.
./memtier_benchmark -s 127.0.0.1 -p 11500 --threads=10 \
--clients=10 --requests=3000 --protocol=memcache_text \
--data-size=1024 --key-minimum=1 --key-maximum=300000 \
--key-pattern=P:P --ratio=1:0
--key-minimum
,--key-maximum
: 삽입할 아이템의 key 범위는 1 ~ 300000 으로, 총 300000 개 아이템 삽입--data-size
: 삽입할 아이템의 밸류 크기는 1MB--key-pattern=P:P
: 요청을 병렬 처리. connection 별로 key 범위를 나눠서 처리함.--ratio=1:0
: Set:Get 비율을 의미하여,SET
요청만을 수행하도록 1:0 설정
앞서 엔진 설정 파일에 설정한 체크포인트 수행 조건에 따르면, 명령 로그 파일의 크기가 아래 조건을 모두 충족하는 시점에 체크포인트를 수행합니다.
chkpt_interval_pct_snapshot=100
- 마지막 체크포인트(구동 시 수행한 체크포인트)에서의 스냅샷 파일 크기인 48bytes에서 100% 추가 증가한 96bytes 이상
chkpt_interval_min_logsize=256
- 최소 256MB 이상
따라서 명령 로그 파일의 크기가 256MB 이상이 되면 체크포인트를 수행하며, 이 때 체크포인트를 수행하는 로그 메세지를 syslog
에서 확인할 수 있습니다.
Dec 11 15:21:01 jam2in memcached[1221]: Checkpoint started.
data_path
와 logs_path
의 파일을 관찰하면 앞서 설명했듯이 체크포인트 스레드가 스냅샷을 수행하여 스냅샷 파일과 명령 로그 파일을 새로 생성한 것을 볼 수 있습니다.
[test@jam2in:ARCUS-DB *]$ ls -lh
-rw-r — — — 1 test test 270M Dec 11 15:15 cmdlog_20201211151519
-rw-r — — — 1 test test 0 Dec 11 15:21 cmdlog_20201211152101
-rw-r — — — 1 test test 48 Dec 11 15:15 snapshot_20201211151519
-rw-r — — — 1 test test 2.8M Dec 11 15:21 snapshot_20201211152101
체크포인트를 완료하면 아래와 같이 완료 로그 메세지가 나타나고,
Dec 11 15:21:01 jam2in memcached[1221]: Done the snapshot action.
Dec 11 15:21:01 jam2in memcached[1221]: Checkpoint has been done.
이전 스냅샷 파일과 명령 로그 파일은 제거된 것을 확인할 수 있습니다.
[test@jam2in:ARCUS-DB *]$ ls -lh
-rw-r — — — 1 test test 40 Dec 11 15:22 cmdlog_20201211152203
-rw-r — — — 1 test test 307M Dec 11 15:21 snapshot_20201211152101
memtier_benchmark
를 이용해서 총 30만개 아이템을 삽입하였으므로, ARCUS에 저장된 총 아이템의 개수를 확인해보겠습니다. telnet
에서 stats
명령을 수행하여 curr_items
값을 확인하면 됩니다. 앞서 Telnet 이용한 ARCUS 명령 수행
에서 삽입한 2개의 아이템을 포함해서 현재 300002개의 아이템이 저장되어 있을 겁니다. 이보다 더 저장되있다면, 이는 ARCUS가 내부적으로 Hang을 탐지하기 위해 아이템 삽입 요청을 수행하기 때문입니다. 참고로 내부적으로 수행하는 명령은 명령 로그에 기록하지 않습니다.
STAT curr_items 300002
ARCUS 인스턴스 재구동 후의 복구 확인
ARCUS 인스턴스를 재구동한 후에 데이터가 그대로 보존되는 지를 확인해보겠습니다. 먼저, ARCUS 인스턴스를 종료합니다.
kill $arcus-memcached_pid
그리고, 동일한 구동 옵션으로 다시 구동합니다.
./memcached -d -v -r -p 11500 -m 500 \
-X /home/test/arcus/lib/syslog_logger.so \
-E /home/test/arcus/lib/default_engine.so \
-e config_file=/home/test/arcus/conf/default_engine.conf
재구동했을 때 아래와 같이 ARCUS 인스턴스가 스스로 data_path와 logs_path에 들어있는 스냅샷 파일과 명령 로그 파일을 이용해 데이터를 복구하는 로그 메세지를 확인할 수 있습니다.
…
Dec 11 15:23:18 jam2in memcached[1333]: Check that ARCUS-DB/snapshot_20201211152101 is valid snapshot file for recovery.
Dec 11 15:23:18 jam2in memcached[1333]: [RECOVERY — SNAPSHOT] applying snapshot file. path=/home/test/arcus/ARCUS-DB/snapshot_20201211152101
Dec 11 15:23:18 jam2in memcached[1333]: [RECOVERY — SNAPSHOT] success.
Dec 11 15:23:18 jam2in memcached[1333]: [RECOVERY — CMDLOG] applying command log file. path=/home/test/arcus/ARCUS-DB/cmdlog_20201211152203
Dec 11 15:23:18 jam2in memcached[1333]: [RECOVERY — CMDLOG] success.
Dec 11 15:23:18 jam2in memcached[1333]: Group commit thread started.
…
종료 전에 Telnet 이용한 ARCUS 명령 수행
에서 삽입한 데이터를 조회 요청을 해보면 데이터가 그대로 복구되었음을 확인할 수 있습니다.
telnet localhost 11500
Trying ::1…
Connected to localhost.
Escape character is ‘^]’.
get kvkey
VALUE kvkey 0 3
qwe
END
bop get btreekey 10
VALUE 0 1
10 3 qwe
END
bop get btreekey 11
VALUE 0 1
11 3 ewq
END
telnet
에서 stats
명령을 수행하여 curr_items
값을 보면 종료 전에 Memtier_benchmark 이용한 ARCUS 명령 대량 수행
에서 확인한 저장된 아이템의 총 개수가 동일한 것을 확인할 수 있습니다.
STAT curr_items 300002
마치며
ARCUS 캐시 시스템에서 스냅샷 방식의 체크포인트와 명령 로깅으로 제공하는 데이터 영속성 기능을 소개하고 사용법을 알아보았습니다. 데이터 영속성은 ARCUS를 캐시 용도 외에 저장 용도까지 활용도를 높일 수 있는 중요한 기술이며, 이러한 출발의 시작점이 될 것입니다. 현재 데이터 영속성 기능의 동작과 기본 테스트까지는 완료하였으며, 향후에 아래 작업을 진행할 예정입니다.
- Persistence 설정을 동적으로 변경하는 기능
- 다양한 워크로드 상에서 지속적인 테스트 및 개선
그리고, 본문에서 소개하였듯이 ARCUS 데이터 영속성은 일반 요청 처리의 영향을 최소화하도록 설계되어서 기존 캐시와 차이가 크지 않은 성능을 보입니다. 다음에 캐시 용도와 저장 용도의 성능 비교를 포함하여 명령 로깅 모드에 따른 성능 차이를 측정하여 알려드리도록 하겠습니다.