본문 바로가기

Advanced MySQL

2. MySQL Limitations Part 2 : The Binary Log

- 요약 -

This is the second in a series on what’s seriously limiting MySQL in certain circumstances (links: part 1).
In the first part,I wrote about single-threaded replication.
Upstream from the replicas is the primary, which enables replication by writing a so-called
binary log of events that modify data in the server.The binary log is a real limitation in MySQL.

이것은 특정한 상황에서 심각하게 제한적인 MYSQL에 대한 두번째 시리즈입니다.
첫 시간에는 single-threaded replication에 대해 논의하였습니다.
replicas에서 업스트림(서버로부터 파일을 전송 받았다고 다시 전기적 신호를 보내는 현상)에 기초합니다.
서버에 데이터 변경등의 이벤트가 발생할때 리플리케이션 쓰기를 사용한다면 바이너리 로그를 호출합니다.
MySQL에서 바이너리 로그는 정말 제한적입니다.


- 바이너리로그 -

The binary log is necessary not only for replication, but for point-in-time recovery, too. Given a backup and the corresponding binary log position, you can replay the binary log and roll forward the state of your server to a desired point in time.

바이너리 로그는 리플리케이션 뿐 아니라  point-in-time recovery를 위해 필요합니다.
백업을 감안할 때 일치하는 바이너리 로그의 위치로 사용자는 바이너리 로그를 다시 쓸 수 있으며,
서버를 원하는 시점의 상태로 roll forward 할 수 있습니다.



- 문제점 -

But enabling the binary log reduces MySQL's performance dramatically. It is not the logging itself that's the problem ?
writing the
log is usually not much additional work. It's ensuring consistency and durability that is expensive. Flushing it to disk adds an fsync call for every transaction. And the server performs an XA transaction between InnoDB and the binary log. This adds more fsync calls, and causes mutex contention, and prevents group commit, and probably other things that aren’t coming to mind now.

하지만 바이너리 로그가 활성화중이라면 MySQL의 성능은 극적으로 저하됩니다.
바이너리 로그는 스스로 로깅되지 않는 문제로 인하여 로그를 쓸때는 보통 추가 작업이 필요합니다.
이것은 일관성과 지속성을 보장하기 때문에 비용이 높습니다.
모든 트랜잭션은 fsync를 호출하여 메모리에 있는 내용을 디스크로 내려씁니다.
그리고 서버는 InnoDB와 바이너리 로그 사이에서 XA 트랜잭션을 수행합니다.
이것은 fsync를 더욱 호출하여, MUTEX(상호 경합) 논쟁 및 그룹 커밋을 방지, 그 외의 다른 것들이 있을 것입니다.

 The performance reduction can be an order of magnitude or more.
성능 감소는 범위를 더욱 늘어나게 할 수 있습니다.



- 해결책 -

What's the solution? I'm not sure I can summarize it concisely.
There is a lot of complexity, and honestly I don’t understand some of the server internals fully enough to have a 50-thousand-foot
view of it all. The binary logging and replication code, and its interaction with InnoDB, is difficult to understand.
Kristian Nielsen has an extensive series of posts on group commit alone.

해결책은 무엇입니까? 저는 해결책을 간결하게 요약할 확신이 없습니다. 
수 많은 복잡성과 솔직히 50만 피트의 서버 세부 내용을 모두 보지 못하기 때문에 이해할 수 없습니다.
바이너리로그와 리플리케이션 코드들이 이노디비와 함게 어떻게 상호 작용을 하는지 이해하기는 어렵습니다.
크리스티앙 닐슨(축구 선수) 혼자서 광범위한 포스트 시리즈에 대한 그룹 커밋을 하였습니다.   - 농담 -


I think that a full fix might require significant architectural changes to MySQL. This will be hard.
Maybe Drizzle is going in a good direction ? time will tell.
All of the solutions that I can think of are too simplistic.
For example, doing replication through the InnoDB transaction log would work fine if
a) all the data were in InnoDB,
b) InnoDB’s data didn’t have to be synchronized with the .frm files (and Drizzle has gotten rid of the .frm files, gotten),
c) privileges and other changes to the non-InnoDB data in MySQL were handled manually.

