Spider On MariaDB 설치해 샤딩 해보기

Spider

Mysql의 스토리지 엔진 중 하나 이며, 기존 테이블 파티션 기능을 확장하여 원격으로 저장하고 읽을 수 있다.

가장 큰 장점은 기존 사용하던 SQL문과 디비 서버의 환경 또는 구조를 변경 하지 않고도, 샤딩이 가능하다는 점이다.

또한, 트랜 잭션과 조인 등도 사용이 가능하다.


적용 결과

마스터 디비 * 1 + 슬레이브 디비 * 1를 구성해, ad-hoc 쿼리가 아닌 저장 프로시저를 사용했을 때에는,

대략 1만 ~ 2만 개의 QPS가 나왔었지만,

SPIDER ON Maria * 2 + 마스터 디비 * 1 + 슬레이브 디비 * 1를 구성했더니

대략 4만 QPS가 나오게 되었고, 전체 성능은 40~50% 가량 향상되는 것을 확인했다.


참고 사이트

http://memocra.blogspot.kr/2011/08/ec2mysqlspider1-spider.html


설치

스파이더 다운로드 페이지에서 원하는 버전을 다운로드 받을 수 있도록 주소를 알아둔다.

여기서는 spider 3.2에 mysql 5.5.34를 선택해서 테스트 해보았다.

하지만, 세션 하나에서 insert 테스트를 했을 때에는 문제가 없었지만,

다중 세션에서 부하 테스트를 하니까 DEADLOCK이 발생하였다.

혹시나 해서 maria db를 설치하여 테스트 하였더니 발생하지 않았다.

mariadb 설치 방법을 추가해 두었다.

# spider가 설치된 mysql 설치하기 $ cd /usr/local $ wget http://spiderformysql.com/downloads/spider-3.2/mysql-5.5.34-spider-3.2-vp-1.1-hs-1.2-q4m-0.95-linux-x86_64-glibc25.tgz $ tar xzvf mysql-5.5.34-spider-3.2-vp-1.1-hs-1.2-q4m-0.95-linux-x86_64-glibc25.tgz $ cd mysql-5.5.34-spider-3.2-vp-1.1-hs-1.2-q4m-0.95-linux-x86_64-glibc25 # mysql 유저 등록하기 $ groupadd mysql $ useradd -r -g mysql mysql $ ./scripts/mysql_install_db --user=mysql $ cp support-files/my-medium.cnf /etc/my.cnf $ cp support-files/mysql.server /etc/init.d/mysqld $ ln -s /usr/local/mysql-5.5.34-spider-3.2-vp-1.1-hs-1.2-q4m-0.95-linux-x86_64-glibc25 /usr/local/mysql $ cd /usr/local/mysql $ chown -R mysql:mysql . $ /etc/init.d/mysqld start Starting MySQL.. SUCCESS! $ chkconfig mysqld on # spider 플러그인 설치 $ ./bin/mysql -u root < ./share/install_spider.sql $ ./bin/mysql -u root mysql> use mysql; mysql> create user 'spider'@'%' identified by '12121212'; mysql> grant all on *.* to 'spider'@'%' with grant option; mysql> flush privileges;

마리아 디비로 설치

$ cd /usr/local $ wget https://downloads.mariadb.org/interstitial/mariadb-10.0.14/bintar-linux-x86_64/mariadb-10.0.14-linux-x86_64.tar.gz/from/http%3A//ftp.kaist.ac.kr/mariadb $ tar xzvf mariadb-10.0.14-linux-x86_64.tar.gz $ cd mariadb-10.0.14-linux-x86_64 #이후 부터는 동일


테스트

최소한의 테스트를 위해서 3 대의 머신이 필요하다.

spider db, shard db1, shard db2


spider db에서 샤딩할 서버 연결 정보 추가하기

