MySQL Master-Slave 복제 환경에서 Binary Log 특징

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

[번역] Go 둘러보기 - encoding 패키지

Nov 9, 2016 00:00 · 5053 words · 11 minute read go walkthrough encoding

우리는 이제까지 로우(raw) 바이트 스트림과 제한된 바이트 슬라이스를 다뤄봤지만 단순히 바이트만을 사용하는 애플리케이션은 별로 없다. 바이트 자체는 많은 의미를 전달해주지 않지만 바이트 위에서 데이터 구조를 인코딩 한다면 우리는 진정으로 유용한 애플리케이션을 구축할 수 있다.

이 포스트는 표준 라이브러리를 이해하는데 도움을 주기위한 Go 둘러보기 시리즈의 일부이다. 기존에 생성된 문서(자동으로 생성된 Go 문서)는 많은 정보를 제공하지만, 이는 패키지를 실제 상황에서 이해하기에는 어려울 수 있다. 이 시리즈는 일상적으로 사용되는 애플리케이션에서 표준 패키지들이 어떻게 사용되는지에 대한 컨텍스트를 제공할 수 있도록 도와준다. 질문이나 코멘트가 있다면 트위터에서 @benbjohnson로 찾아오면 된다.

인코딩이란 정확히 무엇인가?

컴퓨터 과학에서는 간단한 개념에 대한 팬시한 단어들이 있다. 이 뿐만 아니라 많은 경우 하나의 개념을 지칭하는 많은 팬시한 단어들이 존재하기도 한다. 인코딩(Encoding) 은 그 중 하나이다. 가끔 이는 시리얼라이제이션(serialization) 또는 마샬링(marshaling) 으로 불리기도 하며 이는 모두 로우(raw) 바이트에 논리적 구조체를 더한다는 것을 의미한다.

Go 표준 라이브러리에서, 우리는 두 가지의 분리되었지만 서로 관련이 있는 아이디어를 위해 encodingmarshaling 라는 용어를 사용한다. Go에서 encoder 는 구조체를 바이트 스트림에 적용하는 객체인 반면 marshaling 은 구조체를 제한된 인메모리 바이트에 적용하는 것을 말한다.

예를 들면, encoding/json 패키지는 각각의 io.Writer와 io.Reader로 작업을 하기 위한 json.Encoder와 json.Decoder를 가지고있다. 이 패키지는 또한 바이트 슬라이스에 데이터를 쓰고 읽기 위한 json.Marshaler과 json.Unmarshaler를 가지고 있다.

두 가지 타입의 인코딩

인코딩간에는 또 다른 중요한 차이점이 있다. 몇몇의 인코딩 패키지는 문자열, 정수등의 프리미티브에서 동작한다. 문자열은 아스키나 유니코드 또는 다른 언어별 인코딩과 같은 문자 인코딩을 가지고 인코딩이 된다. 정수는 엔디안(endianness)기반 또는 가변 길이 인코딩에 따라 조금 다르게 인코딩 될 수 있다. 심지어 바이트자체는 종종 출력가능한 문자들로 변환 하기위해 Base64와 같은 방식으로 인코딩된다.

그러나 우리는 종종 인코딩이라고 하면, 객체 인코딩을 떠올린다. 이는 구조체(structs), 맵(maps), 그리고 슬라이스(slices) 같은 복잡한 구조체들을 바이트열로 변환하는것을 지칭한다. 이런 변환을 하는데 있어선 많은 트레이드 오프가 있으며 오랜 시간에 걸쳐 많은 사람들이 서로 다른 객체 인코딩 방식을 개발해왔다.

타협(Trade-offs)하기

이 구조체들은 이미 내부적으로 바이트 형태의 인메모리로 표현되기 때문에 처음엔 논리적 구조체를 바이트로 변환하는게 충분히 간단해 보일 수 있다. 그냥 이 포맷을 사용하면 되지 않나?

왜 Go의 인메모리 포맷이 바이트를 변환해서 디스크에 저장하거나 네트워크를 통해 전송하는데에 적합하지 않은지에 대한 이유는 다양하다. 첫번째로 호환성이다. Go의 내부 데이터 구조 포맷은 Java의 내부 포맷과 맞지 않기에 우리는 서로 다른 시스템간 통신을 할 수가 없다. 가끔 우리는 프로그래밍 언어가 아닌 사람과의 호환성이 필요하다. CSV, JSON, 그리고 XML은 모두 사람이 읽을 수 있는 포맷이며 보거나 수정하기가 쉽다.

사람이 읽기 가능한 포맷을 만드는것은 트레이드 오프를 이끌어낸다. 사람이 분석하기 쉬운 포맷은 컴퓨터가 분석하기에는 느리다. 정수가 좋은 예이다. 사람은 정수를 10진법으로 읽지만 컴퓨터는 2진법으로 동작한다. 사람은 또한 1또는 1,000과 같은 가변 길이의 숫자를 읽을 수 있지만 컴퓨터는 32비트나 64비트의 정수와 같은 고정 크기의 숫자를 가지고 동작한다. 성능이 숫자 하나에 대해선 별로 차이가 없어 보일 수 있지만 수백만, 수십억개의 숫자를 분석할 때에는 그 차이가 빠르게 벌어진다.

또한 우리가 처음에 생각하지 않은 다른 트레이드 오프도 있다. 데이터 구조는 시간이 지나면서 변하지만 우리는 여전히 오래전에 인코딩된 바이트 위에서 동작을 시켜야 할 필요가 있다. 프로토콜 버퍼(Protocol Buffers)와 같은 몇몇 인코딩은 여러분의 데이터와 필드의 버전(새로운 필드가 추가될 수 있는 반면, 이전 필드가 더 이상 사용되지 않을 수 있다)에 대한 스키마를 작성할 수 있도록 해준다. 이것의 단점은 객체를 인코딩하고 디코딩 하기위해선 스키마 정의가 필요하다는 것이다. Go의 자체적인 gob 포맷은 다른 방법을 택하는데 실제로 인코딩시 스키마 포맷을 포함한다. 그러나, 이 방법의 단점은 인코딩 사이즈가 매우 커질 수 있다는 것이다.

일부 포맷은 전적으로 주의를 기울여야 하고 유연한 스키마를 지향한다. JSON과 MessagePack는 여러분이 바로 구조체를 인코딩 하도록 해주지만 기존의 포맷에서 구조체를 안전하게 디코딩 하는것에 대한 보장을 제공해주진 않는다.

우리는 또한 따로 인코딩을 생각하지 않아도 우리를 위해 인코딩을 대신 수행해주는 시스템을 사용한다. 예를 들면, 데이터베이스는 우리의 논리적 데이터 MySQL Master-Slave 복제 환경에서 Binary Log 특징 구조를 가지고 이들을 디스크에 바이트로 영구 저장하는 우회적인 방법이다. 이는 네트워크 호출, SQL 파싱, 그리고 쿼리 계획을 포함 할 수 있지만 이들은 모두 기본적으로 인코딩이다.

