바이너리의 단점

마지막 업데이트: 2022년 1월 27일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기

바이너리의 단점

C로 이미지,구조체등 바이너리 데이터를 MySQL에 담는 방법을 알아보자. 또한 C로 저장한 바이너리 데이터를 Flash에서 엑세스하는 법도 다루겠다.

이 글을 이해하려면 기본적으로 C와 ActionScript 3.0, Flex 4에 대해 알아야 한다. 그리고 예제에서 테스트한 C코드는 전부 이클립스+CDT+MinGW 환경에서 작업한 것들이다. 이런 환경을 구축해 본적이 없다면 다음 글을 참고한다.

1. Binary 타입 데이터를 DB에 저장하는 것에 대해
바이너리(Binary) 타입의 데이터를 DB에 저장한다는 것은 가령, 이미지나 사운드와 같은 데이터를 DB에 저장한다는 의미로 해석하면 편하다.

Binary파일을 DB에 넣을때 어떤 형태로 넣을 수 있을까?

한가지 예는 익히 잘 알고 있는 Base64로 치환해서 text형태로 넣는 방식을 생각해볼 수 있다. Base64는 ASCII코드로 화면에 출력할 수 있는 64개 문자(ABCD. 89+/e등)을 이용해 Binary 데이터를 Text로 표현해준다. 하지만 이 방식의 단점은 바이너리의 단점 데이타를 64진수로 표현한 문자열이기 때문에 용량이 필연적으로 커지고 또 encode/decode를 해야하는 부담이 존재한다. base 64에 대해서 알고 싶다면 다음 링크를 보자.

  • Base 64 - Wikipedia
  • 이미지 파일을 Base64로 인코딩하기
  • ByteArray를 String으로 변환해보자.

Base64는 아스키 시대의 유물이다. 요즘에는 pc에서 모바일까지 UTF8을 지원해주므로 이제 Base64에 의존하지 않고 Base256과 같은 것을 만들 수 있다. 이는 꽤 유용하다. 아래 hika님의 블로그를 보면 ActionScript 3.0으로 이와 관련된 글이 있다. 참고 바란다.

  • ByteArray를 문자열로 만들기

많은 DB에 BLOB(Binary Large OBject) 타입을 지원한다. 이 타입을 이용하면 DB에 어떤 형태의 Binary 데이타든지 넣을 수 있게 된다. 이 타입은 Text와 거의 동일하며 Binary 데이터를 넣을 수 있는 것만 다르다.

아래는 인터넷에서 찾은 BLOB에 대해 설명이다.

컴퓨터에서, BLOB[블랍]은 대체로 이미지나 사운드 파일과 같은 하나의 커다란 파일을 말하며, 그 크기 때문에 특별한 방법으로 다루어져야한다. 에릭 레이몬드에 따르면, BLOB에 관한 주요 아이디어는 DBMS와 같은 파일 처리기가 BLOB을 어떻게 처리할 것인가를 해결하기 위해 파일을 이해할 방법이 없다는 것이다. 다른 자료들에서는, 이 용어가 커다란 데이터 객체를 지칭하기 위해, 그리고 이러한 것들을 다룰 때 존재하는 문제점들을 암시하기 위해 만들어졌다고 강조한다. BLOB을 다루는 애플리케이션은 영화나 TV 프로그램 등과 같은 대형 멀티미디어 객체들의 데이터베이스 저장이다. BLOB은 이미지, 비디오, 사운드 등과 같은 멀티미디어 객체들을 저장하기 위해 주로 사용된다. 그러나 모든 DBMS가 BLOB을 지원하는 것은 아니다.

컴퓨터 그래픽에서, blob(소문자로 쓴 바이너리의 단점 BLOB)은 "재미있는 모양 형태"를 갖는 시각적 객체로서, 유연하고, 애니메이션을 따른다.

일반적으로, blob은 무정형이며, 정의를 내리기 힘든 객체이다. UFO 연구에서는 물론, 천문학에도 blob이라는 것이 있다. "The Blob"이라는 제목의 과학 공상영화도 있었다.

2. 이미지를 DB에 저장하기
사실 Binary타입의 일종인 이미지(jpg,png등)를 DB에 저장하는 예제는 정말 많다(php에서 만큼은. ). 그래서 굳이 여기에 예제를 적을 필요가 있겠냐만은.. 요즘 C를 이용해 다양한 시도를 하는 만큼, 이 부분도 적어본다.

