Facebook Online Schema Change for MySQL And Alter table Speed

NoSQL을 선택하는 비중이 큰 이유중에 하나는 Schema Free 라는 겁니다. 그리고 이에 비교하는 것으로 나오는 것이 RDBMS 에서 alter table 의 문제입니다. alter table 하는 동안에 데이터를 변경하지 못하는 것은 아니지만, 어떤 문제가 생길지도 모르고, 또한 이로 인해 서비스 속도가 줄어드는 이슈가 발생합니다.

이로 인해 첫번째 해결 책은 바로 “점검 시간” 입니다. 포털쪽보다, 게임쪽에서 더 자주 사용하는 신공으로 아예 해당 서비스를 그 시간동안 접습니다. 서버도 리부팅 해주고, DB도 옵티마이징 해주고, 보통은 예상시간 보다 더 걸리게 되는 천하제일신공이지요.

그런데, Facebook 이나 와우의 블리자드 같은 경우는 이런 문제를 다른 방법으로 해결합니다. 바로, 실시간 체인지입니다. 즉, 새로운 업그레이드 버전으로 서버를 구성해두고, 특정시간 부터는 바로 여기로 보내버립니다. 간단하게 생각할 때, 하드웨어가 2배로 들어갑니다. 그렇습니다. 돈 없는 회사는 쓰기 힘듭니다. 서비스 점검 시간보다 하드웨어 비용이 쌀 때나 시도해 볼 수 있는 신공이지만, 그러나, 서비스 유지가 정말 중요할 때는 훨씬 유용할 듯 합니다.

다음 사이트에 facebook에서 사용하는 방법이 나와있습니다.
http://www.facebook.com/notes/mysql-at-facebook/online-schema-change-for-mysql/430801045932

간단하게 요약하면
1. Data Dump
2. Change Schema
3. Sync Data
4. Replace

입니다.

그런데 이 걸 보다 보니, 데이터 alter table 을 할 때( 정확하게 말하자면 보통 요구사항의 증가로 인한 alter table add column 입니다. ) 시간이 얼마나 걸릴 것인지 궁금해 졌습니다.

그래서 약 2500만건 정도의 Dummy 데이터를 생성한 다음 alter table을 적용했습니다.

테스트 머신
CPU: Quard Xeon 3.6GH
MEM: 4G

alter table dummy add column test_dummy varchar(255) , add index(test_dummy) 했을 때 innodb 에서 대략 23분 정도 걸렸습니다.

제 예상은 굉장히 오래 걸릴꺼라고 생각했는데, 생각보다 빠른 시간에 굉장히 놀라웠습니다.( 그럼 페이스북 이런데서는 과연 몇시간씩 걸릴려면 몇억, 몇십억 몇조 까지도 가지 않을까 하는 생각이 듭니다.)

하지만, 이렇게 미리 준비하는 것의 이점은, 서버 점검 시간이 길어지는 걸 방지해준다라는 장점이 하나 더 있습니다. alter table 중에 뭔가 장애가 발생하더라도 서비스가 멈춰있지 않기 때문에, 재시도 할 수 있는 시간이 충분히 생깁니다.

뭐, 이런 저런 생각을 하더라도, 돈만 있으면 서버 2배로 늘리고 하는 것도 재미있을듯 합니다.

mysql simple example

간단한 mysql 관련 샘플


#include    <stdio.h>

#include    <mysql.h>

#include    <errno.h>

#include    <string.h>

int main( int argc, char *argv[] ){

MYSQL mysql;

mysql_init(&mysql);

if( !mysql_real_connect( &mysql, "localhost", id, pass, dbname, 3306, NULL, 0 )){

printf("%sn", mysql_error(&mysql));

return 1;

}


printf("Mysql Connectedn");

MYSQL_RES *result;

MYSQL_ROW row;

char sql[256];

strcpy( sql, "select * from tbl_user_info" );

if( mysql_query( &mysql, sql ) != 0 ){

printf("query fail: %sn", mysql_error(&mysql));

mysql_close(&mysql);

return 1;

}

result = mysql_store_result( &mysql );

int nCount = mysql_num_rows( result );

while( (row = mysql_fetch_row( result ) ) != NULL ){

printf("%s %s %sn", row[0], row[1], row[2] );

}

mysql_free_result( result );

mysql_close(&mysql);

return 0;

}

mysql 기본 셋팅

db 생성

mysqladmin create db_name

 

user 생성, 권한 부여

grant all privileges on db_name.* to id@localhost identified by ‘password’ with grant option;

( 예전에는 insert into 로 db, user 를 추가해줘야 했는데, 그럴 필요가 없다.)

 

flush privileges;