# 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;
# shard db에서 deadlock을 확인해 보면 다음과 같다.
SHOW ENGINE INNODB STATUS;
------------------------
LATEST DETECTED DEADLOCK
------------------------
141120 18:15:30
*** (1) TRANSACTION:
TRANSACTION 22B9, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 494, OS thread handle 0x7f5b647bb700, query id 17329 10.10.3.113 spider update
insert into `test`.`shardTest`(`id`,`name`)values(3,'aaa')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 407 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22B9 lock_mode X insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 22B8, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 493, OS thread handle 0x7f5b64941700, query id 17331 10.10.3.113 spider update
insert into `test`.`shardTest`(`id`,`name`)values(2,'aaa')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 407 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22B8 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 407 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22B8 lock_mode X insert intention waiting
*** WE ROLL BACK TRANSACTION (2)
------------
TRANSACTIONS
------------
Trx id counter 22C2
Purge done for trx's n:o < 22BC undo n:o < 0
History list length 508
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 22BC, not started
MySQL thread id 491, OS thread handle 0x7f5b649c3700, query id 17348 10.10.3.113 spider
---TRANSACTION 0, not started
MySQL thread id 485, OS thread handle 0x7f5b645f4700, query id 17404 10.10.3.73 spider
SHOW ENGINE INNODB STATUS
---TRANSACTION 0, not started
MySQL thread id 69, OS thread handle 0x7f5b6487e700, query id 16991 10.10.3.73 spider
---TRANSACTION 228C, not started
MySQL thread id 70, OS thread handle 0x7f5b6483d700, query id 16990 10.10.3.73 spider
---TRANSACTION 22C1, ACTIVE 24 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 499, OS thread handle 0x7f5b646b7700, query id 17400 10.10.3.113 spider Sending data
select `id`,`name` from `test`.`shardTest` order by `id` desc limit 1 for update
------- TRX HAS BEEN WAITING 24 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 408 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22C1 lock_mode X waiting
------------------
TABLE LOCK table `test`.`shardTest` trx id 22C1 lock mode IX
RECORD LOCKS space id 408 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22C1 lock_mode X
RECORD LOCKS space id 408 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22C1 lock_mode X waiting
---TRANSACTION 22C0, ACTIVE 24 sec
2 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 498, OS thread handle 0x7f5b64900700, query id 17393 10.10.3.113 spider
TABLE LOCK table `test`.`shardTest` trx id 22C0 lock mode IX
RECORD LOCKS space id 408 page no 3 n bits 72 index `PRIMARY` of table `test`.`shardTest` trx id 22C0 lock_mode X
----------------------------
END OF INNODB MONITOR OUTPUT
============================
마리아 디비로 설치
$ 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;