저의 생각에는 완전히 해결되기 위해서는 MYSQL의 중요한 아키텍처가 변해야 한다고 생각하지만 이것은 어려울 것입니다.
아마도 Drizzle(DBMS)이 좋은 방향을 제시할 것인지는에 대해서는 시간이 지나면 알게 될 것이다. 
제가 생각한 모든 해결책은 너무나 단순합니다.

만약 이노디비 트랜잭션 로그를 통하여 replication을 사용한다는 가정에서
 a) 모든 데이터가 InnoDB이라면
 b) InnoDB의 데이터를 .FRM 파일과 동기화할 필요가 없습니다. (그리고 Drizzle은 .FRM 파일을 제거하여 강력하다) 
 c) NON -InnoDB 데이터들에 대한 권한과 변경 사항을 수동으로 처리한다.

It could work if you just made sure that you didn't change privileges or schema, but that's a description of a pretty limited,
clunky replication system from the user's point of view. Still, I have considered it. There would need to be a mechanism of transporting the log files, and InnoDB would have to be put into a state of constant 'recovery,' and it would have to be modified to be available read-only in this state so that it could be used for read queries. This can be done, of course. It's just a matter of how hard it is.

만약 당신이 권한이나 스키마를 변경하지 않을 확신이 있다면, 위 설명대로 작동할 것입니다.
그러나 사용자의 관점에서는 굉장히 제한적인 묘사이며, 서투른 리플리케이션 시스템입니다.
여전히 나는 고려중이다. 이것들은 로그 파일 수송 메커니즘이 필요할 것이다.
그리고 이노디비는 지속적인 리커버리 상태가 되어야 하고, 이 상태에서 리드 온리가 가능하도록 변경되어야 한다.
그래야 리드 쿼리로 사용이 가능할 것이다. 이것은 가능한 구성입니다. 단순히 얼마나 어려운가의 문제일 뿐입니다.

It's worth noting that PBXT does replication through its transaction logs, so there's even precedent for this among MySQL storage engines. And there is Galera's multi-master synchronization technology to look at, too.

PBXT가 트랜잭션 로그를 통하여 리플리케이션을 하는 것은 아무것도 아니다.
MYSQL 스토리지 엔진에 중에는 이것에 대한 전례가 없습니다.
그리고 Galera의 multi-master 동기화 기술이 있습니다.

|출처| - http://www.mysqlperformanceblog.com/2010/10/23/mysql-limitations-part-2-the-binary-log/


 - 참조 설명 -

Drizzle from MySQL (Drizzle → MySQL)
Drizzle은 오픈소스 데이터 베이스 관리 시스템이다.  2008년 4월/5월 정도에 Brian Aker에 의해서 처음으로 시작되었다.
Drizzle은 MySQL 6.0버전의 코드베이스로부터 분기하였고 MySQL보다 더 작고 안정적이며 빠른 버전을 목표로 개발되었다고 한다.
Drizzle개발에 조력한 사람들로는 구글, 썬, 캐노니컬(우분투 프로젝트의 스폰서 회사) 그리고,
Six Apart(블로그 툴 개발 전문회사)출신들이 포함되어 있다고 한다.

MVCC (multiversion concurrency control)
MVCC는 다중 사용자 데이터베이스 성능을 위한 진보된 기술이다. MVCC와 다른 LOCK 모델간에 주요한 차이는,
MVCC에서는 질의하고 있는 데이터를 위해 획득된 락이 데이터 기록을 위해 획득된 락과 충돌하지 않으며,
따라서 데이터를 읽는 작업은 기록작업을 절대 방해하지 않고, 기록작업은 읽는 작업을 절대로 방해하지 않는다는 것이다. 
 
Mutex
둘 이상의 스레드가 동시에 공유 리소스에 액세스해야 할 경우 한 번에 하나의 스레드가 리소스를 사용하도록 하는 동기화 메커니즘이다. 공유 리소스에 대한 단독 액세스 권한을 하나의 스레드에만 부여하는 동기화 기본으로 스레드가 뮤텍스를 가져오면 첫 번째 스레드가
뮤텍스를 해제할 때까지 해당 뮤텍스를 가져오려는 두 번째 스레드는 일시 중단된다.
 -> 위의 글은 일반적인 MUTEX에 대한 설명이고, MYSQL에서의 mutex는 메모리 사용간의 이슈를 다룬다.

 