마지막으로, 만약 여러분이 다른 것들보다 정말로 속도가 필요하다면, 데이터 저장을 위해 Go의 내부 포맷을 사용할 수 있다. 심지어 나는 이를 위해 raw라는 라이브러리를 만들기도했다. 이것의 인코딩과 디코딩 시간은 말그대로 0초다. 여러분은 이걸 프로덕션 환경에서 사용해야 하는가? 아마 아닐 것이다.

4가지 인코딩 인터페이스

만약 여러분이 encoding 패키지를 들여다본 몇 안되는 사람들 중 한 명이라면, 조금 실망했을 것이다. 이는 errors 패키지 다음으로 두번째로 가장 작은 패키지이며 단 4개의 인터페이스만 가지고있다.

이들은 객체를 바이너리 포맷으로 변환하거나 역변환하는 방법을 제공한다. 이는 time.Time.MarshalBinary와 같은 표준 라이브러리에서 몇군데 사용된다. 여러분은 이를 많이 보진 못할텐데 보통 객체를 바이너리 포맷으로 마샬링하는 방법이 단일하게 정의되어 있지 않기 때문이다. 보다시피, 수많은 serialization 포맷이 있다.

그러나, 애플리케이션 레벨에서 여러분은 아마 마샬링을 위해 하나의 포맷만 선택할 것이다. 예를 들면, 여러분은 여러분의 모든 데이터에 대해 프로토콜 버퍼를 선택 했을 수 있다. 일반적으로 애플리케이션 데이터를 위해 여러개의 바이너리 포맷을 지원할 이유가 없으므로 BinaryMarshaler를 구현하는건 의미가 있다.

이 두 인터페이스는 출력값이 UTF-8 포맷인걸 제외하고는 바이너리 마샬링 인터페이스와 유사하다.

몇몇 포맷은 json.Marshaler와 같이 동일한 네이밍 스타일을 따르는 자체적인 마샬링 인터페이스 가지고 있다.

인코딩 패키지 개요

표준 라이브러리에는 많은 유용한 인코딩 패키지들이 있다. 우리는 이들의 자세한 내용들은 나중 포스트에서 다룰 것이지만 일단 개요를 살펴보고자 한다. 이들 중 몇몇은 encoding 의 서브패키지인 반면 그 외에는 다른 곳에 뿔뿔이 흩어져 있다.

프리미티브 인코딩

