<< 래리 월이 말한 프로그래머가 가져야할 세가지 덕목 | Home | MySQL에서 무중단으로 스키마 변경하기(Alter) >>

트랜잭션이 중요한 비즈니스에서의 MySQL에 대한 고민들

MySQL에서 데이터 정합성이 중요한 비즈니스에서 데이터 불일치에 대한 고민을 적어 본다. 보통 MySQL은 Replication 방식으로 부하 분산을 대응하고, 여기에 성능의 이유로 sync-binlog=0으로, 비동기 방식(준동기보다)으로 운영을 많이 하는데, 여기서 문제가 발생한다. 장애시의 데이터 불일치, 평상시의 데이터 동기화(마스터에서 슬래이브까지) 지연 등의 현상이 발생하고 나중에 오래 운영하다보면 Master-Slave간의 데이터 불일치도 발생하게 된다.
이런 문제점을 성능을 조금 양보하면서 데이터 정합성을 찾을 수 있는 방법은 없을까?에 대한 생각을 적어 본다. 다른 좋은 의견이 있으시면 코멘트 부탁드립니다. ^^

관련 요소들 그리고 이슈

1. Replication 방식의 변천사 그리고 지연
MySQL의 Replication은 보통 비동기 방식으로 운영한다. 비동기 방식은 마스터 측은 슬레이브를 업데이트했는지 여부 및 업데이트 로그가 전송되었는지 여부는 신경쓰지 않는 방식이다. 만약 마스터의 장애나, 슬레이브 간의 네트워 장애가 발생해도 마스터 측과 슬레이브와의 데이터 차이는 커질 것이다.



구체적으로 지연은 "네트워크 패킷이 통신 시간 + 슬레이브에 업데이트 하는데 걸리는 시간 + α "의 지연 시간이 존재한다. 그 후 5.5 버전부터는 Semi-Synchronous 복제는 슬레이브 릴레이 로그에 업데이트가 기록된 것을 확인 한 후, 클라이언트에 응답을 반환하는 방식으로 트랜젝션 보완을 한 경우이다.



즉, 마스터 변경이 슬레이브 릴레이 로그에 기록되지 않는 한 클라이언트 에 응답을 반환하지 않는다. 마스터 업데이트 및 슬레이브 릴레이 로그 기록까지룰 "동기화" 범주로 보고 슬레이브 릴레이 로그에서 데이터베이스의 업데이트까지는 비동기이므로, "준 동기 (Semi-Synchronous)"라고 불린다.
여기서도 구체적으로 "슬레이브에 업데이트하는데 걸리는 시간 + α"시간이 지연된다고 볼 수 있다.

복제의 경우 지연, 그리고 마스터와 슬래이브 동기화 과정에서의 크래쉬 발생 등으로 데이터 불일치 요소들이 발생하게 된다.

2. sync_binlog
sync_binlog는 몇번의 트랜잭션마다 바이너리 로그를 디스크에 동기화를 설정하는 매개 변수이다. AUTO COMMIT 모드는 몇개의 명령문마다 동기화 할 것인지를 결정한다. 디스크에 동기화에는 fdatasync()를 사용한다. 디스크로의 동기화는 바이너리 로그의 안전성을 높이지만, 동기화 횟수가 많으면 성능이 떨어진다. 그러나 바이너리 로그의 손상, 특히 다수의 슬레이브를 사용하여 부하 분산을 수행하는 경우 아주 중요한 문제가 되기 때문에 최대한 피하고 싶을 것이다.
sync_binlog가 1로 설정되면 MySQL은 특별한 동작을한다. 트랜잭션이 InnoDB만 이루어진 경우, 2 단계 커밋을 사용하여 바이너리 로그가 InnoDB의 로그와 동기화하게되는 것이다.
이는 트랜잭션 파일 시스템(ext3, zfs 등)과 함게 사용하고 바이너리 로그를 데이터 디렉토리와는 다른 디스크에 저장하게 해서 안정성을 높일 수는 있다.

성능상 대부분 0으로 셋팅해서 운영한다. 그러면 sync_binlog = 0에서는 페일 오버시에 바이너리 로그가 손실되므로 복제시에 데이터 손실이 있을 수 있다.

3.innodb_flush_log_at_trx_commit
InnoDB 로그 파일에 대한 쓰기시의 움직임을 조정하는 매개 변수이다. 가능한 값은 0,1,2의 3 종류로, 각각 다음과 같은 의미가있다.
  • 0 : 로그 파일에 기록을 1초마다, 디스크의 플래시를 1초마다 실행한다. 커밋 때 아무것도하지 않는다.
  • 1 : 트랜잭션이 커밋 할 때마다 (커밋 완료하여 클라이언트에 응답을 반환하기 전에) 디스크에 기록하고 플래시를 실행한다. ACID의 D=Durability를 보장 할 수 있다.
  • 2 : 커밋 시 로그 파일에 기록하고, 디스크 플래시는 1 초에 한 번이다.
기본값은 1이며, 어지간한 일이 없는 한 기본적으로 사용되는 것을 권장한다. 또한 0보다 2 편이 낫다.