필자는 앞서 Eclipse기반에서 C/C++ 개발을 위한 환경만들기에 관련된 글을 적었다.

  • Eclipse Galileo에서 C,C++ 개발환경 구축하기 - CDT, MinGW
  • Eclipse, MinGW, CDT 환경에서 C/C++과 MySQL 연동

간단히 이미지를 저장할 수 있는 테이블을 만들어보자. DB는 MySQL을 사용한다.

위와 같은 구조의 테이블을 만들것이다. 다음 Create문으로 위 테이블을 생성한다.

테이블을 만들때 data field가 mediumblob라는 것에 주목하자. 참고로 MySQL에서 BLOB타입은 Tiny BLOB(255, 2^8-1 bytes), BLOB(65,535=2^16-1 bytes), Medium BLOB(16777215=2^16-1 bytes), Long BLOB(4294967295=2^32-1 bytes)등을 지원한다.

다음은 임의 크기의 이미지를 불러와 제작한 테이블에 저장하는 C코드이다. (공개된 PHP코드는 많은데 이외로 C코드는 많이 없다.)

위 코드는 d:/image.png 를 로드해 DB 테이블에 insert 하는 과정을 보여주고 있다. 실제로 테스트가 완료되었고 잘 동작한다.

mysql_real_escape_string() 함수는 바이너리 데이터를 insert하기 위해 SQL insert 문을 작성하는데 있어서 '\0'과 같은 문자가 들어가는 것을 방지해준다. SQL insert문은 텍스트 데이터로 작성되어야 하므로 '\0'과 같은 문자가 중간에 삽입되어 있으면 그것이 문자열의 종료를 의미하기 때문에 이 함수의 호출은 필연적이다.

mysql_real_escape_string() 함수의 2번째 인자는 to, 3번째 인자는 from이다. 즉 from에서 '\0'과 같은 문자를 피하도록(escape) "\\0"등으로 치환해줘 그것이 to에서 참조되도록 하는 것이다. 이때 to의 사이즈는 from의 2배+1 이어야 한다. buf_to = (char*)malloc(file_size*2+1); 문에서도 볼 수 있듯이 buf는 file_size의 크기를 가지는데 buf_to는 그의 2배+1로 바이너리의 단점 메모리를 할당했다. 그 이유는 최악의 상황에서 escape처리할 문자가 from데이터의 2배가 될 수 있기 때문이다. 그리고 마지막 +1은 문자열의 마지막은 항상 '\0' 처리가 되어야 하므로 그 공간을 만들어주는 것을 의미한다.

mysql_real_escape_string()에 대해서는 다음 링크를 참고한다.

  • mysql_real_escape_string() 함수
  • 안전한 null-terminated 문자열 복사
  • mysql_real_query() 함수


코드를 보면 이미지를 insert하는 것보다 select하는게 오히려 쉽다. 실행후 마지막에 d:/savedImage.png가 있다면 성공한 것이다.


3. 구조체를 DB에 저장하기
대학시절 C언어의 구조체를 파일로 저장해본 경험이 있는가? 또 저장한 구조체를 다시 읽어 화면에 출력해본 적이 있는가? 이런 짓을 해봤다면 당신은 이미 DB에 구조체도 넣을 수 있다. 이 구조체도 일반 이미지와 같은 Binary파일이기 때문이다.

이 방법은 일반 이미지를 DB에 넣어본 경험이 있는 분이라면 쉽게 이해할 수 있다.

저장할 구조체를 만들어보자. 개인정보를 담는 아주 간단한 구조체인 Personal을 만든다.

분석할 것도 없다. 총 19bytes의 데이터를 담는 구조체를 만들었고 main함수에서 이 구조체의 크기를 출력한다.

하지만 이 프로그램을 실행하면 실제 구조체 크기인 19bytes가 아닌 20bytes로 출력된다. 왜 그럴까 찾아보다가 발견한 것이 struct member alignment라는 용어였고 이것을 설정하는 코드중에 #pragma pack()이 있다는 것이다.

  • struct member alignment에 대해

필자는 DB에 저장시에 하나의 Field에 여러명의 Personal 정보를 넣는것을 목적으로 하기 때문에 1~2bytes 차이가 저장되는 사람의 숫자만큼 증가되는 문제가 생길 수 있다. 이런 경우에 #pragma pack()을 적절히 사용하면 남는 공간을 줄일 수 있다.