CREATE SERVER shard_db1 FOREIGN DATA WRAPPER mysql OPTIONS( HOST '10.10.3.114', DATABASE 'test', USER 'spider', PASSWORD '12121212', PORT 3306 ); CREATE SERVER shard_db2 FOREIGN DATA WRAPPER mysql OPTIONS( HOST '10.10.3.115', DATABASE 'test', USER 'spider', PASSWORD '12121212', PORT 3306 ); # 확인 SELECT * FROM mysql.servers; # Server_name, Host, Db, Username, Password, Port, Socket, Wrapper, Owner 'shard_db1', '10.10.3.114', 'test', 'spider', '12121212', '3306', '', 'mysql', '' 'shard_db2', '10.10.3.115', 'test', 'spider', '12121212', '3306', '', 'mysql', ''

spider db에서 샤딩할 테이블 생성하기

CREATE TABLE test.shardTest ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name char(120) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=spider COMMENT='wrapper "mysql", table "shardTest"' PARTITION BY KEY (id) ( PARTITION shard1 COMMENT = 'srv "shard_db1"', PARTITION shard2 COMMENT = 'srv "shard_db2"' ) ;

각 각의 shard db에도 테이블 생성하기

CREATE TABLE test.shardTest ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name char(120) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=innodb;

spider db에서 샤딩이 잘 되는지 insert 해보기

#10회 정도 해본다. insert into shardTest(name) values('aa'); #잘 들어갔는지 확인해보자. # spider db에서 # 키 순서대로 나오지 않았지만, 10개의 데이터 모두 정상이다. select * from shardTest; # id, name '1', 'aa' '3', 'aa' '5', 'aa' '7', 'aa' '9', 'aa' '2', 'aa' '4', 'aa' '6', 'aa' '8', 'aa' '10', 'aa' # 분산 되어 있는 것을 확인할 수 있다. # shard db1에서 select * from shardTest; # id, name '1', 'aa' '3', 'aa' '5', 'aa' '7', 'aa' '9', 'aa' # shard db2에서 select * from shardTest; # id, name '2', 'aa' '4', 'aa' '6', 'aa' '8', 'aa' '10', 'aa'

shard2 서버가 죽었을 때

# 전체 가져오기는 실패 select * from shardTest; Error Code: 1429. Unable to connect to foreign data source: shard_db2 # 살아있는 shard1의 데이터는 가져올 수 있다. select * from shardTest where id in (1, 3, 5, 7); # id, name '1', 'aa' '3', 'aa' '5', 'aa' '7', 'aa' # 삽입시, shard가 살아 있는 쪽으로 들어가게 되면 성공이지만, 죽어 있는 쪽으로 들어가게 되면 실패 insert into shardTest(name) values('shard2 shutdown'); 1 row(s) affected insert into shardTest(name) values('shard2 shutdown'); Error Code: 1429. Unable to connect to foreign data source: shard_db2

spider db에서 샤딩 중인 디비 수를 줄이기

# 분산 되었던 데이터를 shard db1에 병합하기 # shard db2에서 데이터만 덤프 시킨다. $ mysqldump -uspider -p --no-create-info test > testBackup.sql # shard db1에서 db2의 백업 데이터를 복구 시킨다. $ mysql -uspider -p test < testBackup.sql # spider 테이블을 지우고 파티션을 줄여 다시 생성 시킨다. # spider에서의 drop table은 shard db의 테이블에는 영향을 주지 않는다. # 다만, truncate table은 shard db까지 영향을 준다. drop table if exists test.shardTest; CREATE TABLE test.shardTest ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name char(120) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=spider COMMENT='wrapper "mysql", table "shardTest"' PARTITION BY KEY (id) ( PARTITION shard1 COMMENT = 'srv "shard_db1"' ) ;

spider db에서 샤딩 할 디비 수를 늘이기