Go를 시작할 때 처음으로 사용하게될 패키지는 아마 fmt 패키지일 것이다. (“fumpt"라 발음한다.) 이는 숫자, 문자열, 바이트, 그리고 일부 지원되는 객체 인코딩까지 포함한 것들을 인코딩 및 디코딩 하기 위해 C 스타일의 printf() 컨벤션을 사용한다. fmt 패키지는 템플릿으로부터 사람이 쉽게 읽을 수 있는 문자열을 훌륭하고 쉽게 만들 수 있는 방법을 제공하지만 템플릿 파싱은 추가적인 오버헤드를 발생시킬 수 있다.

만약 더 나은 성능이 필요하다면 문자열 변환 패키지인 strconv을 사용함으로써 템플레이팅을 피할 수 있다. 이는 기본적인 포맷팅 그리고 문자열, 정수, 실수, 그리고 부울을 위한 스캐닝을 제공하는 로우 레벨 패키지이며 매우 빠르다.

Go 자체와 함께 이 패키지들은 여러분이 UTF-8의 문자열을 인코딩함을 가정한다. 표준 라이브러리에서 유니코드가 아닌 문자의 인코딩 지원이 미약한건 지난 수년간에 걸쳐 UTF-8의 표준이 인터넷의 많은 부분을 빠르게 지배하고 있기 때문에 가능하거나 Rob Pike가 Go와 UTF-8의 공동개발자이기 때문에 가능한일 일 것이다. 누가 아는가? 나는 운좋게도 여태까지 Go에서 비 UTF-8의 인코딩을 처리할 필요가 전혀 없었다. 그러나, unicode/utf16, encoding/ascii85, 그리고 golang.org/x/text 패키지 트리에 몇가지 인코딩 지원이 있긴하다. “x” 패키지 트리는 Go 프로젝트의 일부로 엄청난 패키지들을 많이 포함하고 있지만 Go 1 호환성 요건으로는 적용되지 않는다.

정수 인코딩을 위해, encoding/binary 패키지는 큰 엔디안과 작은 엔디안 인코딩뿐만 아니라 가변 길이의 인코딩도 제공한다. 엔디안이란 바이트가 디스크에 쓰여지는 순서를 가리키는 말이다. 예를 들면, 1,000 (16진법으로는 0x03E8) 의 uint16 표현식은 두 바이트 03E8 의 조합으로 이루어진다. 큰 엔디안 인코딩에서는 바이트가 “03 E8"의 순서로 쓰여진다. 작은 엔디안에서는 “E8 03"으로 순서가 뒤바뀐다. 많은 일반적인 CPU 아키텍처는 작은 엔디안을 MySQL Master-Slave 복제 환경에서 Binary Log 특징 사용한다. 그러나, 큰 엔디안은 보통 네트워크를 통해 바이트를 전송할 때 사용된다. 큰 엔디안은 그래서 (네트워크 바이트 순서) network byte order 라고도 한다.

마지막으로, 바이트 인코딩을 위해 사용할 수 있는 패키지 쌍이 있다. 바이트 인코딩은 보통 바이트를 출력가능한 포맷으로 변환하는데 사용된다. 예를 들면, encoding/hex 패키지는 바이너리 데이터를 16진법으로 볼 필요가 있을때 사용될 수 있다. 나는 개인적으로 디버깅 목적으로만 사용해봤다. 반면, 가끔은 역사적으로 제한된 바이너리 지원 (예로 이메일이 있다.)을 가지고 프로토콜 위에서 데이터를 전송해야하기 때문에 출력가능한 포맷이 필요할 때도 있다. encoding/base32과 encoding/base64 패키지는 이의 한 예이다. 또 다른 예시는 TLS 인증서를 인코딩 하기 위해 사용되는 encoding/pem 패키지가 있다.

객체 인코딩

우리는 표준 라이브러리에서 객체 인코딩을 위한 몇개의 패키지들을 찾았다. 그러나 실제로 이 패키지들은 우리가 필요로 하는 모든 것들을 가지고 있다.

만약 여러분이 지난 10년간 세상을 등지고 살아왔다면, 아마 JSON이 인터넷의 기본 객체 인코딩이 되었다는 것을 알아챘을 것이다. 위에서도 언급했듯이, JSON은 결점을 가지고 있지만 사용하기가 쉬우며 모든 언어에서 라이브러리가 지원 되기 때문에 채택이 급증했다. encoding/json 패키지는 이 프로토콜을 위한 훌륭한 지원을 제공하며 ffjson과 같은 빠른 파서를 생성하기 위한 서드파티 구현체들 또한 존재한다.

JSON이 머신 사이의 프로토콜로서 지배하고 있는 동안, CSV 포맷은 사람들에게 데이터를 내보내기 위한 더 일반적인 프로토콜이다. encoding/csv 패키지는 테이블 형식의 데이터를 이 포맷으로 내보내기 위한 좋은 인터페이스를 제공한다.

만약 여러분이 약 2000년경에 구축된 시스템과 상호 MySQL Master-Slave 복제 환경에서 Binary Log 특징 작용을 하는 경우엔 아마 XML을 사용해야 할 것이다. encoding/xml 패키지는 json 패키지와 유사한 추가적인 태그 기반 marshaler/unmarshaler를 가진 SAX 스타일의 인터페이스를 제공한다. 만약 DOM, XPath, XSD, 또는 XSLT같은 좀 더 복잡한 기능들을 찾고 있다면 아마 cgo를 통한 libxml2을 사용해야 할 것이다.

Go는 또한 gob라고 하는 자체적인 스트림 인코딩을 가지고 있다. 이 패키지는 두 Go 서비스간의 원격 프로시저 호출을 구현하기 위한 net/rpc 패키지에의해 사용된다. Gob은 사용하기가 쉽다. 그러나 이는 그 어떤 언어 크로스도 지원하지 않는다. 만약 서로 다른 언어간 통신이 필요하다면 gRPC가 인기있는 대안이 될 수 있을 것 같다.

마지막으로, encding/asn1라는 패키지가 있다. 문서에는 제한된 정보만 있고 패키지에는 오직 25페이지의 텍스트로 이루어진 layman의 ANS.1 가이드에 대한 링크만 있다. ANS.1은 특히 SSL/TLS의 X.509 인증서에 많이 사용되는 복잡한 객체 인코딩 스키마이다.

인코딩은 바이트 위에서 정보를 레이어링 하기위한 기초적인 기반을 제공한다. 이게 없다면 우린 문자열이나 데이터 구조나 데이터베이스 또는 그 어떤 유용한 애플리케이션도 가질 수 없을 것이다. 상대적으로 간단한 개념처럼 보이는것이 많은 구현의 역사와 다양한 트레이드 오프를 가지고 있다.

이 포스트에서 우리는 표준 라이브러리에 있는 다양한 인코딩 구현의 개요와 그것들의 트레이드 오프들을 살펴봤다. 우리는 이러한 프리미티브와 객체 인코딩 패키지가 우리의 바이트 스트림과 슬라이스의 지식선상에서 어떻게 구현되는지를 보았다. 다음 몇 개의 포스트에선 실제 상황에서 이들을 어떻게 사용할 수 있는지를 알아보기 위해 이 패키지들을 좀 더 깊이 파헤쳐 볼 것이다.

MyInfraBox

복제를 사용할 때 이진 로그에 대해 어떤 타입을 선택할지 정해야 하는데 이때 아래 내용들을 참고해서 설정하시면 도움이 됩니다 . 복제를 할 때 safe( 안전한 ), unsafe( 안전하지 않은 ) 쿼리가 있는데 이것을 알면 업무 특성에 따라 어떤 바이너리 로그로 설정할지 도움이 됩니다 .

■ Binary Logging 의 종류

▶ Statement-based Binary Logging

Staatement-based 바이너리 로깅을 사용할 때 마스터는 SQL 문을 바이너리 로그에 씁니다 . 슬레이브에서 마스터를 복제하면 슬레이브에서 SQL 문을 실행합니다 . 이를 Statement-based Replication (SBR 로 약칭 할 수 있음 ) 이라고하며 , 이는 MySQL Statement-based 바이너리 로깅 형식에 해당합니다 .

▶ Row-based Logging

행 기반 로깅을 사용하는 경우 마스터는 개별 테이블 행이 변경되는 방법을 나타내는 이벤트를 이진 로그에 씁니다 . 마스터에 대한 슬레이브 복제는 테이블 행의 변경 사항을 나타내는 이벤트를 슬레이브에 복사하여 작동합니다 . 이를 Row-based Replication(RBR 로 약칭 할 수 있음 ) 이라고합니다 .

▶ mix of both statement-based and row-based logging

변경 내용을 기록하기에 가장 적합한 명령문 기반 (statement-based) 및 행 기반 (row-based) 로깅을 함께 사용하도록 MySQL 을 구성 할 수도 있습니다 . 이것을 혼합 형식 로깅이라고 합니다 . 혼합 형식 로깅을 사용하는 경우 기본적으로 명령문 기반 로그 (statement-based) 가 사용됩니다 . 특정 명령문과 사용중인 스토리지 엔진에 따라 로그가 자동으로 행 기반으로 전환됩니다 . 혼합 형식을 사용한 복제를 혼합 기반 복제 또는 혼합 형식 복제라고합니다 .

■ Statement-Based 복제의 장점과 단점

이미 입증된 기술로 , 로그 파일에 적은 데이터가 기록됩니다 . 업데이트 또는 삭제가 많은 행에 영향을주는 경우 로그 파일에 필요한 저장 공간이 훨씬 줄어 듭니다 . 또한 백업을 가져오고 복원하는 것이 더 빠르게 수행 될 수 있음을 의미합니다 . 로그 파일에는 데이터베이스를 감사하는 데 사용할 수 있도록 변경 한 모든 명령문이 포함됩니다 .

+ statement-based 복제는 안전하지 않습니다(unsafe) . 명령문 기반 (statement-based) 복제를 사용하여 데이터를 수정하는 모든 명령문 ( 예 : INSERT DELETE, UPDATE 및 REPLACE 문 ) 을 복제 할 수있는 것은 아닙니다 . 명령문 기반 (statement-based) 복제를 사용할 때는 비 결정적 (nondeterministic) 동작을 복제하기가 어렵습니다 . 이러한 DML (Data Modification Language) 문의 예는 다음과 같습니다 .

- UDF(User Define Fundtion) 또는 Stored Program 에 의해 리턴 된 값 또는 제공된 매개 변수 이외의 요인에 따라 달라지기 때문에 결정적이지 않은 (nondeterministic) UDF 또는 저장된 프로그램에 의존하는 명령문 . ( 그러나 행 기반 복제는 UDF 또는 스토어드 프로그램이 리턴 한 값을 단순히 복제하므로 테이블 행 및 데이터에 미치는 영향은 마스터 및 슬레이브 모두에 ​​ 동일합니다 .)

- ORDER BY 없이 LIMIT 절을 사용하는 DELETE 및 UPDATE 문은 결정적이지 않습니다 (nondeterministic) .

- 결정적( deterministic) UDF 는 슬레이브에 적용되어야합니다 .

- 다음 함수들을 사용하는 명령문은 statement-based 복제를 사용하여 올바르게 복제 할 수 없습니다 .

SYSDATE() (unless both the master and the slave are started with the --sysdate-is-now option)

그러나 NOW() 등을 포함한 명령문 기반 (statement-based) 복제를 사용하여 다른 모든 function 이 올바르게 복제됩니다 .

- 명령문 기반 (statement-based) 복제를 사용하여 올바르게 복제 할 수없는 명령문은 다음과 같은 경고와 함께 기록됩니다 .

[Warning] Statement is not safe to log in statement format.

이 경우에도 비슷한 경고가 클라이언트에게 발행됩니다 . 클라이언트는 SHOW WARNINGS 를 사용하여 이를 표시 할 수 있습니다 .

- INSERT . SELECT 에는 행 기반 복제보다 많은 행 수준 잠금이 필요합니다 .

- WHERE 절에서 인덱스가 사용되지 않으므로 테이블 스캔이 필요한 UPDATE 문은 행 기반 복제보다 많은 수의 행을 잠가야 합니다 .

- InnoDB 의 경우 : AUTO_INCREMENT 를 사용하는 INSERT 문은 충돌하지 않는 다른 INSERT 문을 차단합니다 .

- 복잡한 명령문의 경우 , 행을 업데이트하거나 삽입하기 전에 명령문을 평가하고 슬레이브에서 실행해야합니다 . 행 기반 복제를 사용하면 슬레이브는 영향을 받는 행만 수정하고 전체 문을 실행하지 않아도됩니다 .

- 특히 복잡한 명령문을 실행할 때 슬레이브에 대한 평가 오류가있는 경우 , 명령문 기반 복제는 시간이 지남에 따라 영향을받는 행에서 오류 마진을 천천히 증가시킬 수 있습니다 .

- 저장된 함수는 호출 명령문과 동일한 NOW() 값으로 실행됩니다 . 그러나 이것은 저장 프로 시저에는 해당되지 않습니다 .

- 테이블 정의는 마스터와 슬레이브에서 ( 거의 ) 동일해야합니다 .

▶ Row-Based 복제의 장점과 단점

MySQL 은 Statement-based Logging (SBL), Row-based Logging (RBL) 또는 Mixed-based Logging 을 사용합니다 . 사용되는 바이너리 로그 유형은 로깅의 크기와 효율성에 영향을줍니다 . 따라서 Row-based Replication (RBR) 또는 Statement-based Replication (SBR) 중에서 선택하는 것은 응용 프로그램과 환경에 따라 다릅니다 . 이 섹션에서는 행기반 (Row-based) 형식 로그를 사용할 때 발생하는 알려진 문제와 복제시 이를 사용하는 모범 사례에 대해 알아봅니다 .

+ 임시 테이블은 행 기반 (Row-Based) 형식을 사용할 때 복제되지 않습니다 . 혼합 형식 로깅 (Mixed-based Logging) 을 사용하는 경우 임시 테이블과 관련된 안전한(safe) 문은 statement-based 형식을 사용하여 기록됩니다 .

행기반 (row-based) 형식을 사용할 때는 필요하지 않으므로 임시 테이블은 복제되지 않습니다 . 또한 임시 테이블은이를 생성 한 스레드에서만 읽을 수 있으므로 명령문 기반 형식을 사용하는 경우에도 복제하여 얻을 수있는 이점은 거의 없습니다 .

임시 테이블이 작성된 경우에도 런타임시 명령문기반 (statement-based) 에서 행 기반 (row-based) 바이너리 로깅 형식으로 전환 할 수 있습니다 . MySQL 5.7.25 부터 MySQL 서버는 각 임시 테이블을 만들 때 적용되었던 로깅 모드를 추적합니다 . 클라이언트 세션이 종료되고 , 서버가 여전히 실행중이고 statement-based 바이너리 로깅이 사용 중일 때 작성된 각 임시 테이블에 대해 DROP TEMPORARY TABLE IF EXISTS 문을 로깅합니다 . 테이블 작성시 행 기반 또는 mixed 형식 바이너리 로깅을 사용중인 경우 DROP TEMPORARY TABLE IF EXISTS 문이 기록되지 않습니다 . 이전 릴리스에서는 DROP TEMPORARY TABLE IF EXISTS 문이 유효한 로깅 모드에 관계없이 로깅되었습니다 .

명령문에 의해 영향을받는 비 트랜잭션 테이블이 임시 테이블 일때 한해서 , binlog_format = ROW 를 사용할 때 임시 테이블을 포함하는 비 트랜잭션 DML 명령문이 허용됩니다 .

+ 비 트랜잭션 테이블의 RBL(Row-Based Logging) 및 동기화 .

많은 행이 영향을 받으면 , 일련의 변경 사항이 여러 이벤트로 분할됩니다 . 명령문이 커밋되면 이러한 모든 이벤트가 이진 로그에 기록됩니다 . 슬레이브에서 실행할 때 관련된 모든 테이블에서 테이블 잠금이 수행 된 다음 행이 배치 모드로 적용됩니다 . 슬레이브의 테이블 사본에 사용 된 엔진에 따라 이는 효과적이거나 효과적이지 않을 수 있습니다 .

+ 지연 시간 및 이진 로그 크기

RBL(Row-Based Logging) 은 각 행의 변경 사항을 이진 로그에 기록하므로 크기가 매우 빠르게 증가 할 수 있습니다 . 이로 인해 마스터의 슬레이브와 일치하는 슬레이브를 변경하는 데 필요한 시간이 크게 늘어날 수 있습니다 . 어플리케이션에서 이러한 지연이 발생할 가능성을 알고 있어야합니다 .

mysqlbinlog 는 BINLOG 문을 사용하여 이진 로그에 행 기반 이벤트를 표시합니다 . 이 명령문은 이벤트를 기본 64- 인코딩 문자열로 표시하며 그 의미는 분명하지 않습니다 . --base64-output=DECODE-ROWS 및 --verbose 옵션으로 호출하면 mysqlbinlog 는 이진 로그의 내용을 사람이 읽을 수 있도록 형식화합니다 . 이진 로그 이벤트가 행 기반 형식으로 작성되고 복제 또는 데이터베이스 실패를 읽거나 복구하려는 경우 이 명령을 사용하여 이진 로그의 내용을 읽을 수 있습니다 .

+ 또한 slave_exec_mode 를 STRICT 로 설정하면 충분합니다 . 스토리지 엔진에 대한 기본값입니다 .

+ 서버 ID 를 기반으로 한 필터링은 지원되지 않습니다 . CHANGE MASTER TO 문에 IGNORE_SERVER_IDS 옵션을 사용하여 서버 ID 를 기준으로 필터링 할 수 있습니다 . 이 옵션은 명령문 기반 (statements-based) 및 행 기반 (Row-Based) 로깅 형식과 함께 작동합니다 . 일부 슬레이브에서 변경 사항을 필터링하는 또다른 방법은 @@ server_id <> id_value 절과 UPDATE 및 DELETE 문이 포함 된 WHERE 절을 사용하는 것입니다 . 예를 들어 WHERE @@ server_id <> 1 같은 쿼리는 행 기반 로깅에서 제대로 작동하지 않습니다 . 명령문 필터링에 server_id 시스템 변수를 사용하려면 명령문 기반 로깅을 사용하셔야 합니다 .

+ 데이터베이스 레벨 복제 옵션 .

--replicate-do-db, --replicate-ignore-db 및 --replicate-rewrite-db 옵션의 효과는 행 기반 또는 명령문 기반 로깅의 사용 여부에 따라 상당히 다릅니다 . 따라서 데이터베이스 수준 옵션을 피하고 대신 --replicate-do-table 및 --replicate-ignore-table 과 같은 테이블 수준 옵션을 사용하는 것이 좋습니다 .

+ RBL(Row-Based Logging), 비 트랜잭션 테이블 및 중지 된 슬레이브 행 기반 로깅을 사용할 때 슬레이브 스레드가 비 트랜잭션 테이블을 업데이트하는 동안 슬레이브 서버가 중지되면 슬레이브 데이터베이스가 불일치 상태에 도달 할 수 있습니다 . 이러한 이유로 Row-based 형식을 사용하여 복제 되는 모든 테이블은 InnoDB 와 같은 트랜잭션 스토리지 엔진을 사용하는 것이 좋습니다 . 슬레이브 MySQL 서버를 종료하기 전에 STOP SLAVE 또는 STOP SLAVE SQL_THREAD 를 사용하면 문제가 발생하는 것을 방지 할 수 있으며 사용하는 로깅 형식 또는 스토리지 엔진에 관계없이 항상 권장됩니다 .

■ 바이너리 로깅에서 안전 (safe) 하고 안전하지 (unsafe) 않은 문법의 결정

MySQL Replication 에서 명령문의 " 안전성 " 은 명령문과 그 효과가 명령문 기반 (statement-based) 형식을 사용하여 올바르게 복제 될 수 있는지 여부를 나타냅니다 . 이것이 문법에 해당되는 경우 , 우리는 그 문법을 안전한 것으로 참고합니다 . 그렇지 않으면 안전하지 않은 것으로 참고합니다 .

일반적으로 문법이 결정적 (deterministic) 이면 안전 (safe) 하고 , 그렇지 않으면 안전하지 않습니다 (unsafe) . 그러나 특정 비 결정적 (nondeterministic) 기능 (function) 은 안전하지 않은 것으로 고려되지 않습니다 ( 이 섹션 뒷부분의 안전하지 않은 것으로 간주되는 비 결정적 기능 참조 ). 또한 하드웨어 종속적 인 부동 소수점 수학 함수의 결과를 사용하는 명령문은 항상 안전하지 않은 것으로 간주됩니다 .

▶ 안전(safe)하고 안전하지 않은(unsafe) 명령 ( 문법 ) 처리 .

명령문은 명령문이 안전하다고 간주되는지 여부 및 이진 로깅 형식 ( 즉 , 현재 binlog_format 값 ) 과 관련하여 다르게 처리됩니다 .

+ 행 기반 로깅을 사용하는 경우 안전하고 안전하지 않은 명령문을 처리 할 때 구별되지 않습니다 .

+ 혼합 형식 로깅 (mixed-format logging) 을 사용하는 경우 안전하지 않은 것으로 표시된 명령문은 행 기반 형식을 사용하여 로깅됩니다 . 안전(safe)하다고 간주되는 명령문은 명령문 기반 형식을 사용하여 기록됩니다 .

+ 명령문 기반 로깅 (statement-based logging) 을 사용할 때 안전하지 않은 것으로 표시된 명령문은 이 영향에 대한 경고를 생성합니다 . 안전한 명령문은 정상적으로 기록됩니다 .

▶ 안전하지 않은 (unsafe) 것으로 표시된 각 명령문은 경고를 생성합니다 . 이전에는 마스터에서 많은 수의 명령문이 실행 된 경우 오류 로그 파일이 지나치게 커질 수 있습니다 . 이를 방지하기 위해 MySQL 5.7 은 다음과 같이 작동하는 경고 억제 메커니즘을 제공합니다 . 가장 최근 50 개의 ER_BINLOG_UNSAFE_STATEMENT 경고가 50 초 동안 50 회 이상 생성 될 때마다 경고 억제가 활성화됩니다 . 활성화되면 이러한 경고가 오류 로그에 기록되지 않습니다 . 대신 이 유형의 각 50 개의 경고에 대해 마지막 S 초 동안 마지막 경고가 N 번 반복되는것은 오류 로그에 기록됩니다 . 가장 최근에 발생한 경고 50 개가 50 초 이내에 발생하는 한 계속됩니다 . 한번 이 비율이 임계 값 아래로 떨어지면 경고가 다시 한 번 정상적으로 기록됩니다 . 경고 억제는 명령문 기반 로깅에 대한 명령문의 안전성이 결정되는 방법이지만 , 경고가 클라이언트에 전송되는 방법에는 영향을 미치지 않습니다 . MySQL 클라이언트는 여전히 각 해당 명령문에 대해 하나의 경고를 받습니다 .

▶ 안전하지 않은(unsafe) 것으로 간주되는 명령문들 .

다음과 같은 특성을 가진 진술은 안전하지 않은 것으로 간주됩니다 .

+ 슬레이브에서 다른 값을 반환 할 수 있는 시스템 기능이 포함 된 명령문 . 이러한 함수에는 다음 함수들이 포함됩니다 .

FOUND_ROWS(), GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK(), LOAD_FILE(), MASTER_POS_WAIT(), PASSWORD(), RAND(), RELEASE_LOCK(), ROW_COUNT(), SESSION_USER(), SLEEP(), SYSDATE(), SYSTEM_USER(), USER(), UUID(), UUID_SHORT()

+ 비 결정적 (Nondeterministic) 기능은 안전하지 (unsafe) 않은 것으로 간주됩니다 . 이러한 함수는 결정적 (deterministic) 이지 않지만 이들은 로깅 및 복제를 위한 목적으로써 안전한것으로 다루어집니다 .

CONNECTION_ID(), CURDATE(), CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP(), CURTIME(),, LAST_INSERT_ID(), LOCALTIME(), LOCALTIMESTAMP(), NOW(), UNIX_TIMESTAMP(), UTC_DATE(), UTC_TIME(), UTC_TIMESTAMP().

+ 시스템 변수에 대한 참조 대부분의 시스템 변수는 명령문 기반 형식을 사용하여 올바르게 복제되지 않습니다 .

+ UDF 들 . UDF 의 기능을 제어 할 수 없으므로 안전하지 않은 (unsafe) 명령문을 실행한다고 가정해야합니다 .

+ Fulltext 플러그인 . 이 플러그인은 다른 MySQL 서버에서 다르게 작동 할 수 있습니다 . 따라서 이에 따라 계산 된 결과가 다를 수 있습니다 . 이러한 이유로 전체 텍스트 플러그인에 의존하는 모든 명령문은 안전하지 않은 것으로 취급됩니다 .

+ 트리거 또는 저장된 프로그램은 AUTO_INCREMENT 열이있는 테이블을 업데이트합니다 . 행이 업데이트되는 순서가 마스터와 슬레이브에서 다를 수 있기 때문에 안전하지 않습니다 (unsafe) .

또한 , 이 복합 키의 첫 번째 열이 아닌 AUTO_INCREMENT 열을 포함하는 복합 기본키가 있는 테이블에 대한 INSERT 는 안전하지 않습니다 .

+ INSERT . ON DUPLICATE KEY UPDATE 문은 여러 개의 Primary 또는 Unique 키가 있는 테이블에 있습니다 . 둘 이상의 Primary 또는 Unique 키가 포함 된 테이블에 대해 실행될 때 이 명령문은 안전하지 않은 것으로 간주되며 , 스토리지 엔진이 키를 확인하는 순서에 영향을 미치며 , 결정적이지 않으며 , MySQL 서버 의존성에 의해 선택된 행들이 업데이트됩니다 .

하나 이상의 고유 또는 기본 키가있는 테이블에 대한 INSERT . ON DUPLICATE KEY UPDATE 문은 명령문 기반 복제에 안전하지 않은 것으로 표시됩니다 .

+ LIMIT 를 사용하여 업데이트합니다 . 행이 검색되는 순서는 지정되지 않았으므로 안전하지 않은 (unsafe) 것으로 간주됩니다 .

+ 로그 테이블에 액세스하거나 참조합니다 . 시스템 로그 테이블의 내용은 마스터와 슬레이브간에 다를 수 있습니다 .

+ 트랜잭션 작업 후 비 트랜잭션 작업 트랜잭션 내에서 트랜잭션 읽기 또는 쓰기가 수행 된 후 비 트랜잭션 읽기 또는 쓰기가 실행되도록 허용하는 것은 안전하지 않은 (unsafe) 것으로 간주됩니다 .

+ 자체 로깅 테이블에 액세스하거나 참조합니다 . 자체 로깅 테이블에 대한 모든 읽기 및 쓰기는 안전하지 않은 (unsafe) 것으로 간주됩니다 . 트랜잭션 내에서 자체 로깅 테이블에 대한 읽기 또는 쓰기 뒤에 오는 명령문도 안전하지 않은 것으로 간주됩니다 .

+ LOAD DATA 문 . LOAD DATA 는 안전하지 않은 (unsafe) 것으로 취급되며 binlog_format = mixed 일 때 명령문은 행 기반 형식으로 로그됩니다 . binlog_format = statement LOAD DATA 는 다른 안전하지 않은 명령문과 달리 경고를 생성하지 않습니다 .

+ XA 트랜잭션 . 마스터에서 병렬로 커밋 된 두 개의 XA 트랜잭션이 역순으로 슬레이브에서 준비되는 경우 , 안전하게 해결할 수 없는 명령문 기반 복제로 잠금 종속성이 발생할 수 있으며 슬레이브에서 교착 상태로 인해 복제가 실패 할 수 있습니다 . binlog_format = STATEMENT 가 설정되면 XA 트랜잭션 내부의 DML 문이 안전하지 않은 것으로 플래그가 지정되고 경고가 생성됩니다 . binlog_format = MIXED 또는 binlog_format = ROW 가 설정되면 XA 트랜잭션 내부의 DML 문은 행 기반 복제를 사용하여 기록되며 잠재적인 문제는 없습니다 .

■ Master-Slave 복제 환경 관련 참고글

[Master-Slave] 복제소개 및 사용방법

[MySQL][Master-Slave] 복제소개 및 사용방법

MySQL은 여러형태의 복제 솔루션과 HA, 분산기능, 그리고 클러스터링을 지원합니다. Master-Slave구조 + MHA, Multi Master for MySQL, Galera Cluster, MaxScale(MariaDB), Sharding등 참 많은 기능들을 제공한다..

[Master-Slave] 복제환경 모니터링

[MySQL][Master-Slave] 복제 환경 모니터링

Replication 상태에서 모니터링을 하는 방법에 대해 알아봅니다. 모니터링에서 표시해주는 상태에 따라 그에 맞는 대처를 해서 복제가 지속적으로 이루어 지도록 합니다. ■ Slave 상태 확인 mysql 클라이언트에서..

[Master-Slave] 복제 필터링 - 복제평가방법

[MySQL][Master-Slave] 복제 필터링 - 복제평가방법

■ 서버가 복제 필터링 규칙을 평가하는 방법 복제를 구성할때 전체 데이터베이스를 대상으로 하는 방법도 있지만 원하는 데이터베이스만을 선택해서 복제할 수도 있습니다. 반대로 원하는 데이터베이스만을 복제..

[Master-Slave] 복제 필터링 - 명령문 및 적용방법

[MySQL][Master-Slave] 복제 필터링 - 명령문 및 적용방법

■ Replication Filtering Rule 사용 및 적용방법 이전 챕터에서 복제 룰에 대해서 평가하는 방법을 배웠습니다. 이번엔 실제 복제필터링을 적용하는 명령과 환경설정 옵션에서 어떻게 적용하는지에 대해 알아봅니..

[Master-Slave] GTID를 이용한 복제 - 이론

[MySQL][Master-Slave] GTID를 이용한 복제 - 이론

이 섹션에서는 GTID (Global Transaction Identifier)를 사용한 트랜잭션 기반 복제에 대해 설명합니다. GTID를 사용할 때 각 트랜잭션은 원래 서버에서 커밋되고 슬레이브에 의해 적용될 때 식별되고 추적 될 수..

[Master-Slave] GTID를 이용한 복제 - 구성방법

[MySQL][Master-Slave] GTID를 이용한 복제 - 구성방법

■ GTID를 이용한 복제 설정. 이 섹션에서는 MySQL 5.7에서 GTID 기반 복제를 구성하고 시작하는 프로세스에 대해 설명합니다. 이는 처음으로 복제 마스터를 시작하거나 중지 할 수 있다고 가정하는 "콜드 스타트"..

도움이 되셨다면 광고클릭 한번 부탁드립니다 .※

바이너리의 단점

마임(MIME) 타입을 이해하기 위해서는 아스키와 바이너리에 대해 알고 있어야 하므로 먼저 간단하게 설명합니다. 컴퓨터는 0 과 1로 이뤄진 이진수만 이해할 수 있습니다. 바이너리(binary)라는 단어가 "이진의", "이진수의"라는 의미입니다.

컴퓨터에서 'ㄱ,ㄴ,ㄷ' 이나 'a, b, Z, T. ' 등의 문자를 표시하려면 각각의 문자를 숫자로 지정해줄 필요가 있습니다. 즉 'a는 십진수로 97이다', 'z는 122다' . 이런 식으로 규정을 해야 했습니다. 이렇게 규정을 하면 그 값을 이진수로 변환해서 컴퓨터가 각 문자를 식별할 수 있기 때문입니다.

컴퓨터 등장 초기에는 오늘날의 PC처럼 공통된 표준이 정립되어 있지 않았습니다. 각자 자기 식으로 하드웨어를 제작했고 거기에 맞게 소프트웨어를 만들었습니다. 각 문자에 해당하는 값 역시 컴퓨터마다 달랐습니다. 이렇다 보니 서로 다른 메이커에서 만든 컴퓨터 간에 데이타를 교환해야 할 필요가 생긴 경우 문제가 많았습니다. A 컴퓨터에서는 'abc'라고 저장한 것인데 B 컴퓨터에서 열어보면 '!#F'라고 열린다든지 하는 일이 생긴 것이지요.

이에 "ANSI"라는 표준을 정하는 곳에서 각 문자에 해당하는 숫자 값을 하나로 통일하자는 목적 아래 ASCII라는 표준을 만듭니다. "ASCII"는 "American Standard Code for Information Interchange"의 약자입니다. 뜻 그대로 정보 교환을 위한 미국 표준 코드입니다.

ASCII art

컴퓨터가 정보 처리를 할 때 사용하는 기본 단위는 바이트(byte)입니다. 바이트는 8비트를 줄인 말입니다. 이런 것이 1바이트입니다.

8자리의 이진수를 1바이트라고 하는 것입니다. 1바이트는 십진수로 고치면 최소 0( 00000000 )부터 최대 255( 11111111 ) 사이의 값이 됩니다. ANSI는 0부터 255까지의 숫자를 알파벳과 특수문자에 하나하나 대응시켰습니다. a는 97, W는 87 . 이런 식으로 문자마다 값을 지정을 했습니다. 그런데 왜 'A'를 1이나 2처럼 앞의 숫자로 할당하지 훨씬 큰 숫자로 지정했을까요? 그것은 제어 문자(control character)라는 것이 필요했기 때문입니다. 당시 컴퓨터 단말기의 표준격인 TTY에 쓰이던 제어 문자를 위해 앞의 0-32를 남겨둬야 했습니다. 제어 문자는 폰트가 바뀐다든지, 전송의 끝을 알리는 문자처럼 특수한 작업과 기능, 이벤트를 알려주는 특수 문자입니다.

제어 문자에 할당한 0-32 다음 값인 33부터 화면상에 보여지는 보통의 문자를 짝지운 것입니다. 아스키 33은 !이고, 34는 ", 35는 #, . 이렇게 MySQL Master-Slave 복제 환경에서 Binary Log 특징 하면 0부터 127까지 사용해서 대부분의 문자를 다 표시할 수 있습니다. [1] 따라서 8비트 중 128 부터 255까지는 사용할 필요가 없었습니다. 이것을 이진수로 바꿔보면 1 바이트 이진수의 맨 첫 번째 자리는 사용할 필요가 없다는 것이 됩니다. 1111111 이 127이니까요. 그래서 아스키 문자의 이진수 값은 첫 숫자가 0 입니다. 이것을 잘 기억해 두세요."7 비트 아스키 문자"라는 용어는 그런 원리로 등장한 것입니다.

이제 아스키가 뭔지, 왜 아스키 문자는 7비트인지, 그리고 첫 문자 값을 33으로 설정했는지 등을 이해할 수 있을 것입니다. 그렇다면 이것이 도대체 마임과 무슨 상관이 있는가?

문제는 컴퓨터 사이에서 이동되는 파일이 모두 다 아스키 문자로 이뤄진 텍스트 파일은 아니였다는 데서 출발합니다.

바이너리(binary), 인코딩과 디코딩

보통의 텍스트 파일을 컴퓨터 간에 주고 받는 데는 ASCII라는 공통 표준에 따르기만 하면 아무 문제가 없었습니다. 그런데 네트웍을 통해 아스키 파일이 아닌, 즉 '바이너리(binary)' 파일을 보낼 필요가 생깁니다. 바이너리 파일은 음악 파일이나 그래픽 파일, 무비 파일, 또는 포매팅 정보가 담긴 워드 프로세서로 만든 문서 파일 등입니다. 이들은 모두 8 자리 이진수의 첫 번째 자리가 0 으로 한정된 것이 아닌, 8비트 모두를 사용한다는 특징을 갖습니다. "8비트 데이타"입니다.

이메일이나 기타 네트웍 상에서 데이타를 교환하는 시스템은 최초 아스키 문자로 이뤄진 파일만을 전송하는 것을 전제로 제작되었기 때문에 첫 번째 숫자가 1 인 데이타가 섞여 있는 이들 8비트 바이너리 데이타를 제대로 전달할 수가 없었습니다. 바이너리 파일을 기존의 시스템 상에서 문제 없이 전달하기 위해서는 이들을 다시 7 비트의 아스키 문자 파일로 바꾸어서 전달할 필요가 있었습니다. 즉, 바이너리텍스트로 변환해야만 했습니다.

그것을 인코딩(encoding)이라 합니다. 바이너리 파일을 텍스트 파일로 바꾸는 것입니다. 디코딩(decoding)은 인코딩 된 텍스트 파일을 다시 바이너리 파일로 변환하는 해독 과정을 의미합니다.

그러면 초기 인코딩 방식의 대표적 표준인 "UUEncode(Unix-to-Unix Encode)" 방식의 원리를 통해 인코딩의 원리를 간단하게 살펴 봅시다. 어떤 바이너리 파일 데이타 중 3개의 바이트를 가져 왔을 때 다음과 같았다면,

10011100 00110011 11110000

8자리씩 총 24개의 비트입니다. 24개이므로 이것을 다시 6개짜리 4개로 바꿀 수 있습니다.

100111 000011 001111 110000

그 다음, 첫 두 자리에 0 을 붙입니다.

00100111 00000011 00001111 00110000

이제 전부 첫 번째 숫자가 0 이 되어서 조금 더 아스키 코드에 가까와졌습니다.

그 다음, 각각에 십진수 32를 (이진수 100000 ) 더합니다.

조절 문자가 아닌, 화면에 보이는 보통의 문자 값으로 바꾸기 위해서입니다.

01100111 01000011 01001111 01110000

이 됩니다. 이제 이들은 모두 알파벳이나 기타 기호 등의 보통의 아스키 문자로 바꿀 수가 있게 됩니다.

이 과정을 거친 바이너리 파일은 아스키문자 파일이 되어서 종래의 이메일 시스템 등을 타고 아무 문제 없이 전달될 수가 있습니다. 인코딩 된 바이너리 파일을 텍스트에디터로 열어보면 이상한 문자가 가득 뜨는데 그런 이유입니다.

그러면 마임(MIME)이란?

MIME은 Multipurpose Internet Mail Extensions의 약자로 일종의 인코딩 방식입니다. MIME은 이메일과 함께 동봉할 첨부 파일(attachment file)을 텍스트 문자로 전환해서 이메일 시스템을 통해 전달 하기 위해 개발되었기 때문에 이름이 "Internet Mail Extension"입니다만 현재는 웹을 통해서 여러 형태의 파일을 전달하는 데 두루 쓰이고 있습니다.

왜 UUEncode 방식이 있는데 MIME이란 인코딩이 또 나타나게 되었을까요? UUEncode 방식에는 단점이 있었습니다. 문서 끝 부분의 공백이 사실은 공백이 아니라 변환되어야 할 값인데 공백을 무시하는 시스템의 경우엔 UUEncode 파일을 원형 그대로 전달 받을 수 없었다는 것 등의 단점이 있었습니다. 그래서 UUEncode 방식을 대폭 보강한 새로운 인코딩 방식이 등장하게 되었고 그것이 MIME입니다. MIME은 특히 기존의 UUEncode 방식에서는 없었던 파일 포맷 (또는 Content-type) 정보도 함께 담을 수 있습니다. '지금 전달하는 이 파일은 GIF 파일이다', 'MOV 파일이다'처럼 그 파일의 종류를 나타내는 딱지를 붙일 수 있었습니다. 이렇게 MIME 에서 사용하는 인코딩 방식을 "base64"라고 합니다. 방식은 위에서 본 것과 유사합니다. 8비트 3개를 6비트 4개로 바꿔서 적절한 변형을 합니다.

이렇게 해서 텍스트만 전달될 수 있는 기존의 이메일 시스템에서도 바이너리 파일들을 자유롭게 주고 받을 수 있게 되었습니다. 8비트 바이너리 파일을 7비트의 아스키문자 파일로 바꿔주는 것입니다.

마임 타입 (MIME Type), 미디어 타입 (Media Type)

마임으로 인코딩 한 파일은 "Content-type" 정보를 파일의 앞 부분에 담고 있습니다. 컨텐트 타입에는 여러 가지가 있습니다. 이런 얘기를 들어 본 적이 있을 것입니다. '어떤 마임 타입 (MIME type)이 웹브라우져에서 지원된다, 안된다.' 그것은 '특정 컨텐트 타입의 파일을 웹 서버로부터 전달받아서 웹브라우져가 열 수 있다, 아니다'라는 의미입니다. 웹 브라우져가 웹 서버에 접속해서 html 문서를 요청하면서 html 문서 내에 담긴 이미지 태그내에 지정된 패쓰로부터 이미지 파일도 가져 옵니다. 이 때 그 패쓰에 있는 파일이 웹 브라우져에서 지원되는 마임 타입이라면 웹 브라우져 내에서 열 수 있습니다. .jpg, .gif 파일 등은 브라우져 내에서 바로 뜨는 것입니다. (초기 웹브라우져인 모자익(Mosaic) 웹브라우져때만 해도 이것은 획기적인 기능이었습니다. 모자익 이전의 웹브라우져는 .jpg, .gif 마임 타입을 직접 지원하지 않았기 때문에 외부 그래픽 프로그램이 구동되면서 이미지를 보여 줬습니다)

초기 웹 브라우져는 표준적인 마임 타입들(.gif, .jpg, .mov. )은 무리 없이 열렸지만 그렇지 않은 유형은 그 파일을 열어줄 프로그램을 손수 지정해야 했습니다. 그래서 웹 브라우져 설정에 들어가면 파일 포맷별로 외부 프로그램을 연결하는 부분이 있었습니다. 그런데 마이크로소프트가 웹 브라우져를 불공정하게 운영체계에 통합하면서 마임 타입 지정이 OS 차원으로 넘어 갑니다. 윈도우즈 탐색기를 열어서 [보기 > 폴더옵션] 메뉴에 보면 아래 그림같이 "파일 형식"이라는 탭이 있습니다. 여기에서 파일 확장자나 마임 타입 별로 구동될 프로그램을 설정하게 되어 있습니다. gif 파일의 경우를 한 번 볼까요?

"내용 형식"(="Content-type")이라는 단어 옆에 "MIME"이라고 되어 있죠? MIME 타잎이 어떻게 설정되어 있는지를 자세히 봅시다. 가운데에 슬래쉬가 / 있고 슬래쉬 앞 부분에는 파일의 종류("image") / 뒷 부분은 파일의 포맷을("gif") 나타내고 있습니다. 이렇게 마임 타입은 "파일종류/파일포맷" 형태로 정의합니다. 몇 가지 예를 들어 봅시다.

application/msword
text/html
application/pdf
audio/mpeg

위의 대화상자를 보면, 마임 타입 밑에 연결 프로그램으로 인터넷 익스플로러가 설정되어 있습니다. 따라서 gif 파일을 데스크탑 상에서 더블 클릭할 때도 익스플로러를 통해 열립니다. 또는 웹 문서에 포함된 gif 파일은 바로 웹 브라우져내에서 열립니다. image/gif 마임 타입을 다른 그래픽 프로그램과 연결하면, gif 파일이 포함된 웹 문서가 열릴 때마다 외부 프로그램이 뜹니다.

이러한 마임타입은 www이 보편화되면서 "Media Type"이라는 이름으로 확장됩니다. 그리고 현재는 대부분의 파일 타입이 웹브라우져내에서 문제 없이 보여지고 구동하고 있습니다.

우리가 Base64를 사용하는 이유

Base64를 사용하는 가장 큰 이유는 Binary 데이터를 텍스트 기반 규격으로 다룰 수 있기 때문이다. JSON과 같은 문자열 기반 데이터 안에 이미지 파일등을 Web에서 필요로 할때 Base64로 인코딩하면 UTF-8과 호환 가능한 문자열을 얻을 수 있다. 끝에 '='과 같은 패딩 기호가 있다면 이는 구분자로써 사용되므로 대부분 Base64로 생각할 수 있다.

기존 ASCII 코드는 시스템간 데이터를 전달하기에 안전하지 않다. 모든 Binary 데이터가 ASCII 코드에 포함되지 않으므로 제대로 읽지 못한다. 반면 Base64는 ASCII 중 제어문자와 일부 특수문자를 제외한 53개의 안전한 출력 문자만 이용하므로 데이터 전달에 더 적합하다.

📮Base 64 인코딩

Base64는 Binary 데이터를 문자로 변환하는데 영향을 받지 않는 공통 ASCII 코드 영역의 문자로만 이루어진 문자열로 바꾸는 Encoding이다. 문자 그대로 64진법(2^6)을 사용하며 Binary 데이터를 6bit 씩 나누고 해당하는 문자를 위의 색인표에서 맞게 치환하는 과정을 거친다. 6bit cut을 진행함에 있어서 모든 문자열이 3개씩 이쁘게 떨어지면 좋겠지만, 아닌 경우도 왕왕 존재하기 마련이다. 그런 경우를 대비해 padding을 하는데 남는자리에 = 기호를 통해서 채워주는 개념이다.

예를들어 '코딩배우는 학생'을 Base64로 인코딩 하면 '7L2U65Sp67Cw7Jqw64qUIO2VmeyDnQ==' 로 2자리의 빈공간을 알려주게 된다.

padding 문자가 반드시 필요한 것은 아닙니다. JSON이나 HTTP 메세지를 통해 데이터 길이를 명시적으로 구분할 수 있다면 더욱 그렇습니다. 하지만 TCP처럼 Stream형태로 데이터를 주고받는 형태에서는 padding이 유용합니다.

📮Base 64 디코딩

복원한 데이터를 다룰 때 주의할 점은 복원한 데이터만 보면 타입을 특정지을 수 없다는 점입니다. 따라서 데이터 형태와 함께 명시하는 경우가 많습니다.


0 개 댓글

답장을 남겨주세요