#pragma pack는 온라인 게임이나 네트워크 프로그램에서 이기종간 통신 간 패킷단위를 struct로 정의해 통신하는 경우에 유용하다. 그리고 사용시 주의 사항도 있으므로 이에 대해서는 더욱 학습이 필요하다.


3.2 구조체를 담을 DB 테이블 제작

바이너리의 단점 구조체를 담을 DB 테이블은 다음 쿼리로 만들면 되겠다.

area가 key값이고 area별로 사람들의 데이터가 data에 담긴다. 이 data는 여러명의 데이터가 담겨질 것이다. 아마도 이게 유용한거냐?라는 질문을 한다면 이것은 한가지 예일 뿐이고 필자는 실제로 유용한 방법이였다. ^^


3.3 구조체 포인터 배열을 만들어 DB에 저장하고 읽어오기
구조체를 DB 테이블에 저장하는 것은 이미지를 저장할때와 별반 다른 것이 없다. 위에서 제시한 구조체로 이루어진 데이터의 경우가 특별할 것 같지만 실제로는 똑같다. 구조체를 만들때 user_id, user_name, age 순으로 만들었기 때문에 각각 2+15+2 = 19바이트가 1개의 개인정보 바이너리 데이터가 된다. 만약 2명이면 19x2=38 바이트의 바이너리 데이터가 되는 것이다. 이 모든 것을 수행하는 간단한 코드는 다음과 같다.

위 코드를 천천히 분석하면 어떻게 구조체 정보를 데이타베이스에 저장하고 읽어올 수 있는지 어렵지 않게 분석할 수 있을 것이다. 코드 자체는 연습용으로 급조된 거라서 중간중간 엉성한 부분은 그냥 넘어가자 ^^


4. ActionScript 3.0으로 바이너리 데이터 읽어오기

필자가 C를 지금까지 파고 든 가장 큰 목적은 Flash에서 C로 저장된 구조체 데이터를 읽어오는 것에 있다. ActionScript 3.0 API에는 바이너리 데이터를 다룰 수 있는 강력한 클래스가 존재한다. 그것은 ByteArray이다. 이 ByteArray를 이용하면 구조체 바이너리 데이터를 아주 쉽게 사용할 수 있게 된다.

DB에 저장된 바이너리 데이터를 Java로 로드해 AMF로 flash로 전송해주고 Flash에서는 이 데이터를 해석해 사용한다.

자바에서 해당 데이터를 로드할 때 변환되는 Value Object의 형태는 다음과 같을 것이다.

위 자바객체를 BlazeDS나 LCDS를 이용해 AMF(ActionScript Message Format)으로 전송하면 Flex나 ActionScript 3.0에서 직렬화되는 객체는 다음과 같을 것이다.

위 클래스에서 자바에서 AMF로 넘겨주는 PersonArea를 직렬화 처리하기 위해 [RemoteClass(alias="com.jidolstar.person.domain.PersonArea")] 를 사용했다는 것에 주목하자. 또한 자바의 byte[] 포멧은 ActionScript 3.0의 ByteArray로 직렬화 처리된다.

우리는 최종적으로 다음 ActionScript 3.0 클래스로 변환되기를 희망한다.

다음 코드는 이를 진행해 줄 Flex 4 코드이다.

위 코드에서 중요한 부분은 result_handler() 메소드 부분이다. ByteArray로 직렬화되어 들어온 데이터를 어떻게 읽어들이고 사용하는지 보여주고 있다. 중요한 것은 구조체의 정의시 user_id, user_name, age순으로 했기 때문에 ByteArray로 읽을때도 그와 같은 순으로 읽어야 하며 각각 읽어들일때 Byte도 잘 따져야 한다. 각각 2, 15, 2 바이트씩 총 19바이트를 저장했기 때문에 ByteArray에서 2바이트 정수를 읽어주는 readShort()메소드를 사용했다. 또한 문자열을 읽기 위해 readUTFBytes()를 이용했다.

//trace(data.readByte()); 으로 주석된 부분이 있다. 이 부분은 c코드에서 #progma pack(1)으로 처리하지 않았을때 구조체의 크기는 19바이트가 아닌 20바이트가 되므로 ByteArray로 읽을때 항상 1바이트가 남게된다. 그러므로 c코드에서 #progma pack(1)가 꼭 필요하다는 것을 여기서도 알 수 있다.