# 뭉쳐 있던 데이터를 각 shard db에 분산 시키기 # master db1에 데이터를 덤프 $ mysqldump -uspider -p --no-create-info test > testBackup.sql # 줄이기와 마찬가지로 테이블을 다시 생성하여 파티션을 늘린다. drop table if exists test.shardTest; CREATE TABLE test.shardTest ( id int(10) unsigned NOT NULL AUTO_INCREMENT, name char(120) NOT NULL DEFAULT '', PRIMARY KEY (id) ) ENGINE=spider COMMENT='wrapper "mysql", table "shardTest"' PARTITION BY KEY (id) ( PARTITION shard1 COMMENT = 'srv "shard_db1"', PARTITION shard2 COMMENT = 'srv "shard_db2"' ) ; # spider db1에서 덤프 시킨 데이터를 다시 삽입할 것이니, spider db1에서 해당 테이블을 trucate 시키고, # my.cnf에서 auto increment을 1씩 증가하고, 1부터 시작하라고 잠시 변경해 두자. [mysqld] auto_increment_increment = 2 <-- spider 수 auto_increment_offset = 1 <-- 시작 값 $ /etc/init.d/mariadb restart truncate table test.shardTest; # 덤프한 파일을 spider db1에 복사하고, 복원시킨다. $ /usr/local/mariadb/bin/mysql -uroot test < testBackup.sql # 오류가 없었다면, 분산 되어 저장되어 있을 것이다. # my.cnf에서 auto increment 값을 기존 상태로 복원해 둔다.

테이블 스키마

해당 테이블을 사용하는 쿼리가 동작하는데 지장이 없다면,

spider의 테이블 스키마와 shard db의 테이블 스키마가 동일하지 않아도 된다.


파티션 키는 기존 파티션 키 생성 룰과 동일

자주 발생하는 오류는 A PRIMARY KEY must include all columns in the table's partitioning function 이었는데

파티션에 사용할 컬럼을 primay key와 unique key모두에 포함시키면 해결되지만,

그래도 상관없는지 고려는 해야 한다.


저장프로시저를 사용한다면, spider db에만 있어도 무방하다. shard db에는 sql문만 전달된다.

multiple spider 구성하기

# spider를 여러 개 실행할 때에는 auto increment의 초기값과 증감값을 조정해야 중복 오류를 피할 수 있다. spider 2 대를 구성 한다면, my.cnf 설정은 다음과 같이 해줘야 한다. my.cnf of spider1 [mysqld] auto_increment_increment = 2 <-- spider 수 auto_increment_offset = 1 <-- 시작 값 my.cnf of spider2 [mysqld] auto_increment_increment = 2 <-- spider 수 auto_increment_offset = 2 <-- 시작 값

multiple spider에서의 auto increment 테스트

spider db table이 truncate 된 상태에서 처음으로 insert를 하려고 한다면, shard db의 auto increment값을 참고하여 증가하고,

두 번째 insert 부터는 , spider db table의 auto increment값을 참고하여 증가한다.

# 모든 spider db에서 truncate table을 한 후, # spider db1에서 insert 3번 후, spider db2에서 insert 할 경우 # spider db2는 어떤 값을 삽입할까? #spider db1, db2에서 각 각 실행 trucate table shardTest; #spider db1 insert into shardTest(name) values('spider1'); insert into shardTest(name) values('spider1'); insert into shardTest(name) values('spider1'); #spider db2 insert into shardTest(name) values('spider2'); # shard db 테이블에 증가 된 값 이후부터 들어갔다. select * from shardTest; # id, name '1', 'spider1' '3', 'spider1' '5', 'spider1' '6', 'spider2' # spider db1에서만 truncate table을 한 후, # spider db1에서 insert 3번 후, spider db2에서 insert 할 경우 # spider db2는 어떤 값을 삽입할까? #spider db1에서만 실행 trucate table shardTest; #spider db1 insert into shardTest(name) values('spider1'); insert into shardTest(name) values('spider1'); insert into shardTest(name) values('spider1'); #spider db2 insert into shardTest(name) values('spider2'); # shard db 테이블에 증가 된 값이 아닌 spider db 테이블에 증가 된 값 이후부터 들어갔다. select * from shardTest; # id, name '1', 'spider1' '3', 'spider1' '5', 'spider1' '8', 'spider2'

테스트 할 때, 해당 오류가 발생하면, 다음 처럼 해결하면 된다.

Error Code: 145. Table './mysql/spider_tables' is marked as crashed and should be repaired REPAIR TABLE mysql.spider_tables;