추가 참고 서적 (MYSQL 성능 최적화)


분산 (XA) 트렌잭션

스토리지 엔진 트랜잭션이 스토리지 엔진 안에 ACID(Atomicity, Consistency, Isolation, Durability) 속성을 부여하는 반면,
분산(XA) 트랜젹션은 더 상위의 트랜잭션으로 2단계 커밋을 이용해 일부 ACID 속성을 스토리지 엔진 밖으로
(심지어는 데이터베이스 밖으로) 확장한다.
MYSQL 5.0 과 그 이후 버젼은 XA 트렌잭션을 부분적으로 지원한다.

XA 트랜잭션엔 트랜잭션 코디네이터가 있어야 하는데, 코디네이터는 모든 트랜잭션 참가자에게 커밋할 준비가 됐는지 묻는다.(1단계)
'준비됨' 메세지를 모든 참가자에게서 받으면 코디네이터는 참가자들에게 커밋하라고 지시한다. 이게 2단계이다.
MySQL은 XA 트랜잭션에서 코디네이터(조정자)가 아닌 참가자로 행동한다.
실제론 MySQL에 XA 트랜잭션이 두 종류 있다. MySQL 서버는 외부적으론 관리되는 분산 트랜잭션에 참여할 수 있지만
XA를 내부적으로 사용해 스토리지 엔진들과 바이너리 로그를 조정한다.

내부 XA 트랜잭션

MYSQL이 내부적으로 XA 트랜잭션을 사용하는 것은 서버와 스토리지 엔진이 아키텍쳐상 분리되었기 때문이다.
스토리지 엔진은 서로 완전히 독립적이며, 서로를 알지 못한다. 따라서 여러 엔진에 걸친 트랜잭션은 자연히 분산되며, 제3의
누군가가 조정해주어야 한다. MYSQL 서버가 그 '제3자' 역할을 맡는다. 예를 들어 XA 트랜잭션이 없었더라면 교차 엔진 트랜잭션
커밋은 순서대로 각 엔진에게 커밋에 관여하냐고 물어야 했다. 이는 한 엔진이 커밋을 하고 다른 엔진이 커밋을 못한 상태에서 충돌이 날 가능성을 유발하며 이는 트랜잭션의 규칙을 어기는 일이다. (트랜잭션은 모두 성공하거나 모두 실패해야 한다는 사실을 떠올리자.)

바이너리 로그를 로그 이벤트용 '스토리지 엔진' 이라 생각해보면, 트랜잭션 엔진이 하나만 관여됐더라도 XA 트랜잭션이 왜 필수적인지
알 수 있다. 스토리지 엔진 커밋과 바이너리 로그에 이벤트를 '커밋' 하는 것을 동기화하는 일이 분산 트랜잭션이다.
서버(스토리지 엔진이 아니라) 가 바이너리 로그를 다루기 때문이다.

현재 XA는 성능 딜레마를 유발한다. MYSQL 5.0 이후로 XA는 InnoDB가 지원하는 그룹 커밋(group commit, 하나의 I/O 연산으로
트랜잭션 여러 개를 커밋하는 기술)을 깨뜨렸다. 그래서 XA는 원래보다 fsync() 호출을 더 많이 유발한다.
또 XA는 바이너리 로그를 켜면 트랜잭션마다 바이너리 로그 동기화를 요구하고, 커밋당 하나가 아닌 두 개의 로그 플러쉬를 요구한다.
달리 말해서 바이너리 로그가 트랜잭션과 안전하게 동기화되길 원한다면 트랜잭션 마다 적어도 세 번 fsync() 를 호출해야 한다.
이를 막는 유일한 방법은 바이너리 로그를 끄고 innodb_support_xa를 0으로 설정하라는 것이다.
이런 설정은 복제와 호환이 안된다.