마지막으로 ByteArray를 읽기전에 data.endian = Endian.LITTLE_ENDIAN 처리를 했다. Endian의 종류는 두가지이다. Big Endian과 Little Endian이다. 이것은 데이타를 메모리에 쓰는 방식의 차이로 필자가 c코드를 돌려 구조체를 저장할때 방식이 Little Endian방식으로 저장했기 때문에 ByteArray로 넘어온 데이타도 그렇게 읽을 수 밖에 없게 된다. 이 방식의 차이와 장단점은 아래 링크를 통해 살펴보길 바란다.

바이너리 데이터를 데이타 베이스에 저장하고 최종적으로 Flash기반에서 로드하는 것까지 다뤄봤다. 꽤 많은 내용을 다룬 것 같지만 실상은 매우 단순하다. 바이트 단위로 데이타를 이해한다면 그리 어렵지 않은 내용들이며 결국 이런 처리를 익숙하게 할 수 있겠는가가 중요한 것 같다.

필자는 ActionScript나 Java등에 익숙하다 보니 이들 언어에서 메모리 관리등을 모두 다 해주니깐 게을러지는 것 같다. 이들 언어를 하더라도 c언어는 꾸준히 해주어야하고 종종 실무에도 적용해줘야겠다.

바이너리 코드

코딩에서 숫자, 문자 또는 단어가 특정 기호 그룹으로 표시 될 때 숫자, 문자 또는 단어가 인코딩되고 있다고합니다. 기호 그룹을 코드라고합니다. 디지털 데이터는 바이너리 비트 그룹으로 표현, 저장 및 전송됩니다. 이 그룹은binary code. 이진 코드는 숫자와 영숫자로 표시됩니다.

바이너리 코드의 장점

다음은 바이너리 코드가 제공하는 장점 목록입니다.

이진 코드는 컴퓨터 응용 프로그램에 적합합니다.

바이너리 코드는 디지털 통신에 적합합니다.

이진 코드를 사용하면 이진 코드는 디지털 회로를 분석하고 설계합니다.

0 & 1 만 사용하므로 구현이 용이합니다.

이진 코드의 분류

코드는 크게 다음 네 가지 범주로 분류됩니다.

  • 가중 코드
  • 비가 중 코드
  • 이진 코드 십진수 코드
  • 영숫자 코드
  • 코드 감지 오류
  • 오류 수정 코드

가중 코드

가중 이진 코드는 위치 가중치 원칙을 따르는 이진 코드입니다. 숫자의 각 위치는 특정 가중치를 나타냅니다. 코드의 여러 시스템이 10 진수 0에서 9까지를 표현하는 데 사용됩니다.이 코드에서 각 10 진수는 4 비트 그룹으로 표시됩니다.

비가 중 코드

이 유형의 2 진 코드에서는 위치 가중치가 지정되지 않습니다. 가중치가 적용되지 않은 코드의 예는 Excess-3 코드와 그레이 코드입니다.

초과 -3 코드

Excess-3 코드는 XS-3 코드라고도합니다. 십진수를 표현하는 데 사용되는 가중치가없는 코드입니다. Excess-3 코드 단어는 8421의 각 코드 단어에 (0011) 2 또는 (3) 10을 추가하는 8421 BCD 코드 단어에서 파생됩니다. 초과 -3 코드는 다음과 같이 구합니다.

그레이 코드

가중치가 적용되지 않은 코드이며 산술 코드가 아닙니다. 이는 비트 위치에 지정된 특정 가중치가 없음을 의미합니다. 그림과 같이 10 진수가 증가 할 때마다 1 비트 만 변경되는 매우 특별한 기능이 있습니다. 한 번에 하나의 비트 만 변경되므로 그레이 코드를 단위 거리 코드라고합니다. 회색 코드는 순환 코드입니다. 회색 코드는 산술 연산에 사용할 수 없습니다.

그레이 코드 적용

회색 코드는 샤프트 위치 인코더에서 널리 사용됩니다.

샤프트 위치 인코더는 샤프트의 각도 위치를 나타내는 코드 워드를 생성합니다.

BCD (Binary Coded Decimal) 코드

