유의사항 (배경)
•
토스 개발팀에서는 데이터베이스 부하를 분산하기 위해서 RW (DML 전용)와 RO (조회 전용)으로 데이터베이스를 분리하여 운영하고 있습니다. 이 때 RW에 INSERT, UPDATE, DELETE 된 데이터가 RO 에 복제됩니다.
•
이 때 아래와 같은 이유로 복제가 지연되거나 중단될 수 있으며 이는 RW, RO 데이터베이스 간에 데이터 불일치를 초래하여 비지니스 로직 오류 및 서비스 중단을 초래할 수 있습니다.
◦
Slow Query 로 인한 데이터베이스 성능 저하로 인한 복제 지연
◦
장시간 데이터베이스 Lock 을 획득하거나 또는 다량의 데이터에 대해 DML 처리 후 commit 할 경우
◦
짧은 시간에 DML 데이터 증가로 인한 복제 지연 및 중단
◦
RO 데이터베이스에 DML (INSERT, UPDATE, DELETE) 쿼리를 실행하는 경우 (복제 중단 초래)
요청 및 권고사항 (결론)
•
SELECT 부하를 줄이기 위해 EXPLAIN 으로 인덱스가 적용되는지와 1초 이내로 응답이 되는지 확인해야 합니다. 또한 동적 생성 쿼리에 따라 조건절이 변경되므로 모든 검색 조건에 부합한 인덱스가 적용되는지 확인해야 합니다.
•
테이블 생성시 PK 를 반드시 설정해야 합니다. (Auto increment 강력 권고)
◦
◦
PK는 쿼리 데이터의 물리적인 저장 순서에 영향을 줍니다. 따라서 자동 증가(Auto increment) 속성 컬럼을 PK 로 설정하는 것이 DML 작업에 유리합니다.
•
INSERT SELECT 와 같이 데이터 처리량을 제어할 수 없는 구문을 사용하지 않습니다.
•
UPDATE, DELETE 는 반드시 PK 를 조건으로 실행하고, Loop 를 돌며 UPDATE, DELETE 할 때는 2000 건당 1초씩 sleep 을 주어 RO 가 RW 를 안정적으로 반영할 수 있도록 처리해야 합니다.
•
DML 쿼리를 실행할때 auto_commit = 1 로 처리 혹은 한개 쿼리당 commit을 원칙으로 합니다.
◦
단일 Transaction 에서 10 or 100개 묶음마다 commit 하지 않습니다.
•
아래 쿼리는 2000개당 한 개 commit 이기 때문에 사용하면 안됩니다.
◦
update dml_table set values_2 = 4 where id in (1,2,…2000) and values_1 = 'aaa';
고려 후 적용해 볼 항목 (다음 스텝)
•
SELECT 작업은 read-only 데이터베이스에서 수행되도록 Database connection 을 분리해야 합니다.
(현재는 DML 과 SELECT 를 모두 RW 데이터베이스에서 수행하고 있음)
•
대량 데이터로 증가될 데이터 테이블은 페이지네이션 방식을 LIMIT OFFSET 이 아니라 Cursor-based Pagination 으로 구현해야 합니다.
•
빈번하게 조회되는 데이터는 In memory cache 로 등록하여 사용하거나 Redis 에 등록하여 사용하는 것을 지향해야 합니다.