복재는 바이너리 로그와 XA 지원이 필요하고 거기에다 (최대한 안전하려면) sync_binlog를 1로
설정해야 스토리지 엔진과 바이너리 로그가 동기화된다 (그렇지 않으면 XA 지원인 무용지물이다. 바이너리 로그가 디스크에 '커밋' 되지
않을 수도 있기 때문이다.)
이는 우리가 배터리 백업 쓰기 캐시를 갖춘 RAID 컨트롤러를 사용하라고 강력히 권하는 이유 중 하나다.
캐쉬는 추가적은 fsync() 호출 속도를 높이고 성능을 되살릴 수 있다.

-> 실제로 성능 이슈인 서버에서 배터리 캐쉬 사용 결과 비약적인 성능 향상이 이루어졌다.
-> fsync 는 일반적인 싱크 개념과는 다르다. 실제 해당 파일에 소속된 내용들만 메모리 영역에서 내려 쓰도록 한다. 


외부 XA 트랜잭션

MYSQL은 외부 분산 트랜잭션에 참여하되 관리하지 않는다. 완전한 XA 명세를 지원하진 않는다.
예를 들어 XA 명세는 단일 트랜잭션에 여러 연결이 합류하게 허용하지만 MYSQL에선 현재 불가능하다.
외부 XA 트랜잭션은 내부 XA 트랜젹션보다 훨씬 비싼데, 대기 시간이 추가되고 참가자 중 하나가
실패할 가능성이 더 높아지기 때문이다.
WAN이나 더 나아가 인터넷에서 XA를 사용하다 예측 못한 네트워크 성능 문제 때문에 고생하는 경우가 가장 많이 벌어지는 함정이다.
예측 못하는 컴포넌트, 이를 테면 느린 네트워크라던가 오랫동안 '저장' 버튼을 누르지 않는 사용자가 있을 때는 XA는 트랜잭션을
안 쓰는게 일반적으로 최선의 방법이다. 커밋을 지연시킬만한 요소는 모두 비용이 크다.
한 시스템에 그치지 않고 ,여러 시스템에서 지연을 발생시킬 잠재성이 있기 때문이다.
하지만 고성능 분산 트랜잭션을 다른 식으로 설계 할 수는 있다. 예를 들어, 데이터를 로컬에서 삽입하고 큐에 넣은 후 훨씬 작고
빠른 트랜잭션에 원자적으로 배포하면 된다. MYSQL 복제를 이용해 한 장소에서 다른 장소로 데이터를 보내도 된다.
우리는 분산트랜잭션을 쓰는 응용프로그램 중 일부는 분산 트랜잭션을 아예 쓸 필요가 없다는 사실을 발견했다.
XA 트랜잭션은 서버 간에 데이터를 동기화하기에 유용한 방법이 되기도 한다. 이 방법은 어떤 이유 때문에 복제를 사용하지 못한다든가 업데이트의 성능이 아주 중요한 문제가 아닐 때 좋다.

 
PBXT(Primebase XT) 엔진



PBXT 엔진은 독일 함부르크 SNAP Innovartion GmbH의 폴 맥컬라그(Paul McCullagh)가 개발했다. (http://www.primebase.com)
이 엔진은 트랜잭션 엔진으로서 설계가 독특하다. 주목할 만한 특징 중 하나는 트랜젹션 로그와 데이터 파일을 사용하여
WAL(Write - Ahead Logging)을 피하고 트랜젹션 커밋의 오버헤드를 최대한 줄인다는 것이다. 이러한 아키텍처는 PBXT가 고도의
쓰기 동시성 문제를 다룰 수 있는 가능성을 제공하며 테스트에서 실제 어떤 작업에 있어서는 InnoDB보다 빠르다는 점이 입증되었다.
PBXT는 MVCC를 사용하며 외래 키 제약을 지원하지만 클러스터 인덱스는 사용하지 않는다.
PBXT는 다소 새로운 엔진이며, 실제 업무 환경에서 기술을 더 입증해야 한다.
예를 들어 견고한 트랜잭션 기능은 최근에서야 구현되었다.
SNAP Innolvation은 PBXT의 확장 가능한 BLOB 스트리밍 기술을 개발하는 데 노력을 들이고 있다.(http://www.blobstreaming.org)
이는 커다란 바이너리 데이터를 효과적으로 저장하고 검색하기 위해 고안된 것이다.