이 코드에서 각 십진수는 4 비트 이진수로 표시됩니다. BCD는 각 십진수를 이진 코드로 표현하는 방법입니다. BCD에서는 4 비트로 16 개의 숫자 (0000 ~ 1111)를 나타낼 수 있습니다. 그러나 BCD 코드에서는 이들 중 처음 10 개만 사용됩니다 (0000 ~ 1001). 나머지 6 개의 코드 조합, 즉 1010 ~ 1111은 BCD에서 유효하지 않습니다.

BCD 코드의 장점

  • 십진법과 매우 유사합니다.
  • 십진수 0에서 9까지만 이진수에 해당하는 것을 기억하면됩니다.

BCD 코드의 바이너리의 단점 단점

BCD의 더하기와 빼기에는 다른 규칙이 있습니다.

BCD 산술은 조금 더 복잡합니다.

BCD는 십진수를 나타 내기 위해 이진수보다 더 많은 비트 수가 필요합니다. 따라서 BCD는 바이너리보다 덜 효율적입니다.

영숫자 코드

이진 숫자 또는 비트는 '0'또는 '1'상태가 두 개뿐이므로 두 개의 기호 만 나타낼 수 있습니다. 그러나 이것은 통신을 위해 더 많은 기호가 필요하기 때문에 두 컴퓨터 간의 통신에는 충분하지 바이너리의 단점 않습니다. 이 기호는 대문자와 소문자, 0에서 9 사이의 숫자, 구두점 및 기타 기호로 26 개의 알파벳을 나타 내기 위해 필요합니다.

영숫자 코드는 숫자와 영문자를 나타내는 코드입니다. 대부분 이러한 코드는 정보 전달에 필요한 기호 및 다양한 지침과 같은 다른 문자를 나타냅니다. 영숫자 코드는 최소한 10 자리 알파벳 26 자 (총 36 개 항목)를 나타내야합니다. 다음 세 개의 영숫자 코드는 데이터 표현에 매우 일반적으로 사용됩니다.

  • 정보 교환을위한 미국 표준 코드 (ASCII).
  • EBCDIC (Extended Binary Coded Decimal Interchange Code).
  • 5 비트 Baudot 코드.

ASCII 코드는 7 비트 코드이고 EBCDIC는 8 비트 코드입니다. ASCII 코드는 전 세계적으로 더 일반적으로 사용되는 반면 EBCDIC는 주로 대형 IBM 컴퓨터에서 사용됩니다.

바이너리의 단점

기본적으로 Binary Search Tree와 Hash Table은 모두 키 & 값 형태로 자료를 저장하는 자료구조이다.

그렇기 때문에 사용성 측면에서는 굉장히 유사한 인터페이스를 갖고 있고, 지원하는 연산들도 아주 흡사하다.

그런 이유로, 자주 비교대상이 되는 자료구조로써 각각의 장단점을 한번쯤 정리해볼 필요가 있다.

탐색, 삭제, 삽입과 같은 기본기능들에 대해서,

해시 테이블의 해시 함수의 비용과, 충돌 해결비용까지 고려하더라도 데이터가 엄청 많아지는 경우에는 해시 테이블이 효과적이라고 볼 수 있다. 그리고 만약 입력 사이즈를 알고 있다면, 입력 사이즈에 맞게 최적화된 해시 함수를 이용하여 해시 테이블의 해시 값을 균일하게 분포시켜서 성능을 최적화시킬 수 있을 것이다.

하지만 이진탐색트리에는 데이터들의 순서가 정렬된 상태로 유지된다는 강력한 장점이 있다.

이 특성으로 인해 데이터를 정렬된 형태로 순회할 수 있다는 장점도 있겠지만,

아주 좋은 성능으로 범위기반 쿼리가 가능하다는 장점도 있다.

그러므로 순서와 밀접한 연관이 있는 데이터를 다루는 상황에서는 이진탐색트리가 효과적일 것이다.

또한 문자열과 같은 데이터를 다루는 상황에서는 키의 동등 비교를 수행하는 해시 테이블보다, 키의 크기 비교를 수행하는 이진트리가 유리할 것이다.

이진탐색트리는 딱 필요한 원소 만큼의 공간만을 할당하는 반면, 해시 테이블은 해시 적중률을 높이기 위해 원소의 개수 이상의 메모리를 유지해야한다. 그러므로 사용량 측면에서는 이진탐색트리가 유리하다.

이진탐색트리는 노드 기반 자료구조로 메모리 파편화가 진행되어 캐시 적중률이 떨어지게 된다.