개선 방안은 어떤게 있는가?

MySQL의 Replication에서 슬레이브로 데이터 전송을 비동기적으로 수행함으로 인해 지연이 발생하고 네트워크나 마스터, 슬래이브 장애시 데이터 불일치가 존재한다.
sync_binlog = 0에서는 페일 오버시에 바이너리 로그가 손실되므로 복제시에 데이터 손실이 있을 수 있다. 즉, 트랜젝션이 중요한 비즈니스에서는 위험한 일이 아닐 수 없다.
그럼 대응책은 없을까?

1. Replication 지연 대응
  • 롱 트렌젝션을 제거하고
  • Slave 개수를 잘 조절하고
  • 부하량이 적은 환경에서 마스터와 슬레이브 간의 데이터 정합성을 강화시키는 Semi-syncronous 권장.
  • 작업 집합이 InnoDB 버퍼 풀보다 훨씬 큰 경우는 Slave pre-fetching 기술도 활용(SSD 포함). 자세한 설명은 아래에 기술한다.
*. Slave pre-fetching 기술
Slave pre-fetching 중 Replication Booster for MySQL가 가장 좋은 예여서 이부분에 대해서 기술해 본다.



MySQL에서 복제를 설정 한 경우, 마스터의 바이너리 로그를 IO 스레드가 읽어, relay-log에 기록하고 SQL 스레드가 relay-log를 읽어 테이블에 갱신을 하면서 동기화해 나간다. 이 때 SQL thread는 Random 디스크 I/O가 발생해서 지연이 생기게 된다. 그래서 랜덤 디스크 I/O를 발생시키지 않기 위해서 SQL Thread가 실행하기 전에 모든 변경 대상자를 캐시에 올린다면 SQL Thread는 랜덤 디스크 I/O가 발생하지 않는다. 그런 아이디어에 착안한 Replication Booster는 relay-log를 읽고, 업데이트 쿼리를 Select 쿼리로 재 작성해 SQL 스레드보다 먼저 테이블에 액세스한다. 따라서 InnoDB의 buffer_pool 등 메모리에, 앞으로 업데이트되는 데이터들을 실어 업데이트 쿼리 실행 시간을 줄이자는 것이다.

2. sync_binlog=1의 성능 개선
MySQL 5.6에서 sync_binlog=1의 성능이 크게 개선 된다고 한다. 기다려야 한다. ^^

3. Group commit for the binary log
MySQL은 5.6에서 지원 예정이고 MariaDB는 바이너리 로그에 대한 그룹 커밋을 지원한다. 이를 통해서 성능 개선 효과를 볼 수 있다. 그럼 그룹 커밋이 어떤 것일까?
그룹 커밋이 없는 경우, 아래 그림처럼 여러 클라이언트에서 커밋 요청은 순차적으로 처리 된다. DBMS의 특성인 ACID를 충족시키기 위해서 바이너리 로그에 기록할 수 있는 쓰레드는 동시에 하나다.



이렇게 되면 디스크에 동기쓰기를 해야돼 많은 성능 제약을 가져오게 된다. 이런 부분의 문제점을 개선해 주기 위해서 MariaDB 5.3에 이미 지원되고 있고, MySQL은 아직 정식 릴리즈 안된 5.6 버전에 안정화 버전이 포함되어 있는 것이 바로 Group commit이다.



Group commit은 말 그대로 클라이언트로부터 먼저 온 커밋 요청을 처리하는 동안, 다음 커밋 요청 받았을 경우, 디스크에 동기 쓰기를 한꺼번에 처리하는 것을 말한다. 이는 바이너리 로그에 기록 할 수있는 쓰레드가 동시에 하나 뿐이라는 점은 변함 없지만, 한 번의 fsync(2)로 여러 커밋 요청을 처리함으로써 초당 커밋 수를 크게 늘릴 수 있어 성능을 개선할 수 있다.
Group commit인 경우 대개 MariaDB에서는 트랜젝션이 중요한 비즈니스에서는 innodb_flush_log_at_trx_commit=1, sync_binlog=1 설정으로 운영하게 된다.

그리고 Group commit성능이 MariaDB가 가장 우수하다. 근거는 Facebook에서 비교해서 올린 자료를 보면 알 수 있다.



MariaDB의 활용성가 증가할 가능성 있는 한 요소다.

결론적으로 케이스별 테스트를 통해 최선의 선택을 해야할 듯 하다. MariaDB의 Group commit과 prefetching 기술을 적용하면 좋을 거 같다는 생각이 든다.
물론 benchmark 테스트와 데이터 정합성 테스트를 해 봐야 알겠지만.. ^^

[참조 사이트]


Re: 트랜잭션이 중요한 비즈니스에서의 MySQL에 대한 고민들

 http://gywn.net/2012/09/mariadb-galera-cluster/

위에 것도 도움이 될듯하네요. 다만 3rd party라 ㅎㅎㅎ

Re: 트랜잭션이 중요한 비즈니스에서의 MySQL에 대한 고민들

 네.. 저도 고거 좀 볼라구요. MariaDB에 급 관심이 생겨서.. ㅋㅋ


Add a comment Send a TrackBack