반면, 해시 테이블은 배열 기반 자료구조로 연속된 메모리를 유지하기 때문에 캐시 적중률이 상당히 높다.

두 자료구조는 외부적으로는 키&값을 사용하는 자료구조로 굉장히 흡사한 인터페이스를 갖고 있지만,

내부적으로는 완전히 다른 형태로 데이터를 관리한다. 그렇기 때문에 어떤 자료구조가 반드시 더 좋다고 결론을 지을 수는 없고, 데이터의 형태나, 환경, 상황에 맞게 적절한 자료구조를 선택하는것이 좋을 것이다.

바이너리의 단점

개념할당된 클래스를 바이너리화 하는 것을 직렬화 라고 합니다.

이 직렬화를 하는 이유 에 대해서는 클래스의 상태를 저장 혹은 소켓 통신을 통해 전송하기 위해서 사용합니다.

최근에는 Json형태로 데이터를 저장하는 경우가 많아서 직렬화를 잘 사용하지 않는데 Json형태로 저장하는 것은 Class에서 취득할 수 있는 부분까지 저장하는 것이고 private까지 저장하는 것은 아무래도 힘듭니다.

뭐 하고자 하면 Reflection을 통해서도 할 수 있겠지만, 그렇게 하는 것보다는 직렬화를 해서 클래스의 상태를 저장하는 것이 더 효율적이라고 할 수 있습니다.

직렬화 단점

직렬화는 클래스의 상태를 가장 편하게 데이터화 할 수 있으나 몇가지 단점 이 있습니다.

첫번째 는 이 직렬화된 데이터를 메모장에서 열어보면 사람이 이해하기 힘든 구조로 되어있습니다. 즉, 직렬화된 데이터는 역직렬화를 하기 전까지는 데이터를 알 수가 없습니다.

그의 반해 json은 String형태로 되어 있기 때문에 메모장으로 열어도 확인이 가능하고 직접 수정도 가능합니다. 직렬호 데이터는 아무래도 그게 힘드네요.

두번째플렛폼의 호환성을 좋지 않습니다. 즉, java에서 직렬화 시킨 데이터는 C#에서 역직렬화가 되지 않습니다. 정확하게는 되지 않는 것은 아닙니다만, 정보의 유실이 발생할 수 있습니다.

Overview

MySQL에서는 이러한 이벤트들을 Binary log 파일에 로깅할 때 로깅 포맷을 어떻게 가져갈 것인가에 대해 사용자가 선택할 수 있도록 binlog_format 이라는 설정변수(system variable)를 제공하고 있다.

  • binlog_format
    사용자는 아래 3가지 타입 중 하나를 선택하여 설정할 수 있다.
    # Possible values
    - STATEMENT : logging to be statement based
    - ROW : logging to be row based (Default value, >= 5.7.7)
    - MIXED : logging to use mixed format (statement와 row image가 mix되어 로깅됨)
    (MySQL 5.7.7 이전까지는 statement-based logging format이 디폴트 값이였으며, 5.7.7 부터는 row-based logging format 이 디폴트 값으로 지정되었다.)

Row-based logging format 에서 각각의 row change event 들은 before/after 2개의 row image (row data column set) 를 포함한다.

  • Before Image : 변경되기 전 row image
  • After Image : 변경된 row image

보통 MySQL에서는 Before Image, After Image 모두 full row image (all columns) 로 로깅하나, 사실 두 이미지 모두 모든 컬럼이 로깅될 필요는 없다. 필요로하는 최소 컬럼셋만 기록하면 되는 것이다.

  • Before Image
    : row를 유니크하게 식별할 수 있는 최소한의 컬럼 셋이 필요. PK가 있다면 PK가 로깅되고 UK(all not null) 가 있다면 유니크키가 로깅됨. PK & UK (without any null columns) 둘 다 바이너리의 단점 없으면 전체 컬럼들이 모두 기록됨.
  • After Image
    : 변경된 컬럼만 기록

이는 Statement-based 보다 빠르고 안전하다는 장점이 있지만 변경되는 row image가 모두 기록되다보니 대량의 delete/update 작업이 발생할 경우 디스크 용량, 네트워크 트래픽 등이 문제가 될 수 있었고 이러한 단점으로 인해 보통은 Statement-based를 사용하는 경우가 많았다.

MySQL 5.6.2 부터 binlog_row_image 라는 설정 변수가 도입되면서, Row-based logging format 일 때 row image를 최소 컬럼셋으로 로깅하게할지 full로 로깅하게할지 사용자가 선택할 수 있게 되었고 이를 통해 row-based logging format 을 사용할 때의 단점들도 보완할 수 있게 되었다.

  • binlog_row_image
    Row Before Image & After Image 에 저장될 column set을 결정하는 변수
    # Possible values
    - full: Log all columns in both the before image and the after image. (Default value)
    - minimal: Log only those columns in the before image that are required to identify the row to be changed; log only those columns in the after image that are actually changed.
    - noblob: Log all columns (same as full), except for BLOB and TEXT columns that are not required to identify rows, or that have not changed.
  • binlog_row_image 사용 시 주의 사항
    - mysql 5.5 와 그 이전 버전에서는 full image 만 사용하므로, 그보다 더 높은 버전에서 5.5 혹은 그 이전 버전을 슬레이브로 둔다면 full을 사용해야 한다.
    - minimal 바이너리의 단점 바이너리의 단점 / noblob mode를 사용하는 환경에서 delete/update 가 제대로 동작하기 위해서는 source 및 destination table에서 아래 조건들이 충족되어야 한다.
    1) 복제되는 테이블은 src와 dest에서 컬럼이 동일하게 존재해야하고 (컬럼 순서도 동일), 바이너리의 단점 컬럼 데이터 타입도 같아야 한다.
    2) 복제되는 테이블은 PK 정의가 동일해야 한다. (즉, PK가 아닌 인덱스들을 제외하고는 테이블 정의가 같아야 함.)
    이 조건들이 모두 충족되지 않는 경우, destination table 에서 실제 delete/update 에 해당되는 대상 row에 정확하게 적용되지 않을 가능성이 있으며 이 경우 warning 이나 error 메세지가 발생하지 않기 때문에 쥐도새도 모르게 마스터-슬레이브 간 데이터 정합성이 깨질 수 있다.

하지만 binlog_row_image 라는 변수가 도입되었고 또 5.7.7 에서 binlog_format의 디폴트 값이 Row-based 로 지정된 만큼, 실제로 Row-based 일 때에 문제였던 부분이 나아졌는지 확인하기 위해 테스트를 진행해보았다.

Description

테스트는 MySQL version 별로 Row-based/Statement-based 일 때 하루치 Binary Log 전체 사이즈가 얼마나 차이나는지 비교해보는 방식으로 진행하였다.

우리 서비스들에서는 대량의 데이터 변경 작업이 지속적으로 진행되는 서비스가 많지 않고 대부분 OLTP성 서비스들이므로, Binary Log 양을 의도적으로 많이 쌓이게끔하여 극한의 환경에서의 사이즈/리소스 비교를 진행하진 않았음을 참고바란다.

테스트 환경 구축
1) 테스트 DB 서버들의 gtid_mode 는 모두 OFF 로 설정하였다.
2) 선정은 대부분의 데이터가 Integer Type 인 것과 대부분의 데이터가 String Type 인 것 두 가지를 선정하여 서로 다른 두 환경에서의 Binary Log 양을 비교한다.
3) Binary Log 사이즈에 영향을 줄만한 MySQL 설정변수들을 전부 살펴보면서 Binary Log에 최대한 불필요한 정보가 들어가지 않고 일반적으로 사용되는 셋팅으로 변수값을 설정하여 테스트를 진행한다.

위 조건들을 바탕으로 선정한 서비스 및 테스트 DB 설정 변수들은 다음과 같다.

Test1Test2
Binary Log Size일별 100G 정도 쌓일 경우일별 100~200G 정도 쌓일 경우
MySQL VersionMariaDB 5.5.24MySQL Facebook 5.6.23
Data Type대부분 Integer (int, bigint)대부분 String (char, varchar, TEXT)
Related Variablesbinlog_format
binlog_row_image (>= 5.6.2)
binlog_rows_query_log_events (>= 5.6.2)


* binlog_rows_query_log_events
5.6.2 부터 도입된 설정변수로 row-based logging format 일 때 해당 변수가 Enable 되어있으면 Binary log에 Row query log event 와 같은 정보성 로그 이벤트들이 기록된다.
Default 값은 OFF 이며, 테스트 DB들은 모두 Default 값 (즉 Disable) 그대로 설정하였다.


0 개 댓글

답장을 남겨주세요