'Technical/DBMS'에 해당되는 글 28건


MySQL이 Oracle 에 인수될 즈음부터 MySQL을 기반으로 하면서 보다 향상된 개념으로 각자가 이름을 떨치며 꾸준히 진행되어 온 프로젝트가 바로 Percona와 MariaDB이다. 참고로 두 프로젝트의 연관성을 비교하는 내용은 이 곳의 포스팅을 보시면 되겠고, 이번 포스팅에서는 Codership이 만든 Synchronous Multimaster 방식의 Galera cluster 를 설치해 보고, 운영에 관련해서 고려할 점들을 정리해 두려 한다.


Multimaster, Synchronous 한 특징을 가지는 이러한 MM 솔루션이 나오기 전에는(물론 완성도가 떨어지고 운영상 불편했던 MMM 같은 것도 있기는 했다), Master-Slave 구조의 비동기 Replication 방식이 많이 쓰였다. 한 편으로는 Semi-sync(Master는 변경 사항을 Slave 로 전달하는 것 까지만 책임을 진다)라는 장점을 가지기는 했지만 태생적으로 비동기식에서 벗어날 수 없기에, 만약의 상황에서 데이터 손실을 감수해야 하는 한계를 지녔었다고 볼 수 있겠다.


다뤄 나가고자 하는 내용을 간단히 요약하면 다음과 같다


* MariaDB Galera Cluster 설치 및 설정 과정

* 노드의 추가(확장)과 Maintenance를 위한 제거 등 운영 방법



1. MariaDB Galera Cluster 설치 및 설정 과정


설치 방법은 소스 빌드, 바이너리 다운로드&설치, rpm 설치 등 여러 가지가 있지만, 여기서는 mariadb.org 에서 권고하는 distro별 링크를 통해 단계를 밟아 나가는 내용을 그대로 따르면서 진행해 보자.


본 글에서 선택한 설치, 운영 환경: Ubuntu 14.04 Trusty, MariaDB 10, Kaist archive


* 설치 & 테스트를 진행할 3개의 Ubuntu 14.4 머신을 준비한다

 - ubuntu14-pv1, 10.0.10.1

 - ubuntu14-pv2, 10.0.10.2

 - ubuntu14-pv3, 10.0.10.3

* Local network이 아닌 외부 망을 통하여 노드간 원격 접속이 필요한 경우(AWS AZ 도 포함) 또는 서버 자체 방화벽(ufw 등) 이 설정되어 있을 때는, 방화벽 설정에서 TCP 3306/4568/4444 port와 TCP, UDP 4567 을 개방해야 한다(☞참조)



첫 번째 Cluster, Doner 노드의 설치와 기동


* 대다수 작업이 root 권한을 필요로 하므로 super user 로 로그인하여 진행한다

* 설치 과정에서 mysql 관리자 계정인 root 암호를 2번 입력(여기서는 편의상 maria 로 정한다)

* 첫 번째로 설정되어 기동되는 MariaDB 머신 도너(Doner) 노드라고 부르며, 다음과 같이 설정

* 여러 머신간의 데이터 동기화가 중요한 환경에서는, DB 데몬이 머신 부팅 후 자동 실행되는 방식을 피하는 것이 바람직

ubuntu@ubuntu14-pv1:~$ su -

root@ubuntu14-pv1:~# apt-get install software-properties-common

root@ubuntu14-pv1:~# apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db

root@ubuntu14-pv1:~# add-apt-repository 'deb http://ftp.kaist.ac.kr/mariadb/repo/10.0/ubuntu trusty main'

root@ubuntu14-pv1:~# apt-get update

root@ubuntu14-pv1:~# apt-get install mariadb-galera-server

root@ubuntu14-pv1:~# mysql_secure_installation

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> grant all on *.* to 'root'@'%' identified by 'maria';

MariaDB [(none)]> grant usage on *.* to sst_user@'%' identified by 'maria';

MariaDB [(none)]> grant all privileges on *.* to sst_user@'%';

MariaDB [(none)]> flush privileges;

MariaDB [(none)]> quit

root@ubuntu14-pv1:~# service mysql stop

root@ubuntu14-pv1:~# apt-get install sysv-rc-conf <== mysqld 의 자동 실행을 중지하기 위함

root@ubuntu14-pv1:~# sysv-rc-conf <== runlevel 2~5 에 대해 space 를 눌러서 해제


* 복제 방법으로 Percona 의 xtrabackup 을 사용하기 위함(rsync 를 선택할 경우 설치하지 않아도 됨)

* 이 경우 데이터스트림 전송을 위한 다용도 relay 솔루션인 socat은 꼭 설치해야 함

root@ubuntu14-pv1:~# apt-get install xtrabackup socat


* 중요 설정, 고유 입력 항목은 붉은 글씨로 표시

* wsrep_node_address 에는 머신 자체 ip 를 등록

* 초기 설정시에는 wsrep_cluster_address에 머신 자체 ip 만 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

# Read by /etc/mysql/my.cnf


[client]

default-character-set = utf8

 

[mysqld]

character-set-server = utf8

collation-server = utf8_general_ci

character_set_server = utf8

collation_server = utf8_general_ci

 

autocommit = 0


# Load Galera Cluster

wsrep_provider = /usr/lib/galera/libgalera_smm.so

wsrep_cluster_name='galera_cluster'

wsrep_retry_autocommit = 0

wsrep_sst_auth=sst_user:maria

#wsrep_sst_method = rsync

wsrep_sst_method = xtrabackup

wsrep_provider_options = "evs.keepalive_period = PT3S; evs.suspect_timeout = PT30S; evs.inactive_timeout = PT1M; evs.install_timeout = PT1M"

 

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1'

wsrep_sst_receive_address=10.0.10.1:4569

 

# Other mysqld options

default-storage-engine=innodb

binlog_format = ROW

innodb_autoinc_lock_mode = 2

innodb_flush_log_at_trx_commit = 2

innodb_locks_unsafe_for_binlog = 1

innodb_log_file_size=100M

innodb_file_per_table

query_cache_size=0

query_cache_type=0

bind-address=0.0.0.0

datadir=/var/lib/mysql

tmpdir=/tmp

user=mysql

log-error=/var/log/mysql/mysql.err


* Cluster 내에서 최초로 기동되는 MariaDB doner 노드이기에 --wsrep-new-cluster 옵션으로 시작

* [주의] Checking for corrupt, not cleanly closed... 메시지는 DB가 정상 기동 되었음을 의미함

root@ubuntu14-pv1:~# service mysql start --wsrep-new_cluster

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


여기까지가 Doner 노드 설정 과정이다.


* 데이터베이스가 정상 작동하는지 간단히 테스트해 보고, 다음 Cluster 확장 단계로 넘어가자

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> create database cluster_test;

MariaDB [(none)]> use cluster_test;

Reading table information for completion of table and column names

You can turn off this feature to get a quicker startup with -A


Database changed

MariaDB [cluster_test]> create table tbl1 (id varchar(20));

Query OK, 0 rows affected (0.25 sec)

MariaDB [cluster_test]> insert into tbl1 values ('abcdefg');

Query OK, 1 row affected (0.00 sec)

MariaDB [cluster_test]> commit;

Query OK, 0 rows affected (0.00 sec)



2. 운영 요령: 노드의 추가(확장)과 머신 점검을 위한 제거 등


앞의 단계는 Cluster 에 1개의 머신만 등록한 상태이다. 이번에는 Cluster 내에 2개의 머신을 더 추가하여, Galera Cluster 에서 권장하는 최소 홀수 개인 3개를 완성하는 과정과 Failover 및 자동 복구, Cluster 내에서 노드의 제거(머신 점검 등의 상황일 때)와 재투입 과정에 대해서 정리해 보자.


Cluster 의 두 번째 노드, 첫 Joiner 노드의 추가


* 앞의 Doner 노드 설정 과정과 거의 동일하며, config(maria.cnf) 의 일부 내용과 기동 방법이 다르다


* wsrep_node_address 에는 머신 자체의 ip 를 등록

* wsrep_cluster_address 에 기존의 Doner 노드와 Joiner 노드 ip 를 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv2:~# scp root@10.0.10.1:/etc/mysql/conf.d/mariadb.cnf /etc/mysql/conf.d/

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2'

wsrep_sst_receive_address=10.0.10.2:4569

...


* Debian, Ubuntu 계열의 경우 특별히 신경 써서 작업해 주어야 하는 부분(debian-sys-maint 계정을 동일하게)

* Doner 노드의 /etc/mysql/debian.cnf 를 복사(password 만 Doner 노드의 것을 가져와도 됨)

root@ubuntu14-pv2:~# scp root@10.0.10.1:/etc/mysql/debian.cnf /etc/mysql/


* Cluster 내에 추가 되는 Joiner 노드는 별도 옵션 없이 시작

root@ubuntu14-pv1:~# service mysql start

 * Starting MariaDB database server mysqld                                [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


* Doner 노드의 config 를 새로이 추가된 Joiner 를 반영하여 수정해 둔다.

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2'

wsrep_sst_receive_address=10.0.10.1:4569

...


* Doner 노드의 Mariadb 를 재시작할 필요는 없다(일단 맞추어 놓기만 하고, 다음에 재시작할 때 읽어 들이면 될 것이다). Joiner 가 추가되면서 이미 내부적으로 서로의 존재가 인식되었기 때문인데, Doner 노드에서 아래의 방법으로 확인할 수 있다. 즉, wsrep_cluster_address 변수는 config 에서 읽어들인 값을 가지고 있지만, Cluster 의 현재 상태 값을 가진 wsrep_incoming_addresses 는 2개 노드 접속 주소를 모두 가지고 있다.

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> show variables like 'wsrep_cluster_address';

+-----------------------+-------------------+

| Variable_name         | Value             |

+-----------------------+-------------------+

| wsrep_cluster_address | gcomm://10.0.10.1 |

+-----------------------+-------------------+

1 row in set (0.00 sec)


MariaDB [(none)]> show status like 'wsrep_incoming_addresses';

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+-------------------------------+

1 row in set (0.00 sec)



Cluster 의 세 번째 노드, 새로운 Joiner 노드의 추가


* wsrep_node_address 에는 머신 자체의 ip 를 등록

* wsrep_cluster_address 에 기존의 노드에 추가하여 새로운 Joiner 노드 ip 를 등록

* wsrep_sst_receive_address 에는 자체 ip:4569 를 등록

root@ubuntu14-pv3:~# scp root@10.0.10.2:/etc/mysql/conf.d/mariadb.cnf /etc/mysql/conf.d/

root@ubuntu14-pv3:~# vi /etc/mysql/conf.d/mariadb.cnf

# MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera3'

wsrep_node_address='10.0.10.3'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.3:4569

...


* Doner 노드의 /etc/mysql/debian.cnf 를 복사

root@ubuntu14-pv3:~# scp root@10.0.10.1:/etc/mysql/debian.cnf /etc/mysql/


* Cluster 내에 추가 되는 Joiner 노드이므로 별도 옵션 없이 시작

root@ubuntu14-pv3:~# service mysql start

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


* 기존의 Doner 노드와 Joiner 노드의 config 를 새로이 추가된 Joiner 를 반영하여 수정해 둔다. 앞 선 과정과 같은 요령

* 위와 마찬가지로 기존 MaraiDB들을 재시작할 필요는 없다

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

 # MariaDB-specific config file.

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3'

wsrep_sst_receive_address=10.0.10.2:4569

...


여기까지가  두 번째 Joiner 노드 추가 과정이며, 목표로 했던 3대로 이루어진 Galera cluster 가 완성되었다.


* 3대로 구성된 Galera Cluster 가 정상 작동하는지 간단한 테스트를 해 보자

root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> show variables like 'wsrep_cluster_address';

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+

1 row in set (0.01 sec)

MariaDB [(none)]> insert into cluster_test.tbl1 values ('xyz123');

1 row in set (0.01 sec)

MariaDB [(none)]> commit;

0 row in set (0.00 sec)


* 최초에 Doner 에서 insert 했던 데이터와 직전에 insert 했던 데이터가 모두 조회된다

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "select * from cluster_test.tbl1;"

+--------+

| id     |

+--------+

| abcdefg   |

| xyz123   |

+--------+


<여기서 퀴즈1> node1(doner), node2, node3 구성일 때, node1의 MySQL이 shutdown 되었다면 node2, node3 중 하나가 doner 가 될 것이다. 잠시 후 node1이 다시 Cluster에 참여하면 node은 원래대로 doner가 될까?정답은 아래로 Drag!
정답: node1은 원래의 Doner 지위를 자동으로 되찾게 됨


Cluster 내의 노드를 제거/복원(재투입)하려면?


서버 머신 점검을 위해 Doner 노드(ubuntu14-pv1)를 Cluster 에서 제거해야 하는 상황이다. 아래의 과정으로 밟도록 하자.


* config 에서 wsrep_cluster_address 설정을 gcomm:// 로 클리어하고 DB를 재시작하면 Cluster 에서 제거됨

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

#wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Comment out

wsrep_cluster_address = 'gcomm://' <== 추가

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv1:~# service mysql restart

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


root@ubuntu14-pv2:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306 |

+--------------------------+-------------------------------+

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+-------------------------------+

| Variable_name            | Value                         |

+--------------------------+-------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306 |

+--------------------------+-------------------------------+



ubuntu14-pv1 머신의 점검/수리가 끝났다. 원래 대로 재투입하려면 다음 과정을 밟으면 된다.


* config 를 이전 상태로 되돌리고 단순히 restart 하면 끝(이미 Galera Cluster 내에 노드가 1개 이상 작동중일 때에는 --wsrep-new-cluster 옵션을 쓰지 않음)

root@ubuntu14-pv1:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera1'

wsrep_node_address='10.0.10.1'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Uncomment

# wsrep_cluster_address = 'gcomm://' <== Comment out

wsrep_sst_receive_address=10.0.10.1:4569

...

root@ubuntu14-pv1:~# service mysql restart

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


root@ubuntu14-pv2:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+

root@ubuntu14-pv3:~# mysql -uroot -pmaria -e "show status like  'wsrep_incoming_addresses';"

+--------------------------+----------------------------------------------+

| Variable_name            | Value                                        |

+--------------------------+----------------------------------------------+

| wsrep_incoming_addresses | 10.0.10.3:3306,10.0.10.2:3306,10.0.10.1:3306 |

+--------------------------+----------------------------------------------+




3. 노드간 데이터 복제가 잘 되지 않는 것 같다. 확인/조치 방법은?


Cluster 내의 모든 노드들은 자신이 Primary 노드라고 인식한다(참고). 그러나 특정한 상황, 즉 네트워크 일시적 단절(network glitch), 과반수 이상의 노드가 장애를 겪거나 또는 split-brain 상태에 빠질 수도 있다. 이렇게 되면 데이터의 동기화에 문제가 발생할 가능성이 커지게 된다.


[여기서 잠깐] split-brain 에 대해 정리해 둘 필요가 있다. 일반적인 split-brain 이란 Master-Slave 상황에서 각자가 Master(또는 primary) 라고 인식하게 되는 상황을 말한다. Galera Cluster 와 같은 Multimaster 의 경우에도 Doner와 Joiner 관계가 있는 것과 같이 Master라 하더라도 '급' 이 다른 구분이 필요하다(즉, "데이터의 오리지널 소스가 누구지?"에 대한 답이 필요하다). 잠시 후 2-node 구성일 때의 네트워크 단절 상황에 대해 테스트 해보기로 하자.


첫 번째 장애: 3-node 구성일 때 1대의 머신에 네트워크 장애 발생


* node2의 네트워크 단절(머신 자체는 동작하지만 node1, node3 과 네트워킹이 안되도록 iptables 로 장애를 흉내 냄)

* 일정 시간이 지나면 node2 는 '쓰기 불가' 상태에 빠지며 wsrep_local_index가 0으로 떨어짐

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.1 -j REJECT

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.3 -j REJECT

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 1     |

+-------------------+-------+


MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 0     |   <== 값이 0인 노드는 Doner 또는 Standalone 노드

+-------------------+-------+


MariaDB [(none)]> show status like 'wsrep_incoming_addresses';

+--------------------------+----------------+

| Variable_name            | Value          |

+--------------------------+----------------+

| wsrep_incoming_addresses | 10.0.10.2:3306 |

+--------------------------+----------------+


MariaDB [(none)]> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 1     |

+--------------------+-------+


MariaDB [(none)]>  show status like 'wsrep_cluster_status';

+----------------------+-------------+

| Variable_name        | Value       |

+----------------------+-------------+

| wsrep_cluster_status | non-Primary |

+----------------------+-------------+


MariaDB [(none)]> insert into cluster_test.tbl1 values ('data1234');

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


[주의사항] Cluster에서 제외된 노드(여기서는 node2)에서는 정상적인 쿼리가 수행되지 않는다

* 이 때 wsrep_provider_options 변수에 pc.bootstrap=1(YES) 값을 설정하면 자체가 Standalone 모드로 작동하게 할 수 있다. 단, 네트워크를 정상화한 이후에 다시 Cluster 내에 투입하려면 반드시 MySQL을 재시작해야 한다

* Cluster 내에서 하나의 노드에서만 수행해야 한다(galera Cluster 에서는 Automatic Bootstrap 이라고 함)

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> SET GLOBAL wsrep_provider_options='pc.bootstrap=1';


* [주의사항] 또 다른 장애 발생 가능성: 이 상황에서 node2의 특정 테이블에 insert 후 PK 변경 DDL 수행시,  Cluster에 재투입하면 node1, node3 에서는 Deadlock 발생 가능성이 있음

* 따라서, Cluster 에서 제외된 노드에서는 더 이상의 DDL이나 insert/update 쿼리가 돌지 않도록 특별히 유의해야 함

root@ubuntu14-pv1:~# 

MariaDB [cluster_test]> select * from tbl1;

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

root@ubuntu14-pv3:~# 

MariaDB [cluster_test]> select * from tbl1;

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction


* [원상복귀] node1, node3 은 정상 작동 중인 상황, node2를 되살린다

* node2 의 네트워크를 되살리면 일정 시간이 지나 node1, node2가 있는 Cluster 로 자동 복귀

root@ubuntu14-pv2:~# iptables -F <== 네트워크 장애가 해결되었음을 시뮬레이션



[특정 노드의 전체 데이터 수동 동기화]

* node2 가 Cluster에서 분리된 이후에 Update되어 데이터가 node1, node3 에 비해 지나치게 상이한 경우의 조치(초기화)

* 아래 과정대로 하면 node1, node3로부터 전체 데이터에 대해 동기화(mysqldump, xtrabackup, rsync 등 방법도 있음)

root@ubuntu14-pv2:~# rm -rf /var/lib/mysql/*

root@ubuntu14-pv2:~# rm -rf /var/log/mysql/*

root@ubuntu14-pv2:~# mysql_install_db

root@ubuntu14-pv2:~# service mysql start --wsrep_cluster_address='gcomm://'

root@ubuntu14-pv2:~# mysql_secure_installation

root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> grant all on *.* to 'root'@'%' identified by 'maria';

MariaDB [(none)]> grant usage on *.* to sst_user@'%' identified by 'maria';

MariaDB [(none)]> grant all privileges on *.* to sst_user@'%';

MariaDB [(none)]> flush privileges;

MariaDB [(none)]> quit

root@ubuntu14-pv2:~# service mysql stop

root@ubuntu14-pv2:~# vi /etc/mysql/conf.d/mariadb.cnf

...

# Galera Node Option

wsrep_node_name='galera2'

wsrep_node_address='10.0.10.2'

wsrep_cluster_address = 'gcomm://10.0.10.1,10.0.10.2,10.0.10.3' <== Uncomment

# wsrep_cluster_address = 'gcomm://' <== Comment out

wsrep_sst_receive_address=10.0.10.2:4569

...

root@ubuntu14-pv1:~# service mysql start

 * Stopping MariaDB database server mysqld                               [ OK ] 

 * Starting MariaDB database server mysqld                               [ OK ] 

 * Checking for corrupt, not cleanly closed and upgrade needing tables.


두 번째 장애: 2-node 구성일 때 1대의 머신에 네트워크 장애 발생(split-brain)


* Cluster내에 2개의 노드(node1, node2) 만 남아 있는 상황

* node2 에 네트워크 장애 발생, 2개의 노드에서 동일하게 데이터베이스가 정상작동하지 않음

* Cluster 내의 Master 노드 정족수가 부족(과반수를 초과해야 하나, quorom=1/2)하게 되기 때문(이러한 한계를 무시하는 설정도 있고, 노드를 흉내내 주는 대안적 방법으로 garbd(Galera Arbiter로 2개 노드일 때 quorom 값을 +1 증가시켜 줌, ☞참고) 를 쓰는 방법도 있으나, 썩 바람직하지 않으므로 Skip)

root@ubuntu14-pv2:~# iptables -A INPUT -d 10.0.10.2 -s 10.0.10.1 -j REJECT


root@ubuntu14-pv1:~# mysql -uroot -pmaria

MariaDB [(none)]> select * from cluster_test.tbl1;

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> use cluster_test;

ERROR 1047 (08S01): WSREP has not yet prepared node for application use


* [원상복귀] node2 의 네트워크를 되살리면 일정 시간이 지나 node1이 있는 Cluster 로 자동 복귀

root@ubuntu14-pv2:~# iptables -F


root@ubuntu14-pv1:~# mysql -uroot -pmaria
MariaDB [(none)]> show status like 'wsrep_local_index';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| wsrep_local_index | 0     |
+-------------------+-------+


root@ubuntu14-pv2:~# mysql -uroot -pmaria

MariaDB [(none)]> show status like 'wsrep_local_index';

+-------------------+-------+

| Variable_name     | Value |

+-------------------+-------+

| wsrep_local_index | 1     |

+-------------------+-------+



- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

 

[mongodb client UI]


MongoDB 2.2.x 2.1.2 부터 TTL(Time To Live) 기능이 제공되고 있다. IT에 익숙한 분이라면 icmp, DNS, cache server 등의 프로토콜이나 설정/작동 방법상에서 자주 나타나는 용어라는 것을 알 수 있으리라.


mongodb에서의 이 기능은 단순하게 설명하자면, 지정된 시간 이전의 레코드를 자동으로 지우는(purging, removing) 기능이다. 주로 통계성 데이터나 모니터링 데이터 등 시계열 데이터가 저장되어 있을 경우나 일정 시간 동안만 저장되어야 하는 session 정보 등을 저장하는데 유용하게 사용할 수 있겠다.

중요한 주의사항 몇 가지를 아래에 정리해 두고 테스트를 진행해 본다.
  1. mongodb의 Date 에 해당하는 날짜시간 데이터가 저장되는 필드가 필요하고, 여기에 ensureIndex로 인덱스를 두는 방식이다
  2. 해당 필드는 다른 index 에 복합적으로 참조되지 않아야 한다(단일 필드, 단일 인덱스)
  3. 해당 필드에는 위 1번에서 처럼 Date BSON type의 데이터가 UTC 기준으로 저장되어야 자동으로 지워진다
  4. mongodb의 ttl thread는 1분단위로 동작한다. 즉 10초로 설정한다고 데이터 저장 후 10초만에 지워지는 것이 아니라 1분 가량의 오차가 존재하며, DB 시스템의 부하 정도(mongod의 workload가 얼마나 큰지)에 따라 달라질 수 있다는 즉, 정확히 해당 시간 경과후 지워진다는 보장은 없다는 것.
  5. 모든 컬렉션의 공통 필드인 _id 필드는 ttl 필드로 사용할 수 없다.
  6. capped collection은 ttl index를 적용할 수 없다.

각설하고, 아래와 같이 간단히 테스트 해 본다

> db.tt_col.save( { id: 'id1', name: 'aaa', dt: new Date() } );
> db.tt_col.save( { id: 'id2', name: 'bbb', dt: new Date() } );
> db.tt_col.save( { id: 'id3', name: 'ccc', dt: new Date() } );
> db.tt_col.find();
{ "_id" : ObjectId("509de58b1493b98702441310"), "id" : "id1", "name" : "aaa", "dt" : ISODate("2012-11-10T05:26:35.370Z") }
{ "_id" : ObjectId("509de5ac1493b98702441311"), "id" : "id2", "name" : "bbb", "dt" : ISODate("2012-11-10T05:27:08.218Z") }
{ "_id" : ObjectId("509de5ba1493b98702441312"), "id" : "id3", "name" : "ccc", "dt" : ISODate("2012-11-10T05:27:22.450Z") }
> db.tt_col.ensureIndex( {dt: 1}, {expireAfterSeconds: 10} );
> db.tt_col.find();
{ "_id" : ObjectId("509de58b1493b98702441310"), "id" : "id1", "name" : "aaa", "dt" : ISODate("2012-11-10T05:26:35.370Z") }
{ "_id" : ObjectId("509de5ac1493b98702441311"), "id" : "id2", "name" : "bbb", "dt" : ISODate("2012-11-10T05:27:08.218Z") }
{ "_id" : ObjectId("509de5ba1493b98702441312"), "id" : "id3", "name" : "ccc", "dt" : ISODate("2012-11-10T05:27:22.450Z") }
잘 보면 날짜/시간 부분이 localtime이 아닌 UTC 기준시간으로 저장되어 있음에 유의한다.

약 40초 후에 컬렉션의 데이터를 조회해 보니 3건의 데이터가 삭제되어 있음을 확인할 수 있다. 
> db.tt_col.find().count();
0
> db.tt_col.find();
>


응용할 수 있는 트릭이라면, 지워지게 하고 싶지 않은 데이터가 있을 경우 어떨게 하면 될까?


한 가지 방법은 보관이 필요한 데이터를 찾아서 ttl 설정 필드 값을 Date() 로 update하는 것이다. 만약 계속 보존처리를 해야 한다면 매번 update를 수행해야 할 것이고,

계속 보존해야 한다면, 단순하게도 다음과 같이 ttl 필드를 Date가 아닌 다른 데이터 값으로 설정하면 된다.

> db.tt_col.update( { id: 'id1' }, { dt: null } );


[pymongo 2.3]

사용 방법은 유사하지만 python 내에서 ttl 기능 설정/사용시에 유의할 사항이 있다. 아래 예시의 함정을 찾아 보자.


Python 2.7.2 (default, Aug 19 2011, 20:41:43) [GCC] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import pymongo

>>> from datetime import datetime, date, time, timedelta

>>> datetime.now()

datetime.datetime(2012, 11, 2, 2, 3, 50, 18750)

>>> pyMongoConnStr = 'mongodb://10.10.10.70:28017/myschema'

>>> connMongo = pymongo.Connection( pyMongoConnStr )

>>> connMongo.myschema.tt_col.save( { 'a':1, 'b':2, 'dt': datetime.now() } )
ObjectId('50aa68a94422527639f91a34')
>>> connMongo.monitor.t_col.ensure_index( 'dt', pymongo.ASCENDING, expireAfterSeconds = 15 )
>>> connMongo.myschema.tt_col.find_one()
{u'a': 1, u'dt': datetime.datetime(2012, 11, 2, 2, 13, 13, 517000), u'_id': ObjectId('50aa68a94422527639f91a34'), u'b': 2}


15초 가량 후에 해당 row가 삭제되어야 하는데, 10분이 지나도 멀쩡하게 남아 있다. index 설정을 봐도 잘못 된게 없고, 시스템 시간도 정확하게 현재시간을 가리키고 있는데, ...


결론을 말하자면, 위에서 등록한 row는 한국 시간으로 9시간 가량 후에 지워질 것이다. 왜냐하면 mongodb의 ttl thread 는 UTC 를 기준으로 작동하는데, python에서 mongodb에 등록한 데이터(row)에서 dt 필드의 값인 datetime.now() 는 KST(대한민국표준시; 또는 시스템 시간이 localtime) 기준의 시간 값이기 때문이다. 즉 python에서 ttl index 필드의 시간 값을 설정할 때는 반드시 datetime.utcnow() 를 사용하여야만 한다. 이점 유의하자.



- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

 

LGU+ 회사의 클라우드(cloudN) 환경의 가상머신(VM,Virtual Machine)에 oracle 11gR2를 설치해 보았다. 대개 서버 설치시에 X-window를 포함하지 않는 경우가 많으므로, java 와 GUI가 제공되는 그래피컬 환경(일반적으로 주로 사용하는 OUI 모드)이 아닌, 텍스트 기반의 서버 환경에서 설치를 진행한다(구글은 이 Silent mode를 침묵 모드라는 말로 멋지게 번역해 준다).


이론은 간단한 듯 하지만, 실제로 해 보면 결코 그렇지만은 않다. 특히 response 파일 설정에서, 다소의 시행착오와 installer 재실행을 몇 번 해 보아야 한다. 일단 한 번 해 보면 어렵지 않게 누구나 따라서 설치 가능하도록 소상하게 과정을 다루도록 하겠다.

 

다만, 서버에 오라클을 설치할 정도의 엔지니어라면 기본적인 Linux 서버의 사용법이나 소프트웨어 설치, 운영에 어느 정도는 기본 지식이 있을 것이라는 전제하에 기초에 해당하는 지식은 과감히 설명없이 넘어가려 함에 유의해 주자.


[사전 작업 - Prerequisites]


반드시 거쳐야 할 작업으로, 스킵하면 installer가 validate시에 칞젏하게 뱉어내 주며, 다음 단계로 진행할 수가 없다.


1. 커널 파라미터 조정

Oracle이 구동되기 위한 기본 설정이므로 아래와 같이 /etc/sysctl.conf 내에 설정하고 root 계정에서 sysctl -p로 실행해야 함을 잊지 말자.


# Mandatory prerequisite conditions


# semaphores: semmsl, semmns, semopm, semmni

kernel.sem = 250 32000 100 128


fs.file-max = 6815744

fs.aio-max-nr = 1048576


net.ipv4.ip_local_port_range = 9000 65500


net.core.rmem_default = 262144

net.core.wmem_default = 262144


kernel.core_uses_pid = 1

fs.suid_dumpable = 1


이 값은 최소한의 값이며 시스템의 상황에 따라 별도로 튜닝을 해 주어야 할 경우도 발생한다.

파라미터들의 값이 적절하지 않으면 installer가 log 파일을 통해서 상세하게 투덜거려 주므로 tail로 log 파일을 반드시 모니터링 하도록 한다.


fs.suid_dumpable 설정은 CentOS 버전에 따라 deprecated 되었을 수도 있으니 참고로 알아두자.


2. 의존하는 패키지 설치


yum install 명령으로 아래의 패키지들을 설치한다. x64 OS라 하더라도 i386에 해당되는 필수 패키지는 반드시 설치하여야 함에 유의한다.


zip.x86_64 unzip.x86_64

ksh.x86_64

perl.x86_64

binutils.x86_64 binutils220.x86_64

libaio.x86_64 libaio-devel.x86_64

libaio.i386 libaio-devel.i386

pdksh.x86_64

compat-libstdc++-33.x86_64

compat-gcc-34.x86_64

libstdc++.i386

libgcc.i386

elfutils.x86_64 elfutils-libelf.x86_64

elfutils-libelf-devel.x86_64

sysstat

unixODBC.x86_64 unixODBC-devel.x86_64

unixODBC.i386 unixODBC-devel.i386


3. VM 방화벽 설정


my.cloudn.co.kr 에 접속하여, Network Filter 메뉴에서 Oracle_sec_rule 와 같은 rule을 정의하고 등록한다. 기본적으로 linux VM이므로 ssh용 TCP 22, ICMP 등을 개방하여야 하며, 이에 덧붙여 Oracle에 접속할 PC나 서버의 IP와 TCP port(1521)를 등록하고 저장한다.


Security Group 메뉴에서 보안그룹을 등록하고, VM NIC그룹맵 수정 기능을 선택, Oracle이 설치되는 VM을 선택하고, 보안관리 드롭다운에서 위에서 등록한 rule을 선택, 운영대상여부를 체크하고 저장, 적용 여부를 묻는 질문에 '예'를 선택하면 방화벽 설정이 종료된다.


접속이 허용되도록 설정된 PC 등에서  telnet oracle_server_ip 1521 와 같이 명령을 실행하여 TCP 포트가 잘 개방되었는지 확인해 보자.


[설치 파일 다운로드, VM에 복사]


www.oracle.com 사이트에 가입하고 oracle 11gr2 에 해당하는 파일들을 다운로드 받는다.


linux.x64_11gR2_database_1of2.zip

linux.x64_11gR2_database_2of2.zip


* 참고: 보통은 오라클 설치 후 패치 파일 또는 패치셋을 애드온 개념으로 설치해야 하지만, 11gr2 linux판의 패치셋은 10g와 같은 이전 버전과 달리 '패치'가 아닌 '재설치', 즉 전체 설치방식(애들 말로 완전체...)이므로 만약 적용할 경우 기존 데이터를 반드시 백업해야 한다.


설치할 VM에 /home/data 디렉토리로 추가 디스크인 /dev/sdb1 을 마운트(/etc/fstab 파일에 설정)해 두고, oracle_zip_file 와 같은 서브디렉토리를 만들고 local PC에서 VM으로 복사해 넣는다. windows 계열의 PC에서 다운로드 받았다면 winscp 같은 훌륭한 무료 프로그램으로 linux 서버에 업로드 해 넣을 수 있다.

 

oraserver# mount -t ext3 /dev/sdb1 /home/data

mypc# scp -i ~/sec_key/mykey.pem linux.x64_11gr2_database_* root@vm_ip:/home/data/oracle_zip_files


[설치 준비]


root 계정으로 oracle계정과 그룹을 다음과 같이 생성한다.

# groupadd -g 5000 dba

# useradd -g dba oracle

# passwd oracle


Oracle inventory(log, 설치 실행을 위한 임시 작업 디렉토리)는 /home/oracle/oraInventory 로 하기로 한다.

# vi /etc/oraInst.loc

inventory_loc=/home/oracle/oraInventory

inst_group=dba


# chown oracle.dba /etc/oraInst.loc


# vi /etc/pam.d/login (라인 추가)

session    required     pam_limits.so


# vi /etc/security/limits.conf (라인 추가)

oracle       soft    nproc   2047

oracle       hard    nproc   16384

oracle       soft    nofile  1024

oracle       hard    nofile  65536


Oracle 데이터베이스의 실제 설치 위치(ORACLE_BASE)는 /home/data/oracle 로, 데이터베이스명(Global database name, ORACLE_SID)은 gdbora1으로 하기로 하자.

# su - oracle

# vi .bash_profile

export PS1="[\u@\H \w]\$ " # CentOS의 prompt를 바꿔둔다

export EDITOR=vi

export ORACLE_BASE=/home/data/oracle

export ORACLE_HOME=$ORACLE_BASE/product/11.2.0

export ORACLE_SID=gdbora1

export ORACLE_TERM=xterm

export NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949

export ORA_NLS10=$ORACLE_HOME/nls/data

export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:/usr/local/lib

export PATH=$PATH:$ORACLE_HOME/bin

export CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib

export LANG=C


Oracle 설치를 위한 프로그램 파일, 스크립트, 설정 및 response 파일등을 저장할 위치는 /home/oracle/database 로 한다.

# cd

# unzip /home/data/oracle_zip_files/linux.x64_11gR2_database_1of2.zip

# unzip /home/data/oracle_zip_files/linux.x64_11gR2_database_2of2.zip # 현재 디렉토리에 database 디렉토리가 생성된다


[response(응답) 파일 작성 및 엔진 설치]


# cd ~/database/response

# cp db_install.rsp myresp.rsp


# vi myresp.rsp (아래에 해당하는 라인을 찾아서 편집한다)

oracle.install.option=INSTALL_DB_AND_CONFIG

UNIX_GROUP_NAME=dba

INVENTORY_LOCATION=/home/oracle/OraInventory

SELECTED_LANGUAGES=en,ko

ORACLE_HOME=/home/data/oracle/product/11.2.0

ORACLE_BASE=/home/data/oracle

oracle.install.db.InstallEdition=EE

oracle.install.db.DBA_GROUP=dba

oracle.install.db.OPER_GROUP=dba

oracle.install.db.config.starterdb.globalDBName=gdbora1

oracle.install.db.config.starterdb.SID=gdbora1

oracle.install.db.config.starterdb.memoryLimit=512

oracle.install.db.config.starterdb.installExampleSchemas=true

oracle.install.db.config.starterdb.enableSecuritySettings=true

oracle.install.db.config.starterdb.password.ALL=Oracle123

oracle.install.db.config.starterdb.password.SYS=Oracle123

oracle.install.db.config.starterdb.password.SYSTEM=Oracle123

oracle.install.db.config.starterdb.password.SYSMAN=Oracle123

oracle.install.db.config.starterdb.password.DBSNMP=Oracle123

oracle.install.db.config.starterdb.storageType=FILE_SYSTEM_STORAGE

oracle.install.db.config.starterdb.fileSystemStorage.dataLocation=/home/data/oracle/datadir

oracle.install.db.config.starterdb.fileSystemStorage.recoveryLocation=/home/data/oracle/backupdir

DECLINE_SECURITY_UPDATES=true


2개의 터미널창에서 동시에 작업한다

# cd ~/database

# ./runInstaller -noconsole -silent -force -waitforcompletion -responseFile /home/oracle/database/response/myresp.rsp


다른 하나의 터미널창에서 runInstaller 가 보여 주는 로그 파일을 tail -f /home/oracle/oraInventory/logs/installAction....log 명령으로 관찰한다.


runInstaller가 성공적으로 동작하여 데이터베이스 엔진이 설치되었다면

......

INFO: Completed executing action at state <finish>

INFO: Waiting for completion of background operations

INFO: Completed background operations

INFO: Moved to state <finish>

INFO: Waiting for completion of background operations

INFO: Completed background operations

INFO: Validating state <finish>

WARNING: Validation disabled for the state finish

INFO: Completed validating state <finish>

INFO: Terminating all background operations

INFO: Terminated all background operations

INFO: Successfully executed the flow in SILENT mode

INFO: Finding the most appropriate exit status for the current application

INFO: Exit Status is -3

INFO: Shutdown Oracle Database 11g Release 2 Installer

와 같은 결과가 확인될 것이다.


[데이터베이스 기동 및 리스너 설정]


root 계정으로 작업한다.

# /home/data/oracle/product/11.2.0/root.sh


oracle 계정으로 DBA 상태로 접속해 본다

# su - oracle

# sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on Wed Sep 26 15:55:58 2012


Copyright (c) 1982, 2009, Oracle.  All rights reserved.


Connected to an idle instance.


SQL> 


리스너를 기동할 준비를 아래와 같이 한다

# vi ~/database/response/netca.rsp (해당 라인 편집)

SHOW_GUI=false

LOG_FILE=""/home/data/oracle/product/11.2.0/log/netca.log""


# cd /home/data/oracle/product/11.2.0/bin/

# ./netca /silent /log /home/data/oracle/product/11.2.0/log/netca.log /responseFile /home/oracle/database/response/netca.rsp


리스너를 기동/정지해 보고 프로세스 상태를 점검하자

# lsnrctl stop

# lsnrctl start

# lsnrctl status

# ps -eaf | grep -v grep | grep oracle


[데이터베이스 스키마 생성, 연결 설정]


oracle 계정으로 작업한다.


# vi /home/oracle/database/response/dbca.rsp (해당 라인 편집)

GDBNAME = "gdbora1"

SID = "gdbora1"

SYSPASSWORD = "Oracle123"

SYSTEMPASSWORD = "Oracle123"

NATIONALCHARACTERSET= "UTF8"


# cd /home/data/oracle/product/11.2.0/bin/

# ./dbca -silent -templateName /home/data/oracle/product/11.2.0/assistants/dbca/templates/General_Purpose.dbc -responseFile /home/oracle/database/response/dbca.rsp

Copying database files

1% complete

3% complete

11% complete

18% complete

26% complete

37% complete

Creating and starting Oracle instance

40% complete

45% complete

50% complete

55% complete

56% complete

60% complete

62% complete

Completing Database Creation

66% complete

70% complete

73% complete

85% complete

96% complete

100% complete

Look at the log file "/home/data/oracle/cfgtoollogs/dbca/gdbora1/gdbora1.log" for further details.


수행결과를 log 파일을 통해 확인해 보자

# cat /home/data/oracle/cfgtoollogs/dbca/gdbora1/gdbora1.log


리스너가 정상 작동하는지 확인한다

# lsnrctl status

LSNRCTL for Linux: Version 11.2.0.1.0 - Production on 26-SEP-2012 16:50:24


Copyright (c) 1991, 2009, Oracle.  All rights reserved.


Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))

STATUS of the LISTENER

------------------------

Alias                     LISTENER

Version                   TNSLSNR for Linux: Version 11.2.0.1.0 - Production

Start Date                26-SEP-2012 16:40:38

Uptime                    0 days 0 hr. 9 min. 45 sec

Trace Level               off

Security                  ON: Local OS Authentication

SNMP                      OFF

Listener Parameter File   /home/data/oracle/product/11.2.0/network/admin/listener.ora

Listener Log File         /home/data/oracle/diag/tnslsnr/vm00046-1/listener/alert/log.xml

Listening Endpoints Summary...

  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host_ip_address)(PORT=1521)))

Services Summary...

Service "gdbora1" has 1 instance(s).

  Instance "gdbora1", status READY, has 1 handler(s) for this service...

Service "gdbora1XDB" has 1 instance(s).

  Instance "gdbora1", status READY, has 1 handler(s) for this service...

The command completed successfully


# sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on Wed Sep 26 15:55:58 2012


Copyright (c) 1982, 2009, Oracle.  All rights reserved.


Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options


SQL> connect / as sysdba

Connected.

SQL> select status from v$instance;


STATUS

------------------------

OPEN


SQL> 



[클라이언트 접속 환경 설정과 그 이후...]


아래 링크를 통해 'instant client'를 다운로드 받고 OCI 를 설치하여야 한다.

http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html


 설치 가능한 풀 버전은 아래 링크를 통해 다운로드 받을 수 있다.

http://www.oracle.com/technetwork/database/enterprise-edition/downloads/112010-win64soft-094461.html


<주> Windows에서 Toad for oracle을 사용한다면 64bit용 instant client를 다운로드 받으면 oci.dll 이 로딩되지 않고 toad에서 oracle 접속이 되지 않는다. 이는  Quest software에서 여전히 32bit 버전의 toad.exe를 고수하고 있기 때문인데, 구글링 해 보면 registry 를 조작하는 방법으로 잘 정리한 문서들이 많이 있으니 참조해서 문제를 해결하자.


TNSNAMES.ora 편집 및 데이터베이스 접속에 대해서는 개발자 입장의 지식이고, 이미 많은 개발자들이 다루고 있는 부분이므로 본 포스팅의 성격과 맞지 않아서 생략한다.



- Barracuda -



저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

 

MongoDB를 백업하는 방법에는 Journaling을 지원하는 Block 장치일 경우 snapshot, lock & fsync, mongodump & mongorestore 등의 여러 가지가 있다. mongo.org 에 의하면 증분 백업(incremental backup)을 지원하지는 않고 있으며, 아직까지 이러한 기능을 수행하는 도구 또한 존재하지 않는 상황이다.


데이터베이스 엔진이 중단되지 않아야 하는 상황의 경우 dump & restore를 통한 방법이 일반적이므로 아래에 그 사용법에 대해 정리해 둔다. 이 방식은 쉽게 표현하자면 단순히 레코드 단위로  백업(dump)을 받고, 복구시에도 레코드 단위로 insert를 반복적으로 수행하게 된다.


[mongodump]

# 전체 데이터베이스 Full backup

/mongo/bin/mongodump --out /mongobackup/20120901 --oplog --host 10.10.0.10 --port 28017 -uuser -ppass


* 특정 데이터베이스 스키마만 백업할 경우에는 --db dbsname 옵션을 사용한다.

* --oplog 옵션은 백업이 진행되고 있는 도중에 발생한 트랜잭션에 대한 데이터를 별도로 처리하여 누락되는 백업데이터가 없도록 해 주는 기능이다.

* 백업이 끝나면 /mongobackup/20120901 디렉토리에 각 데이터베이스 스키마별로 서브디렉토리가 생성되어 컬렉션별로 .bson 파일들이 생성된다.

* 용량과 서버 성능에 따라 수십분 내지 수시간이 걸릴 수 있으며, 백업되는 디스크의 용량도 수백GB 또는 수TB까지도 사용 가능하여야 할 수도 있다.


[mongorestore]

# 전체 데이터베이스 Full restore

/mongo/bin/mongorestore --host 10.10.0.10 --port 28017 -uuser -ppass --oplog --drop  /mongobackup/20120901/


* 특정 데이터베이스 스키마만 복구하려면 아래와 같이 수행한다. 백업디렉토리의 하위 디렉토리 위치에 대상 데이터베이스명을 정확히 기입하여야 한다.

/mongo/bin/mongorestore --host 10.10.0.10 --port 28017 -uuser -ppass --drop --db dbname /mongobackup/20120901/dbname/


* --drop 옵션은 복구시에 해당 컬렉션을 삭제하는 방식이다. 즉 복구시에 동일한 컬렉션이 존재할 경우 컬렉션을 초기화하고 dump된 데이터만을 채워 넣으므로, dump 이후에 저장된 데이터는 소실됨을 의미하므로, 데이터베이스 전체를 dump된 시점으로 되돌릴 때 사용한다.

*  데이터베이스 개별 복구일 경우 --oplog 옵션은 적용되지 않는다.

 


- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


이전 글을 포스팅 하고 보니 의외로 HammerOra 를 사용해서 DBMS 벤치마킹을 하는 작업이 단순하지 않다는 생각이 들어, 따라하기 버전의 테크니컬 리포트 하나 정도는 만들어 둠이 좋을 듯하여 같은 제목 일련번호 2를 붙여 추가로 포스팅한다.


실제로 구글링, 네이버링을 해서 국내나 해외사이트들의 HammerOra 관련 정보를 찾아 보아도, 반드시 알아 두고 체크해 주어야 하는 데도 불구하고, 그에 대한 주의사항이 없는 경우가 많다. 그래서 더 이상 정상적인 진행이 되지 않는 경우가 대부분이며, 심지어 HammerOra 매뉴얼에서 조차, 진행 과정에 대한 명확한 설명이 명료하게 되어 있지 않은 부분도, 본 글을 추가하는 이유 중의 하나이다.

 

글을 보시는 분들 중, 개인적으로 데이터베이스 성능 측정을 해 보고자 하는 분은 직접 따라 해 보시고, 궁금하거나 잘 안 풀리는 부분이 있으면 부담 없이 비밀 댓글로 문의해 주시면, 아는 범위 내에서 도움을 드리도록 하겠다.



데이터베이스 성능 측정


HammerOra 버전은 2.11, 대상 DBMS는 MSSQL Server를 적용하였고, 각 서버는 LGU+ 의 CloudN내의 가상서버를 사용하였다. 


- HammerOra server: CPU4, Mem2g

- DB Server: CPU2, Mem4g


덧붙여 말하지만 본 테스트는 특정 데이터베이스나 서버의 성능을 측정하고자 하는 것이 아니므로, 결과로 나타나는 성능수치에 대해서는 특별히 관심을 두지 않아도 되며, 단지 본인의 테스트 결과와의 단순 비교정보로 생각해주기 바란다. 실제로 하드웨어의 규모나 성능에 따라 측정 결과는 1~2만 tpmC부터 수십만~수백만 tpmC 까지 다양한 결과를 보여주게 된다.


1. DB Server의 설정

DB Server는 Windows 2008 R2, MS SQLServer 2008 standard 버전을 사용하였다. 테스트용 데이터베이스 엔진의 관리자 계정은 데이터베이스 생성 권한을 가지는 sa 계정을 사용한다.


2. HammerOra server의 설정

Windows 2008 R2, HammerOra 2.11, SQL Server Native Client 10.0(이전 포스팅 참조)


3. TPC-C schema 생성


3.1. HammerOra 실행

프로그램을 실행하면 로고 화면이 나오고 조금은 세련되지 못한 HammerOra 메인 화면이 나타난다.


3.2. TPC-C 데이터베이스 구축


TPC-C 를 위한 데이터베이스는 전자상거래의 비즈니스모델을 구현, 시뮬레이션하게 되는데, 위의 그림과 같이 창고/상품 정보, 고객과 각 고객별 권역정보로 구성되며, TPC-C 스키마를 생성하게 되면 실제와 유사한 데이터가 자동으로 생성되어 데이터베이스가 구축된다.




메인화면 좌측의 메뉴영역에서 SQL Server를 더블클릭하면 위의 팝업창에 선택사항이 나타나고 기본 모델인 TPC-C가 선택된 상태가 된다. OK 선택.



 

Schema Build 메뉴의 +버튼을 선택하고 Options를 더블클릭하면 위의 팝업화면이 나타나며, 스키마를 생성할 데이터베이스 서버의 ip주소와 접속 정보를 입력하고 OK 선택.




 

실제로 스키마와 데이터베이스를 구축하는 단계로 가기 위해 Build 를 더블 클릭(또는 상단의 블럭 모양의 아이콘 클릭)한다. 확인 팝업창에서 '예(Y)' 선택.



 

선택 옵션에 따라 데이터베이스 생성, 창고정보/상품정보/고객정보 등의 데이터 등록이 진행되며 수분~수십분 가량 경과후에 위의 그림과 같이 SCHEMA COMPLETE 메시지가 나타나고 상단 상태창에 COMPLETE 메시지가 보이면 스키마 생성이 완료된 상태이다.



 

여기서부터 주의해서 진행해야 하는데(주의 1), 위 화면에서와 같이, 상단 아이콘의 Destroy Virtual Users 아이콘(신호등 모양)을 클릭하여 스키마 생성시에 사용된 가상 유저 정보를 Clear 해 주어야만 오류 없이 다음 단계로 진행할 수가 있다.



 

이제 부하를 발생시킬 드라이버 스크립트를 정의하는 단계이다. 좌측 메뉴창에서 Driver Script 메뉴의 + 버튼을 클릭하고 Options를 더블 클릭. 팝업 화면에서 Standard Driver Script(이미 선택 되어 있음), Total trx per User(가상 유저당 트랜잭션 수) 의 입력창에 10000 을 입력하고 OK 선택(당연히 수치는 조정 가능)



 

여기도 주의할 지점(주의 2). 앞에서 드라이버 스크립트 옵션 지정 후, 위의 화면과 같이 반드시 Load 메뉴을 더블클릭하여 드라이버 스크립트를 로드하여야 다음 단계 진행 가능.



 

부하를 발생시킬 가상 유저 수와 반복 횟수를 위의 화면과 같이 입력하고 OK 선택.

 


 

 

가상 유저 생성 단계(주의 3). 좌측 메뉴 창의 Create 메뉴를 더블클릭(또는 상단의 사람 아이콘=Create Virtual Users 클릭)하여 가상유저를 생성하여야만 벤치마킹의 수행이 가능하다.


이제 준비 끝.

 


 

4. 벤치마킹 시작과 결과 보기


4.1. 테스트 시작


 

위의 그립에서 상단의 화살표 아이콘(Run Virtual Users)를 클릭하면 테스트가 시작된다.



4.2. 테스트 중지/재개


 

테스트가 진행되는 동안 우측 창의 Virtual User Output 탭화면에서 각 가상 유저들의 시뮬레이션되어 발생되는 액션에 대한 트랜잭션의 들이 출력된다. 이 작업을 멈추고 싶다면 상단 아이콘 중 화살표 아이콘 왼쪽의 신호등 아이콘(원래는 가상유저 생성아이콘이며, 테스트가 진행되면 아이콘 모양이 신호등 모양으로 바뀜을 알 수 있다)을 클릭하여 멈출 수 있다.


 

 

테스트에 투입되는 가상유저의 수를 변경하고 싶다면 앞에서 설명한 신호등 아이콘을 클릭하여 테스트를 멈춘 후, Virtual User의 Options 메뉴를 더블클릭하여 가상 유저수를 수정하고 테스트를 처음부터 다시 시작할 수도 있다.



 

앞에서 가상 유저 수를 4로 변경하여 테스트를 다시 시작하는 화면이다. 이 때도 역시 마찬가지로 Create 메뉴를 더블 클릭(주의 3 참조)하여 가상 유저 생성후, Run Virtual Users 아이콘을 클릭하여 테스트를 진행한다.



4.3. 테스트 성능 수치(tpmC, TPC-C 에 의한 분당 trx수) 확인하기


 

tpmC 측정 성능 수치 값을 확인하기 위해서는 상단의 펜 모양 아이콘(Transaction Counter)을 클릭한다.



 

앞의 선택 결과에 따라 테스트가 진행되는 도중에 측정되는 tpmC의 수치 값이 그래프와 함꼐 출력됨을 확인할 수 있다.

 


 

 

(참고) 그래프 Refresh 주기 등을 변경하기 위해서는 상단 메인 메뉴의 Options > Transaction Counter 메뉴 항목을 클릭하면 된다.



- Barracuda -

 

저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


최근(2015.4)에 HammerOra에서 HammerDB 로 이름이 변경되었고, Oracle TimesTen, Redis 등도 지원하는 등, 꾸준한 변화를 보이고 있네요.



HammerOra('해머오라' 라고 읽자. 의미는 'Hitting Oracle with a Hammer'라고 한다) 는 시중에서 별 다른 제약 없이 사용해 볼 수 있는 거의 유일한 Open Source DBMS 성능 측정 툴이고, TPC-C, TPC-H 등 요즘 주로 사용하는 성능측정 방법을 구현해 놓은 것으로

http://hammerora.sourceforge.net 에서 Linux/MS-Windows(X86/X64) 용으로 각각 빌드된 패키지를 다운로드 받아서 사용할 수 있다.


더구나 각 플랫폼 별로 간단 설치법과 심지어 해당 DBMS를 직접 설치할 수 있는 상세한 매뉴얼을 제공하고 있으니 초심자에게 많은 도움이 될 듯 하다. 적용 가능한 DBMS는, 2.11 버전부터는 기존의 Oracle, MS SqlServer, MySQL 뿐 아니라 PostgreSQL 까지도 지원 가능하도록 업데이트 되어 있다. HammerOra의 개발과 업데이트는 sourceora(sourceora.com)에서 제공하며, 2010년부터 sourceforge를 통해서 업데이트가 이루어지고 있다 (Pro Oracle RAC on Linux 책에서도 잠깐 언급된 적이 있었다).


프로그램의 설치 과정 자체는 다운로드후 설치-프로그램-실행이라는 단순한 수순을 따르지만, 실제로는 측정 대상이 되는 DBMS에 접속이 가능하도록 Oracle OCI 또는 ODBC 드라이버를 별도로 설치해 주어야 하므로, 제공되는 설치매뉴얼을 꼼꼼하게 읽고 진행해야 한다. 실제로 MS Sqlserver 를 대상으로 테스트를 진행하려고 무심코 테스트를 시도하였으나, DB 접속 실패가 발생해서, 곰곰 생각해보니 HammerOra가 SqlServer에 접속하는 방식이 ODBC 가 아닌 Native SQLserver Client를 사용하는데, 그에 맞는 적절한 Client 를 설치해 주지 않아서 접속 자체가 되지 않는 것이었다.


HammerOra 설치를 Windows 2008 서버에, 테스트 대상이 MS Sqlserver 2008 이라면 아래의 사이트에서 클라이언트를 적절히 선택해서 HammerOra 서버장비에 설치해 주어야 한다.


http://www.microsoft.com/ko-kr/download/details.aspx?id=8824

Microsoft SQL Server 2008 Native Client 항목에서 X86/X64/IA64 패키지 중에서 선택


단, 상식적이기는 하지만, 주의해야 할 사항은 HammerOra 를 설치해서 사용할 서버 자체의 사양이 일반적인 사양보다 충분히 좋아야 한다는 점에 유의한다. 즉, 부하를 발생시키는 장비 자체가 저사양/저성능이면 원하는 충분한 부하가 측정 대상 서버로 적절하게 생성/분배/처리가 되지 않을 것이기 때문이다.


<참고 1>

TPC는 Transaction Processing Performance Council(www.tpc.org) 이라는 국제 공인 단체에서 시스템의 성능을 측정하는 객관적인 기준을 방법론 형태로 제시한 것이다. 그 중에서 TPC-C는 tpmC 라는 측정 결과값을 도출해 주며, 이는 "분당 처리건수" 라는 의미를 지닌다.


여기서 주의하여야 할 것은 이미 많은 문헌이나 블로그들에서 TPC 방법론의 허와 실에 대해 분석한 부분을 주의 깊게 읽어 보아야 하며, TPC 측정을 통해 나타나는 결과가 시스템이나 서버의 성능을 판단하는 절대적인 기준은 될 수 없다라는 사실이다.


단적으로 말하자면, 위에서 다룬 HammerOra 를 통한 TPC-C 측정 방법은 "5개의 트랜잭션 유형 / 9개의 테이블 / 테이블당 10~15개의 컬럼" 만으로 구성된 주문처리(OLTP) 업무를 기준으로 만들어진 것이지만, 실제 각 기업의 업무용 Application의 경우 수백개의 테이블, 테이블당 수십/백개의 컬럼과 다양한 비즈니스 로직이 복잡하게 적용되어 결과가 나오게 되므로, TPC 측정 결과가 좋다고 해서 실제 그 회사의 업무를 적용했을 때의 최고의 성능이 발휘되리라는 기대는 하지 않는 것이 좋으나, 모든 경우에 해당되는 절대적인 측정 도구나 방법이 없기 때문에 "그러리라 기대"하면서 참고 자료로 사용하여야 한다는 것이 본 참고 부분의 골자 되겠다.


<참고 2>

TPC에서 제안하는 성능측정 방법 중 현재 주로 채택/적용되는 방법은 아래와 같다.

  • TPC-C(측정 단위: tpmC)

  OLTP환경의 DBMS 트랜잭션 성능을 측정하기 위한 방법론, 전자상거래 비즈니스 로직

  •  TPC-E(측정 단위: tpsE)

  보다 향상된 트랜잭션 처리 성능층 위한 방법론, 증권거래 비즈니스 로직

  •  TPC-H(측정단위: qphH)

  DSS(Decision Support System)의 성능 측정 방법론, 병렬 update와 복잡도 높은 쿼리의 동시 수행에 관여되는 업무

  •  TPC-DS

  보다 향상된 DSS(Decision Support System)의 성능 측정 방법론, 주로 DSS, OLAP, data mining 업무

  •  TPC-A/B/D/R/W/App

  더 이상 사용하지 않는(Obsolete or Retired) 방법론들


<참고 3>

비즈니스 영역에 따라 웹서버, 웹어플리케이션서버 등의 성능 측정시에는 SPEC(Standard Performance Evaluation Corporation, 

http://www.spec.org)에서 제시하는 SPEC CPU2006, SPECweb99_SSL 등의 방법을 적용하기도 한다.



[관련 글]

2012/09/14 - [Technical/DBMS] - HammerOra로 DBMS 성능 측정하기(TPC-C) -2



- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


5.1.X~5.5.X 까지도 가끔 발생되는 오류인데

mysqldump 를 실행하면 로그상에 보이는 오류메시지이다.


[ERROR] mysqld: Table './mysql/proc' is marked as crashed and should be repaired

[Warning] Checking table:   './mysql/proc'


이 때는 mysql 유틸리티에 포함된 mysqlcheck 을 사용하여 해결할 수 있다.


# mysqlcheck --repair mysql proc -uroot -ppassword

저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


상용 운영 상태에서 Database를 shutdown하는 의사 결정이 쉽지 않은데, 2대의 Replication 데이터베이스들의 동기화가 깨졌을 때는 이 방법을 쓰도록 한다.
Dual Master 구성일 경우 M1:10.0.3.71, M2:10.0.3.72, 동기화할 대상 DB는 my_db 라고 가정하고 아래와 같이 진행한다. 단, 양쪽 데이터베이스를 모두 Running 상태로 유지하되, Read/Write 작업은 M1(동기화 원본) 쪽에서만 일어나는 상황이어야 한다.

M1> slave stop;
M1> reset slave;
M2> slave stop;
M2> reset slave;
M2> drop database my_db;
M2> create database my_db;

M1# mysqldump -uroot -ppassword --databases my_db --opt --master-data=2 >  mysql_data_20110101.sql
M2# scp root@10.0.3.71:mysql_data_20110101.sql /workdir
M2# grep MASTER_LOG_FILE /workdir/mysql_data_20110101.sql 
M2# head -25 /workdir/mysql_data_20110101.sql

 
위에서 grep으로 검색 된 결과에서 head를 수행한 결과, 25 라인 정도 위치에 있는 MASTER_LOG_FILE, MASTER_LOG_POS 값을 이용해야 하니 따로 메모 또는 에디터로 복사해 둔다.
(전체 데이터베이스를 동기화하고 싶을 경우, --databases my_db 옵션 대신
--all-databases=TRUE 옵션을 사용한다)

M2# mysql -uroot -ppassword < /workdir/mysql_data_20110101.sql
M2> flush logs;
M2> reset slave;
M2> change master to master_host='10.0.3.71', master_user='root', master_password='password', master_log_file='mysql-bin.000019', master_log_pos=429;

메모 또는 복사해 둔 2개의 값(예: mysql-bin.000019, 419) 을 사용하여 동기화를 수행한다.

M2> slave start;
M2> show slave status; 

 Slave 쓰레드를 기동하고 상태를 확인한다.

M2> show master status;
M1> flush logs;
M1> reset slave;
M1> change master to master_host='10.0.3.72', master_user='root', master_password='password', master_log_file='mysql-bin.000022', master_log_pos=106;
M1> slave start;
M1> show slave status; 

 M2 의 로그파일과 위치를 이용해서 M1을 동기화하고, Slave 쓰레드를 기동하고 상태를 확인한다. 최종 점검을 위해서 test 테이블을 생성하고 양쪽에서 insert 를 수행하고 동기화가 되는지 확인하도록 한다.


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


Mongo DB를 사용한 Replication은 그 조합과 목적에 따라 여러 가지 구조로 구현된다. Master-Slave 이중화 및 다중화, Master-Master 이중화, Master-Master Circular 구조의 다중화, Cluster 기술이 적용된 Replica Set 등, ... 결국은 데이터베이스의 고가용성을 갖추기 위한 목적은 같지만 말이다.

가장 대표적이고 단순한 것은 Master-Slave이다. 이를 통해서 Data redundancy는 구현되지만, Fail-over 문제, 자원의 비효율적 사용 때문에 Master-Master 구조를 선호하는 것이 일반적이다. 또한 그 구조도 비교적 단순하며 Fail-over 를 통한 Availability 뿐 아니라 Read/Write 부하의 분산의 측면에서 아직까지 중/소규모 데이터 처리시에 효과적으로 활용될 수 있다. 물론 Database의 앞 쪽에 Load Balancer가 있어, 양쪽으로 부하를 분산해 줄 수 있을 경우 또는 드라이버나 Application 에서 Fail-over에 대응하는 접속 설정이 가능할 경우에 해당된다.

이 방식에서의 치명적인 단점은 바로 운영의 부담이 크다는 것이다. 데이터를 양쪽 노드에 모두 쓰기가 가능함으로 해서, Fail-over의 혜택을 누렸지만, 이를 복구한 이후에 재 투입을 할 경우, 짧은 순간이지만, 각 노드가 Master 이면서 Slave 이기 때문에 살아 있던 Master의 replication 옵션을 바꾸어서 장애 복구한 노드를 재 투입하여 Replication을 하고, 정상적으로 Replication될 경우 다시 한번 양 쪽의 raplication 옵션을 Master-Master 바꾸어서 재실행하여야 한다.

10Gen 에서는 MongoDB 초창기(1.4?) 부터 Master/Slave Replication 의 단점을 보완하고자 지금은 없어진 Replica Pair, Replica Set 기능을 개발 해 왔고 1.6.* 이후 부터 본격적으로 안정된 Replica Set 기능을 제공하고 있다. 즉 2대 이상의 서버를 이용해 Master-Slave(1:n) 구조로Data를 복제하여 저장하되, 정상 상황에서 하나의 Primary만 존재하여 작동하되, Primary에 문제가 생길 경우 Slave 중의 하나를 Primary로 선정(vote)하여 Master 기능을 넘겨 받는 구조이다.


[주의] 
모든 경우에 Replica Set이 만능은 될 수 없다. mongos와 Config server를 사용하여 쓰기 부하를 분산하도록 해야 하며, Master-Slave 이중화 구성에서 Replica Set으로 이전하려면, Application 측의 driver 를 변경하여 Primary 노드를 찾아가도록 하는 추가적인 노력이 필요한 점에 유의하여야 하며, 기존의 이중화 구성에서 사용한 Load Balancer의 설정 방식에도 변화를 주어야 한다. 하지만 한 번 적용해 놓으면 트리 구조의 단순성과 추가 노드 투입(확장성)또는 장애 대처의 편리성(운영 편의), 거의 100%에 가까운 가용성 때문에 중 대규모 데이터를 처리하고자 하는 환경인 경우에 지극히 효과적인 장점을 보이는 것은 분명하다.


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


* 2011/09/22에 update됨
* MySQL이 MySQL 5.5 부터는 SemiSync 라는 쓸만한 기능으로 Availability가 더 향상되었다.
즉, M-S1S2 형태의 Replication에서 M의 Transaction과 S로의 binlog write가 병렬로 처리되며(Master가 Slave의 binlog로의 전송을 보장, 동기=sync), S의 binlog에서 Storage 로의 write 는 비동기(async)로 처리된다(==> 반동기=SemiSync)
[참조] http://www.mysqlkorea.co.kr/gnuboard4/bbs/board.php?bo_table=develop_03&wr_id=73

* 기존의 5.1.x 대에 비해서 script의 위치나 Replication 설정 방식에서 약간의 차이를 보이고 있다.

* M1=Master1, M2=Master2

* 선행 패키지 설치

# zypper in -y cmake ncurses-devel readline-devel bison



* 다운로드 & 빌드

wget http://www.percona.com/redir/downloads/Percona-Server-5.5/Percona-Server-5.5.15-21.0/source/Percona-Server-5.5.15-rel21.0.tar.gz
#  tar xvzf Percona-Server-5.5.15-rel21.0.tar.gz
# cd Percona-Server-5.5.15-rel21.0/
# groupadd mysql 
# useradd -g mysql -s /bin/false mysql
# sh BUILD/autorun.sh
./configure --prefix=/user/service/mysql --with-mysqld-user=mysql --sysconfdir=/user/service/mysql/conf --with-unix-socket-path=/tmp/mysqld/mysql.sock --with-charset=utf8 --with-extra-charsets=all --with-plugins=innobase,innodb_plugin,myisam,partition
# make && make install



* 디렉토리, my.cnf 설정

# cd /user/service/mysql
# export PATH=$PATH:/user/service/mysql/bin (.bashrc 에도 추가) 
# mkdir conf



# vi conf/my.cnf
[client]

port                                    = 3306
socket                                  = /tmp/mysql.sock
[mysqld_safe]
socket                                  = /tmp/mysql.sock
nice                                    = 0
# TimeZone
#default-time-zone                       = 'Asia/Seoul'

[mysqld]
# TimeZone
#default-time-zone                       = 'Asia/Seoul'

# UTF8
init_connect=SET collation_connection   = utf8_general_ci
init_connect                            = SET NAMES utf8
character-set-server                    = utf8
collation-server                        = utf8_general_ci
# Storage engine
default-storage-engine                  = innodb
# no difference between upper and lowercases
lower_case_table_names                  = 1
# General settings
user                                    = mysql
pid-file                                = /tmp/mysqld/mysql.pid
socket                                  = /tmp/mysqld/mysql.sock
port                                    = 3306
# Directory settings
basedir                                 = /user/service/mysql
datadir                                 = /user/service/mysql/data
tmpdir                                  = /tmp
# ETC
skip-external-locking
# Tunnig options
key_buffer_size                         = 384M
max_allowed_packet                      = 16M
table_open_cache                        = 512
sort_buffer_size                        = 2M
read_buffer_size                        = 2M
read_rnd_buffer_size                    = 8M
myisam_sort_buffer_size                 = 64M
thread_cache_size                       = 8
# for MyIsam
myisam-recover                          = BACKUP
max_connections                         = 250
max_user_connections                    = 200
# Try number of CPU's*2 for thread_concurrency, 5.5.3+ ignored
# thread_concurrency                    = 8
# Important for bulk loading
query_cache_size                        = 32M
# * Logging and Replication
slow_query_log                          = /user/service/mysql/data/mysql-slow.log
long_query_time                         = 2

# Replication Master Server (default)
server-id                               = 1

log-bin                                = mysql-bin
log-warnings
log-slave-updates
replicate-same-server-id                 = 0
auto-increment-increment               = 1
relay-log                               = mysql-relay-bin

expire_logs_days                        = 10
max_binlog_size                         = 100M
binlog_format                           = ROW
# * InnoDB
innodb_data_home_dir                    = /user/service/mysql/data
innodb_data_file_path                   = ibdata1:2000M;ibdata2:10M:autoextend
innodb_log_group_home_dir               = /user/service/mysql/data

# buffer_pool_size up to 50 - 80 % of RAM
#innodb_buffer_pool_size                 = 1536M # 사용 가능 memory 에 맞게 설정
innodb_buffer_pool_size                 = 256M
innodb_additional_mem_pool_size         = 20M
# log_file_size to 25 % of buffer pool size
innodb_log_file_size                    = 384M
innodb_log_buffer_size                  = 8M
innodb_flush_log_at_trx_commit          = 1
innodb_lock_wait_timeout                = 10
innodb_file_per_table
innodb_file_format                      = barracuda

[mysqldump]
quick
max_allowed_packet                      = 32M
[mysql]
no-auto-rehash # faster start of mysql but no tab completition
[myisamchk]
key_buffer_size                         = 256M
sort_buffer_size                        = 256M
read_buffer                             = 2M
write_buffer                            = 2M
[mysqlhotcopy]
interactive-timeout


* 기본 데이터베이스 스키마 생성 & Grant 설정

# ./scripts/mysql_install_db --defaults-file=/user/service/mysql/conf/my.cnf --user=mysql

# mysqld_safe --defaults-file=/user/service/mysql/conf/my.cnf --log-bin-trust-function-creators=1 &

# mysqladmin -u root password 'password'
# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -ppassword mysql 
## Database에서 Timezone 을 사용할 경우, my.cnf 에서 comment 로 막아 둔 default-time-zone 의 comment 를 해제
# mysqladmin  -uroot -ppassword shutdown
# mysqld_safe --defaults-file=/user/service/mysql/conf/my.cnf --log-bin-trust-function-creators=1 --skip-slave --relay-log=mysql-relay-bin &
# mysql -uroot -ppassword
M1> use mysql;
M1> grant all privileges on *.* to 'root'@'%' identified by 'password' with grant option;
M1> grant all privileges on *.* to 'root'@'localhost' identified by 'password' with grant option;
M1> flush privileges; 

root 권한 설정/ 확인
M1> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO root@"%" IDENTIFIED by 'password';
M1> flush privileges; 

사용하려고 하는 database명이 mydb 라고 가정하고, 데이터베이스 생성과 개발자(사용자) 계정을 생성하고 권한을 아래과 같이 설정한다
M1>  insert into mySql.User (host, User, Password) values ('%', 'devuser', password('dev_passwd'));
M1> insert into mySql.User (host, User, Password) values ('localhost', 'devuser', password('dev_passwd'));
M1> flush privileges; 
M1> create database mydb;
M1> GRANT ALL PRIVILEGES ON mydb.* TO 'devuser'@'localhost' IDENTIFIED BY 'dev_passwd';
M1> GRANT ALL PRIVILEGES ON mydb.* TO 'devuser'@'%' IDENTIFIED BY 'dev_passwd'; 
M1> REVOKE ALTER, DROP ON mydb.* FROM 'devuser'@'localhost';
M1> REVOKE ALTER, DROP ON mydb.* FROM 'devuser'@'%'; 
M1> flush privileges; 
M1> GRANT ALL PRIVILEGES ON mysql.func TO 'devuser'@'localhost' IDENTIFIED BY 'dev_passwd';
M1> GRANT ALL PRIVILEGES ON mysql.func TO 'devuser'@'%' IDENTIFIED BY 'dev_passwd'; 
M1> GRANT ALL PRIVILEGES ON mysql.proc TO 'devuser'@'localhost' IDENTIFIED BY 'dev_passwd';
M1> GRANT ALL PRIVILEGES ON mysql.proc TO 'devuser'@'%' IDENTIFIED BY 'dev_passwd'; 
M1> GRANT ALL PRIVILEGES ON mysql.procs_priv TO 'devuser'@'localhost' IDENTIFIED BY 'dev_passwd';
M1> GRANT ALL PRIVILEGES ON mysql.procs_priv TO 'devuser'@'%' IDENTIFIED BY 'dev_passwd'; 
M1> flush privileges; 



* M1의 DB를 source로 하여 M2 로 동기화 후 Master-Master 설정하기
   M1, M2 의 DB shutdown(또는 M1을 down 시키기 곤란한 경우 flush logs; flush tables wih read lock 으로 lock 설정, M2는 down)

# rsync -rpv root@M1_ip_addr:/user/service/mysql/data /user/service/mysql/
## Default port 22가 아닌 sshd  접속의 경우
# rsync -rpv -e "ssh -p 55000" root@M1_ip_addr:/user/service/mysql/data /user/service/mysql/ 
## CloudN, EC2 등과 같은 Cloud Platform의 pem 보안 키 접속일 경우
# rsync -rpv -e "ssh -i XXXX,pem" root@M1_ip_addr:/user/service/mysql/data /user/service/mysql/ 
# chown -R mysql.mysql ./data

* M1, conf/my.cnf 에서 server_id = 1 임을 확인
* M2, conf/my.cnf 에서 server_id = 2(또는 2보다 큰 정수) 임을 확인

* M1, M2 Database start
# mysqld_safe --defaults-file=/user/service/mysql/conf/my.cnf --log-bin-trust-function-creators=1 --skip-slave --relay-log=mysql-relay-bin &



* M1에서
# mysql -uroot -ppassword
M1> show master status;

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
| mysql-bin.000010 |      107 |              |                  |
1 row in set (0.00 sec)

* M2에서
# mysql -uroot -ppassword
M2> change master to master_host='M1_ip_addr', master_user='root', master_password='password', master_log_file='mysql-bin.000010', master_log_pos=107;
M2> slave start;
M2> show slave status;

* M1에서 M2 를 source로 하여 마찬가지로 change master to 로 Replication 을 설정하고 slave start 로 복제를 시작시킨다



* MySQL 5.5 에서는, 5.1.X 에서 적용되던 my.cnf 에서의 master_host, master_user, master-password 변수를 통한 Replication 설정은 더 이상 사용되지 않게 바뀌었다.
 


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


Haproxy 의 option mysqlchk 로 DB 의 가용 여부를 점검하는 데에 쓸 수 있으나
정상적인 점검이 정확하게 되지 않으며, MySQL의 connection을 잠식하는 문제점이 있다.
단순히 DB 접속 port만 감시하는 방법도 쓸 수 있으나, DB의 정상 가동여부를 체크하는 방법으로는 적합하지 않다.

xinetd service와, 간단한 db connection & query script를 이용
Assumption: MySQL home - /user/service/mysql
Thanks to Unai Rodriguez(script author) & Sysbible(http://sysbible.org/)

1. script 작성

# cd /user/service/mysql/bin; vi mysql_hc
#!/bin/bash MYSQL_HOST="localhost" MYSQL_PORT="3306" MYSQL_USERNAME="mysql_hc" MYSQL_PASSWORD="password" TMP_FILE="/user/service/mysql/var/mysqlchk.out" ERR_FILE="/user/service/mysql/var/mysqlchk.err" # a simple query /user/service/mysql/bin/mysql --host=$MYSQL_HOST --port=$MYSQL_PORT --user=$MYSQL_USERNAME --password=$MYSQL_PASSWORD -e "show databases;" > $TMP_FILE 2> $ERR_FILE # Check the output. If it is not empty then everything is fine and we return # something. Else, we just do not return anything. # if [ "$(/bin/cat $TMP_FILE)" != "" ] then # mysql is fine, return http 200 /bin/echo -e "HTTP/1.1 200 OK\r\n" /bin/echo -e "Content-Type: Content-Type: text/plain\r\n" /bin/echo -e "\r\n" /bin/echo -e "MySQL is running.\r\n" /bin/echo -e "\r\n" else # mysql is fine, return http 503 /bin/echo -e "HTTP/1.1 503 Service Unavailable\r\n" /bin/echo -e "Content-Type: Content-Type: text/plain\r\n" /bin/echo -e "\r\n" /bin/echo -e "MySQL is *down*.\r\n" /bin/echo -e "\r\n" fi

# chown root.mysql mysql_hc; chmod 744 mysql_hc
# mysql -uroot -ppassword
  > GRANT SELECT on mysql.* TO 'mysql_hc'@'%' \
  > IDENTIFIED BY 'password' WITH GRANT OPTION;
  > GRANT SELECT on mysql.* TO 'mysql_hc'@'localhost' \
  > IDENTIFIED BY 'password' WITH GRANT OPTION;
  > flush privileges;
# ./mysql_hc - 실행 결과 확인(HTTP/1.x 200 OK)


2.  vi /etc/services 에 아래 라인 추가

mysql_hc    28001/tcp                      # mysql_hc - mysql health checker

3. vi /etc/xinetd.d/mysql_hc

# default: on
# description: mysql_hc
service mysql_hc
{
        flags           = REUSE
        socket_type     = stream
        port            = 28001
        wait            = no
        user            = root
        server          = /user/service/mysql/bin/mysql_hc
        log_on_failure  += USERID
        disable         = no
        only_from       = 0.0.0.0/0      # recommended to put the IPs that need
                                                 # to connect exclusively (security purposes)
        per_source      = UNLIMITED
}
 
# service xinetd restart

4. 정상 작동 test

# telnet 10.10.0.10 28001

Trying 10.10.0.10... Connected to 10.10.0.10. Escape character is '^]'. HTTP/1.1 200 OK Content-Type: Content-Type: text/plain MySQL is running. Connection closed by foreign host.


5. HaProxy configuration 에 설정 추가

listen RDB-1
        bind 10.10.0.71:28000
        mode tcp
        option httpchk
        timeout connect 5m
        timeout client 30m
        timeout server 30m
        server RDB-1 10.10.0.10:3306 check port 28001 inter 5s rise 1 fall 3
        server RDB-2 10.10.0.30:3306 check port 28001 inter 5s rise 1 fall 3 backup
        log global


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


extrabackup은 incremental backup을 지원하지만 innodb에 대해서만 가능하므로 MyISAM등의 복합적 엔진구성인 경우 작동하지 않는다.

이러한 경우 MySQL에서 제공하는 innobackupex base의 Percona 수정판 perl utility로 백업을 할 수 있다(innobackupex-1.5.1). 하지만 이 perl source에 버그가 숨어 있어서, 실행하면 "Invalid version format (non-numeric data) at /usr/bin/innobackupex-1.5.1 line 1708." 와 같은 에러를 뱉어 내므로 아래와 같이 수정한다.
...
} else {
$perl_version = chr($required_perl_version[0])
. chr($required_perl_version[1])
. chr($required_perl_version[2]);
#if ($^V lt $perl_version) {
#my $version = chr(48 + $required_perl_version[0])
# . "." . chr(48 + $required_perl_version[1])
# . "." . chr(48 + $required_perl_version[2]);
#print STDERR "$prefix Warning: " .
# "Your perl is too old! Innobackup requires\n";
#print STDERR "$prefix Warning: perl $version or newer!\n";
#}
}

<참고> innobackupex 사용법

- PATH 추가
xtrabackup binary 파일들을 mysql bin direcotry에 복사하고
# export PATH=$PATH:/user/service/mysql/bin
과 같이 명령 경로를 지정해야만 제대로 동작한다(옵션에서 절대 path를 지정할 수 있지만 정확히 작동하지 않음에 주의)

- 백업(Percona XtraDB일 경우)
# innobackupex-1.5.1 --defaults-file=/user/service/mysql/conf/my.cnf --user=root --password=dbpass --host=host_ip --databases=db_name --ibbackup=xtrabackup --redo-only /user/service/backups
* Target directory에 timestamp로 서브 디렉토리가 자동으로 만들어지고 여기에 데이터가 백업된다
* Percona가 아닌 MySQL에 대해서는 xtrabackup 대신 xtrabackup_51 를 지정

- 복구(copy back, Database shutdown 필요)
cp -r /user/service/backups/2011-01-01_01-15-27 /user/service/mysql/var


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


MySQL에서 NOT FOUND exception은 Cursor Fetch 시에만 발생한다.

따라서 update 아래의 IF 문 내의 처리는 의도한 대로 동작하지 않는다. 즉, 코더의 의도는 Update 문을 실행해서 해당 데이터가 없다면 If 문 내의 문장이 처리되기를 원한 거겠지만, 아래의 이 IF 문 내의 문장은 전혀 실행되지 못하게 된다.
DECLARE MyErr INT default 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND set MyErr = -1;
...
UPDATE table
   SET COL = 'data'
WHERE
   KEY_COL = 'key data';

IF MyErr < 0 THEN
    statements_for_not_found...;
END IF;

또한 update에서 해당 row가 없을 경우에 found_rows()=0 역시 동작하지 않는다.
이런 경우 반드시 아래와 같이 ROW_COUNT() 를 이용해서 코딩해야 한다.
/* DECLARE CONTINUE HANDLER FOR NOT FOUND set MyErr = -1; */
...
...
/* IF MyErr < 0 THEN */
IF ROW_COUNT()=0 THEN
    statements_for_not_found...;
END IF;
...


- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


Database 내에서 발생하는 모든 쿼리들을 logging할 필요가 있을 때
SHOW VARIABLES LIKE 'general_log';
SHOW VARIABLES LIKE 'log_output';

SET GLOBAL general_log = 1;
SET GLOBAL log_output = 'table';
-- 필요시에만 켜서 사용

SET GLOBAL general_log = 0;
SET GLOBAL log_output = 'file';
-- 평상시에는 이렇게 disable해 두어야 엔진의 성능에 부담이 가지 않으므로 주의

Query logging table: mysql.general_log

* MySQL에서는 milli-second 단위로 시간을 처리하지 않으므로 timestamp는 초 단위까지만 기록된다.
ALTER TABLE mysql.general_log 
    ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT AFTER argument,
    ADD PRIMARY KEY(seq),
    ENGINE=MYISAM;
으로 log table을 alter한 후 order by seq desc와 같이 select 해서 실행 순서대로 정렬하여 활용하면 된다.
MySQL에서 사용되는 기본 general_log 테이블에는 index 가 없으므로, 위와 같이 index 를 이용한 조회를 하지 않으면
데이터베이스 성능에 부담을 주게 되며,

확인이 끝 난 후 반드시 general_log를 disable해 두어야만 성능상의 문제로 재난이 생기지 않으니 반드시 유의해야 한다.

general_log 테이블을 비워야 할 경우, delete 쿼리를 수행하면 '로그테이블에 대한 처리 불가'라고 오류가 발생하게 되므로
아래와 같이 처리해야 한다.
SET GLOBAL general_log = OFF; -- log를 계속 쌓도록 하려면 생략
USE mysql;
create table tmp_general_log like general_log;
rename table generlal_log to old_general_log, tmp_general_log to general_log;


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


(MySQL은 Percona XtraDB 5.1.49 기준)
binutils
automake
libtool 
bison 
make 
termcap 
libtermcap.x86_64 
libtermcap-devel.x86_64 
gcc
gcc-c++.x86_64 
libstdc++.x86_64 
ncurses 
ncurses-devel.x86_64 
glibc.x86_64 
glibc-common.x86_64 
glibc-devel.x86_64 
glibc-headers.x86_64 
glibc-utils.x86_64


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

Tag centos, mysql

* Reference : http://www.qijoo.com/FAPM/mysql/5.1/MySQL_51_en/ch06s12.html

[Statement-based]
<Up>
 - MySQL 3.23 부터 존재해 온 검증된 기술이다
 - 상대적으로 log 파일 크기가 작다. 특히 다량의 update/delete의 경우에 효과가 크다
    log 크기가 작으면 저장공간에 부담이 적고 빠른 백업이 가능하다
 - log 파일에 모든 변경 내용이 저장되어 DB audit 에서 사용 가능하다
 - log 파일은 replication 용도 뿐 아니라, 적절한 시간과 지점에서의 recovery에 사용될 수 있다
 - Slave는 Mater와 다른 더 새로운 버전의, row 구조가 다른 MySQL로도 적용될 수도 있다
<Down>
 - UPDATE문에서의 random함수 사용시에 replication이 보장되지 않을 수 있다
 - statement 내에서 found_rows(), uuid() 또는 non-deterministic UDF(User-defined function) 등의
   함수 사용시에 정확한 replication을 기대할 수 없다
   ex) load_file(), uuid(), user(), found_rows(), sysdate() (--sysdate-is-now 옵션으로 수행하지 않은 경우)
   cf) rand(), now()등의 대부분의 함수는 가능
 - INSERT...SELECT 문의 경우, 상대적으로 많은 수의 row-level lock이 발생할 수 있다 <1>
 - index를 사용하지 않아서 table scan이 발생하는  UPDATE문의 경우, 상대적으로 많은 수의 Master 내에서의 row-level lock이 발생할 수 있다 <2>
 - innodb의 경우, auto_increment 가 적용된 테이블에 INSERT시에, 실제로 충돌이 일어나지 않는 다른 INSERT 문들이 제약을 받을 수 있다 <3>
 - 내장함수들이 동일한 now() 함수를 호출하게 되는데, 이것이 원하는 결과일 수도, 아닐 수도 있다
 - Slave에는 Deterministric UDF만 존재하고, 사용되어야 한다
 - Slave의 동기화에 문제가 생기는 경우, 시간이 지날수록 Master와의 차이가 커질 가능성이 높다
 - Master와 Slave의 테이블들의 구조는 (거의) 동일해야 한다

[Row-based]
<Up>
 - 모든 것들이 동기화 된다. 가장 안전한 Replication 방법이다.
    * Mixed mode(--binlog-format=MIXED) 일 경우, CREATE 같은 DDL은 statement-based로, DML들(GRAND, REVOKE를 포함하여)은 row-based 로동작한다
 - 대부분의 다른 DBMS들과 동일한 복제 방법이다
 - 일반적인 경우, PK를 가지는 테이블에 대해 빠른 동기화가 이루어 진다
 - Statement-based의 <1>, <2>, <3> 경우에 대해, Master에서 상대적으로 적은 수의 lock이 발생한다 
 - INSERT, UPDATE, DELETE 문들에 대해, Slave에서 상대적으로 적은 수의 lock이 발생한다
 - SMP 머신일 경우 Slave에서 여러개의 thread를 통해 data를 병렬적으로 반영할 수 있게 된다
<Down>
 - Log 파일의 크기가 커질 가능성이 많다
 - 대량의 데이터가 롤백될 경우 binlog에 해당 데이터가 다량 쌓이게 된다
 - Statement-based의 경우 단순 statement(UPDATE, DELETE 문 등)만 log에 기록되지만, row-based 는
   모든 UPDATE 또는 DELETE된 row의 데이터가 기록되어 binlog가 상대적으로 긴 시간동안 lock 될 것이고
   Concurreny 문제가 발생될 가능성이 커진다
 - 크기가 큰 BLOB 값을 생성하는 Deterministic UDF의 경우 replicate에 상당히 많은 시간이 소요될 수 있다
 - 어떤 statement가 실행되었는지 log를 분석할 수 없다
 - Slave에서 어떤 statement가 Master로부터 전송되고 실행되었는지 알 수 없다
 - Non-transactional bulk operation(SELECT * FROM table_name)에 대해서 Masterdhk Slave에서의 결과가 달라질 가능성이 있다

* 위의 대부분의 내용은 reference의 내용을 번역하고, 본인이 정리하기 쉽게 각색한 것이다.

[Bottom Line]

- 모든 경우에 해당하는 정답은 없으나, 개발자가 어떤 Stored function이나 UDF를 쓸지 100% 통제가 불가능하다면
  row-based가 더 권장된다.
- Trigger, stored procedure를 주로 사용하는 환경이라면 row-based가 더 권장된다
  (실제로 Trigger를 다수 사용하는 Schema에서 Statement-based replication을 설정하면 상당히 자주 Sync가
   깨지는 경우는 발견할 수 있다. 즉, 이 경우에는 MUST 라고 할 수 있다)
- DDL, DML에서 uuid(), rand() 와 같은 non-deterministic 함수를 사용하거나, cascading foreign key relation
  등을 통해 indirect update를 자주 수행하는 경우 row-based가 더 권장된다.
- Storage가 넉넉하고 하드웨어 성능이 좋다면 row-based가 더 권장된다.
- 상대적으로 단순한 Schema를 사용하고, 대량의 데이터가 한꺼번에 UPDATE, DELETE, INSERT...SELECT 되는
  경우가 빈번하다면 Statement-based가 더 권장된다.


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


Full dump 파일이 100MB 이상 되면 slave 에서 로드하다보면 제대로 되는지 확인이 안되서
시간은 급한데 억장이 무너진다면 아래의 방법을 써본다.

* Master: 10.10.0.200, Slave: 10.10.0.201

1. Master database read lock
# mysql -uroot -prootpass
<Master> flush logs;
<Master> flush tables with read lock;

2. Rsync from master to slave(Slave)
# mysqladmin -uroot -prootpass shutdown
# rm -rf /user/services/mysql/data/*
# rsync -r -p -v root@10.10.0.200:/user/service/mysql/data /user/service/mysql/

* Check my.cnf
server-id=2 (or other number, not 1)
master-host=10.10.0.200
master-user=root
master-password=rootpass

# chown -R mysql.mysql /user/service/mysql/data
# mysqld_safe --user=mysql --log-bin-trust-function-creators=1 --skip-slave --relay-log=mysql-relay-bin &
# mysql -uroot -prootpass
<Slave> stop slave;
<Slave> reset slave;

3. Reset master & start slave thread
<Master> unlock tables;
<Master> reset master; -- purge all log-bins
<Master> show master status;
<Slave> start slave;
<Slave> show slave status;

* Slave_IO_State : Waiting for master to send event, Master_Host : master_ip, ... => Successful 


- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들



* make 시에 아래와 같은 오류 발생
------------------------------------------------------------------------------------------------------
gcc -DHAVE_CONFIG_H -I. -I../include -I../include -I../include -I../sql    -O3 -m32
-march=core2 -fomit-frame-pointer -pipe -fno-exceptions   -DUNIV_LINUX
@ndbcluster_includes@  -c perror.c
gcc: @ndbcluster_includes@: No such file or directory
make[3]: *** [perror.o] Error 1
------------------------------------------------------------------------------------------------------

[Solution]
* configure 직후에 ./extra/Makefile에서 @ndbcluster_include@ 삭제 -- (1)
            "             ./sql/Makefile에서 @ndbcluster_inclide@, @NDB_SCI_LIBS@ 삭제 -- (2)

# ./configure --prefix=/user/service/mysql --with-mysqld-user=mysql --sysconfdir=/user/service/mysql/conf --with-unix-socket-path=/tmp/mysqld/mysql.sock --with-charset=utf8 --with-extra-charsets=all --with-plugins=innobase,myisam,semisync,partition

# vi ./extra/Makefile --(1)
# vi ./sql/Makefile --(2)

# make && make install

* Enjoy & have fun ~


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


[Getting ready]

* Install spidermonkey(js.lib)
# curl -O ftp://ftp.mozilla.org/pub/mozilla.org/js/js-1.7.0.tar.gz
# tar zxvf js-1.7.0.tar.gz
# cd js/src
# export CFLAGS="-DJS_C_STRINGS_ARE_UTF8"
# make -f Makefile.ref
# JS_DIST=/usr make -f Makefile.ref export

* install scons, pcre-devel
# zypper in scons
# zypper in pcre-devel

* Packages needed for building  mongo
<Fedora 8, 10, ...Opensuse 11, ...>
git, tcsh, scons, gcc-c++, glibc-devel
boost-devel pcre-devel js-devel readline-devel
boost-devel-static, readline-static ncurses-static
<Ubuntu 9.x>
tcsh git-core scons g++
libpcre++-dev libboost-dev libreadline-dev xulrunner-1.9.1-dev
libboost-program-options-dev libboost-thread-dev libboost-filesystem-dev libboost-date-time-dev

[Building & installing]
* js와 mongodb-src-r1.x.x 가 동일한 directory에 위치하도록(mongo build시 ../js 를 참조함)

# scons all
# scons --prefix=/user/service/mongo install

* Enjoy huMONGOus document database

[Run mongo as an auto-start daemon]

* Make data & log directory for mongo
# mkdir /user/service/mongo/data
# mkdir /user/service/mongo/log

vi mongo
-----------------------------------------------------------------------------
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          mongoDB
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop the mongo database server daemon
# Description:       Controls the main mongo database server daemon "mongod"
### END INIT INFO
#
# Copy this file to /etc/init.d & run commands below
#  1. Make symbolic link to /etc/rc[0-6].d/S??mongo
#  2. ln -s /etc/init.d/mongo /etc/rc[2345].d/S30mongo ==> start on boot(as to run level 2, 3, 4, 5
#  3. ln -s /etc/init.d/mongo /etc/rc[012].d/K30mongo ==> start on boot(as to run level 2, 3, 4, 5
#
export MONGO_HOME=/user/service/mongo
# Test if the file is executable, exits if not
test -x $MONGO_HOME/bin/mongod || exit 0
#
# main()
#
case "${1:-''}" in
  'start')
        # Start daemon
        $MONGO_HOME/bin/mongod --auth --port 28017 --dbpath $MONGO_HOME/data/ --fork --logpath $MONGO_HOME/log/mongodb.log
        ;;

  'stop')
        pid=`ps -o pid,command ax | grep mongod | awk '!/awk/ && !/grep/ {print $1}'`
        if [ "${pid}" != "" ]; then
            echo "About to kill mongod ...";
            echo "Pid: $pid";
            sudo kill -2 ${pid};
        fi
        ;;

  'restart'|'reload'|'force-reload')
        pid=`ps -o pid,command ax | grep mongod | awk '!/awk/ && !/grep/ {print $1}'`
        if [ "${pid}" != "" ]; then
            echo "About to kill '$1'...";
            echo $pid;
            sudo kill -2 ${pid};
        fi
        sleep 5
        $MONGO_HOME/bin/mongod --auth --port 28017 --dbpath $MONGO_HOME/data/ --fork --logpath $MONGO_HOME/log/mongodb.log
        ;;

  'status')
        $MONGO_HOME/bin/mongod --sysinfo
        ;;

  *)
        echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
        exit 1
        ;;
esac
-----------------------------------------------------------------------------

# chmod +x mongo
# cp mongo /etc/init.d
# chkconfig --add mongo
# chkconfig mongo ON

* Start by "/etc/init.d/mongo start" & have fun.


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


MySQL InnoDB 사용자를 위한 모니터링 툴( http://code.google.com/p/innotop/ , http://code.google.com/p/innotop/wiki/Screenshots )

2010/11 에 새 버전이 나와서 update합니다.

* Run as superuser
# wget http://innotop.googlecode.com/files/innotop-1.7.2.tar.gz
# wget http://innotop.googlecode.com/files/innotop-1.8.0.tar.gz
# zypper install perl-DBD-mysql
[참고] # yum install perl-TermReadKey (Fedora의 경우, 빠져 있기 쉬운 패키지)
# tar xvzf innotop-1.8.0.tar.gz
# cd innotop-1.8.0
# perl Makefile.PL
# make install

* Run and enjoy
# innotop -uroot -prootpass --socket /tmp/mysql.sock (socket option 필요 없으면 제외)

* Thannks to aracine( http://code.google.com/u/aracine/ )


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


[Mysql NDB Cluster 설정] - 5.1.44-ndb-7.1.4b

1. 소스 다운로드
http://dev.mysql.com/get/Downloads/MySQL-Cluster-7.1/mysql-cluster-gpl-7.1.4b.tar.gz/from/http://mirror.khlug.org/mysql/

2. 압축 해제, 설치
(필수 패키지: curses*, termcap, gcc-c++)
# ./configure --prefix=/user/service/mysql --with-mysqld-user=mysql --sysconfdir=/user/service/mysql/conf --with-unix-socket-path=/tmp/mysqld/mysql.sock --with-charset=utf8 --with-extra-charsets=all --with-plugins=innobase,myisam,partition,heap,ndbcluster
# make && make install

5. cnf 복사, 설정
# cp /ForMysqlBaseDir/mysql/share/mysql/my-huge.cnf /ForMysqlBaseDir/mysql/conf/my.cnf
* cnf 편집, 디렉토리 설정
  또는 미리 준비한 my.cnf 복사(cp /home/myaccound/mysql554/my.cnf /ForMysqlBaseDir/mysql/conf)

* Sample 설정
------------------------------------------------------
[mysqld]
init_connect=SET collation_connection = utf8_general_ci
init_connect=SET NAMES utf8
character-set-server=utf8
collation-server=utf8_general_ci
# Storage engine
default-storage-engine = innodb
# no difference between upper and lowercases
lower_case_table_names = 1
user            = mysql
pid-file        = /tmp/mysqld/mysql.pid
socket          = /tmp/mysqld/mysql.sock
port            = 3306
basedir         = /user/service/mysql
datadir         = /user/service/mysql/data
tmpdir          = /tmp
------------------------------------------------------

6. 초기데이터베이스 생성
# cd /ForMysqlBaseDir/bin
# ./mysql_install_db --user=mysql

7. Directory 생성, 권한 설정
# mkdir -p /ForMysqlBaseDir/mysql/conf
# chown -R root.mysql /ForMysqlBaseDir/mysql
# chown -R mysql.mysql /ForMysqlBaseDir/mysql/data

8. 테스트 실행
> cd /ForMysqlBaseDir/mysql/bin
> ./mysqld_safe --user=mysql &
> ./mysqladmin shutdown

9. Daemon 등록 실행
> cp /ForMysqlBaseDir/mysql/share/mysql/mysql.server /etc/init.d/mysqld
> chkconfig --add mysqld
> chkconfig | grep mysql
> chkconfig mysqld on
> /etc/init.d/mysqld start

10. Root 암호 등록, Daemon  종료
> mysqladmin -u root password 'xxxx'
> /etc/init.d/mysqld stop

* 여기까지 기본 설치(모든 노드)
* 총 4대의 서버중 2대(10.10.0.7, 10.10.0.8)을 MGM+SQL node 로, 2대(10.10.0.9, 10.10.0.10)을 NDB node 로
   설정한다고 가정

11. MGM, Mysql node
mkdir /user/service/mysql-cluster

* Cluster configuration(vi cluster.ini)
[ndbd default]
NoOfReplicas= 2
DataMemory= 512M
IndexMemory= 128M
DataDir= /user/service/mysql-cluster
TimeBetweenWatchDogCheck= 30000
MaxNoOfConcurrentOperations= 10000
MaxNoOfOrderedIndexes = 10000 
MaxNoOfUniqueHashIndexes = 15000 
MaxNoOfTables= 250
[ndb_mgmd default]
DataDir= /user/service/mysql-cluster
[ndb_mgmd]
Id=1
HostName= 10.10.0.7
[ndb_mgmd]
Id=2
HostName= 10.10.0.8
[ndbd]
Id= 3
HostName= 10.10.0.9
[ndbd]
Id= 4
HostName= 10.10.0.10
[mysqld]
Id= 5
HostName= 10.10.0.7
[mysqld]
Id= 6
HostName= 10.10.0.8
[mysqld]
Id= 7
[mysqld]
Id= 8
[tcp default]
PortNumber= 63132

* MySQL configuration
vi /user/service/mysql/my.cnf
[mysqld]
ndbcluster
ndb-connectstring=10.10.0.7,10.10.0.8
[mysql_cluster]
ndb-connectstring=10.10.0.7,10.10.0.8

* Daemon 등록(ndb_mgmd)
echo '/user/service/mysql/libexec/ndb_mgmd -f /user/service/mysql-cluster/cluster.ini' > /etc/init.d/ndb_mgmd
chmod 755 /etc/init.d/ndb_mgmd

12. NDB node

* mkdir /user/service/mysql-cluster

* MySQL configuration
vi /user/service/mysql/my.cnf
[mysqld]
ndbcluster
ndb-connectstring=10.10.0.7,10.10.0.8
[mysql_cluster]
ndb-connectstring=10.10.0.7,10.10.0.8

* Daemon 등록(ndbd)
echo '/user/service/mysql/libexec/ndbd' > /etc/init.d/ndbd
chmod +x /etc/init.d/ndbd
chkconfig --add ndbd
chkconfig ndbd on

13. Service start

<MGM node>
/etc/init.d/ndb_mgmd

<NDB node>
/user/service/mysql/libexec/ndbd --initial => 처음에 한번, 설정 변경시 적용
/etc/init.d/mysqld start

* Remote connect Grant
# mysql -uroot -prootpass
> use mysql;
> grant all privileges on *.* to 'root'@'%' identified by 'rootpass' with grant option;
> flush privileges;

14. Cluster 적용 상태 확인
# ndb_mgm


[MySQL Replication 시 작업] - 앞서 빌드 했던 5.5.4-m3 사용

* Master측
vi my.cnf
[mysqld]
server-id=1
log-bin

/user/service/mysql/bin/mysql_install_db --user=mysql
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO root@"%" IDENTIFIED by 'qrwe1423';
flush privileges;
show master status;

/etc/init.d/mysqld restart

* Slave측
vi my.cnf
log-bin
server-id=2
log-slave-updates
log-warning
max_allow_packet=32M -- sqldump backup/restore시 중요

CHANGE MASTER TO MASTER_HOST='10.10.10.11', MASTER_USER='root', MASTER_PASSWORD='qrwe1423';
* Restart mysql !!!
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
slave start;
show slave status;

* Error 발생시(ERROR 1418 (HY000))

show global variables like 'log_bin_trust_function_creators';
set global log_bin_trust_function_creators = 1;
mysqld 실행시 옵션 추가:  --log-bin-trust-function-creators=1

* show slave status에서 Duplicate PRIMARY ...mysql.tmp_db... blahblah Erro 발생시
master에서 reset master, slave에서 slave stop; reset slave; change master...; DB restart, slave start...

* 동기화 오류로 sync가 동작하기 않을 때의 임시 조치
(1) 1차 조치
<Slave> slave stop ;
<Slave> set global sql_slave_skip_counter=1;
<Slave> slave start ;

(2) 1차 조치로 해결되지 않으면
<Slave> /etc/init.d/mysqld stop
<Slave> ./mysqld_safe --skip-slave
<Slave> MYSQL> stop slave;
<Master> MYSQL> reset master; -- Qery log 파일 초기화
<Slave> MYSQL> reset slave;
<Slave> MYSQL> CHANGE MASTER TO MASTER_HOST='10.10.0.9', MASTER_USER='root', MASTER_PASSWORD='qrwe1423';
<Slave> MYSQL> slave start;
<Slave> MYSQL> start slave;


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


1. Source 다운로드, 압축해제
다운로드 http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.4-m3.tar.gz/from/http://mirror.khlug.org/mysql/
# tar xvzf mysql-5.5.4-m3.tar.gz

2. mysql 사용자 추가
# groupadd mysql
# useradd -M -g mysql -s /bin/false mysql

3. Configure Makefile
* ForMysqlBaseDir : /usr/local/ or /dev/local/service/, etc...
# rm -rf /ForMysqlBaseDir

# ./configure --prefix=/ForMysqlBaseDir/mysql --with-mysqld-user=mysql --sysconfdir=/ForMysqlBaseDir/mysql/conf --with-unix-socket-path=/tmp/mysqld/mysql.sock --with-charset=utf8 --with-extra-charsets=all --with-plugins=innobase,myisam,semisync,partition

* Clustering을 위해서는 plugin option에 ndbcluster 추가
  Clustering 을 위해서는 cluster버전 소스를 따로 받을 것

4. Build & Install ( libtool 이 필요할지도... zypper install libtool)
# make && make install

5. cnf 복사, 설정
# cp /ForMysqlBaseDir/mysql/share/mysql/my-huge.cnf /ForMysqlBaseDir/mysql/conf/my.cnf
* cnf 편집, 디렉토리 설정
  또는 미리 준비한 my.cnf 복사(cp /home/myaccound/mysql554/my.cnf /ForMysqlBaseDir/mysql/conf)

* Sample 설정
------------------------------------------------------
[mysqld]
init_connect=SET collation_connection = utf8_general_ci
init_connect=SET NAMES utf8
character-set-server=utf8
collation-server=utf8_general_ci
# Storage engine
default-storage-engine = innodb
# no difference between upper and lowercases
lower_case_table_names = 1
user            = mysql
pid-file        = /tmp/mysqld/mysql.pid
socket          = /tmp/mysqld/mysql.sock
port            = 3306
basedir         = /user/service/mysql
datadir         = /user/service/mysql/data
tmpdir          = /tmp
------------------------------------------------------

6. 초기데이터베이스 생성
# cd /ForMysqlBaseDir/bin
# ./mysql_install_db --user=mysql

7. Directory 생성, 권한 설정
# mkdir -p /ForMysqlBaseDir/mysql/conf
# chown -R root.mysql /ForMysqlBaseDir/mysql
# chown -R mysql.mysql /ForMysqlBaseDir/mysql/data

8. 테스트 실행
> cd /ForMysqlBaseDir/mysql/bin
> ./mysqld_safe --user=mysql &
> ./mysqladmin shutdown

9. Daemon 등록 실행
> cp /ForMysqlBaseDir/mysql/share/mysql/mysql.server /etc/init.d/mysqld
> chkconfig --add mysqld
> chkconfig | grep mysql
> chkconfig mysqld on
> /etc/init.d/mysqld start

10. Root 암호 등록

> mysqladmin -u root password 'xxxx'


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


SET @mac := '00afafafafaf'; -- ==> '00afafafafb0' 로 주소 값을 1증가 시키려고 한다
CONV(@mac, 16, 10) + 1; -- 12자리 mac address string을 BigInt 정수로 변환하여 +1
HEX(정수); -- 정수값을 hexadecimal string으로 변환
LPAD(string, digits, '0'); digits자리수 만큼 왼쪽에 '0'을 채운다
-- 결과
SELECT LPAD(HEX(CONV(@mac, 16, 10)+1), 12, '0');

<참고> SELECT INET_ATON( '168.126.63.1') = 2826845953 -- BigInt
           SELECT INET_NTOA( 2826845953 ) = '168.126.63.1'


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


시스템 설정이 많으므로 root 계정에서 작업(/root/src)
dev.mysql.com 에서 소스 다운로드(mysql-5.1.45.tar.gz)

압축해제, make 준비
# tar -xvzf mysql-5.1.45.tar.gz
# ./configure --prefix=/user/service/mysql \ --> 주요파일 설치 위치(bin, libexec, lib, ...Default는 /usr/local/mysql)
> --localstatedir=/user/service/mysql/data \ --> 데이터, 로그 저장 위치
> --sysconfdir=/user/service/mysql \ --> 기본 설정파일 my.cnf 등 저장 위치
> --with-mysqld-user=mysql \ --> Daemon 실행 계정
> --with-charset=utf8 --with-extra-charsets=all \ --> 기본 charset 지정
> --with-tcp-port=9998 \ --> 접속용 TCP port(기본 3306)
> --with-plugins=innobase \ --> innodb용 plugin
> --enable-shared \
> --enable-assembler \

빌드 및 설치
# make && make install
Daemon 실행 계정 추가
# useradd -M mysql

data저장소 초기데이터 생성
# cd /user/service/mysql/bin
# ./mysql_install_db --user=mysql ==> /user/service/mysql/data 에 mysql, test 디렉토리 생성됨
mysql 계정권한 설정
# cd /user/service/mysql
# chown -R mysql.mysql ./data/

mysql loading시 참조될 설정파일 준비
# cd /user/service/mysql/share/mysql

# cp my-huge.cnf /user/service/mysql/my.cnf ==> configuration type 선택(small, medium, ..., huge)
# vi my.cnf ==> charset 등 지정

# vi ~/.bash_profile
PATH=$PATH:/user/service/mysql/bin
# vi /etc/skel/.bash_profile
PATH=$PATH:/user/service/mysql/bin
# source ~/.bash_profile

# cp /user/service/mysql/share/mysql/mysql.server /etc/init.d/mysqld
# chkconfig --add mysqld
# chkconfig --list | grep mysqld ==> Run level별 start/stop 설정 확인(0:off  1:off  2:on   3:on   4:on   5:on   6:off)

# /etc/init.d/mysqld start ==> MySQL Daemon 실행
# mysqladmin -u root password **** ==> root password 지정



저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


mongo db는 몽고 라는 나라와 전혀 상관이 없다. Humongous 하는 단어에서 만들어진 것.

설치후 아무런 제약 없이 ./mongo 만 치면 db에 접속된다. 개발환경이라면 문제 없지만
개념 없이 쓰다가 큰 일 ㅡ_-? 이 날지도...

우선 mongod를 기동시킬 때 --auth 옵션을 추가해 두자.
다음 글에서 mongod 를 시스템 스타트시에 기동되도록 설정하는 방법을 정리할 것이다. ubuntu, centos, suse 등
거의 모든 linux 머신에서 특정 App을 기동시키는 일반적인 방법이 되겠다.

각설하고,
mongo db는 system 영역 내에 admin 이라는 DB 관리를 위한 스키마 영역(database)를 가진다.
* 메서드 Name에 대소문자 구분 주의
# ./mongo
# use admin
# db.addUser( "adminname", "adminpassword" )
이제 관리자로 접근하려면
# db.auth( "adminname", "adminpassword" )
라고 입력해야만 DB를 use 할 수 있다.

* 이제 DB를 관리하기 위해서는 반드시 아래와 같이 해야만 정상적으로 접속되고 user 생성 등을 할 수 있다.
# mongo -uroot -padminpassword --port 12345 admin

# db.system.useres.find() => users 테이블 내용을 select

일반적인 작업 영역을 위해 별도의 DB를 만들고 권한을 설정하려면
# use newdb => mongo는 newdb가 없으면 자동으로 생성한다. table(collection이라고도 한다)이나
                        key(attribute, column)에 대해서도 마찬가지. 즉, DDL이 따로 없다. C/C++의 structure
                        구조와 같은 composite한 다중 컬럼도 생성이 가능하므로 자칫하면 table 구조가 엉망이 될
                        수도 있다.
# db.addUser( "newdbuser", "newpassword" )
이제 newdb 데이터베이스로 접근하려면
# db.auth( "newdbuser", "newpassword" ) 로 접근할 수 있다.

* 데이터베이스마다 owner 개념으로 접근 계정을 각각 할당하는 방식에 유의 !!!

이제 데이터베이스에 접속하려면  아래 방법들 처럼 접속이 가능하다
# mongo -unewdbuser -pnewpassword newdb --port 27017 --host 100.100.100.20
# mongo -uroot -padminpassword --port 29007 newdb
저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


먼저 상태를 확인해 본다.
> mysqladmin -u root -p status

root로 mysql db로 접속
> mysql -u root -p (또는 mysql -uroot -ppassword) 

만약 root 암호를 변경하려면
mysql> update mysql.user set password = password('root-password') where user = 'root';
를 수행한다

사용자를 추가하려면
> mysql -uroot -ppassword mysql

INSERT INTO mysql.user (Host, User, Password) VALUES ('%', 'username', password('password'));
-- %를 쓰지 않고 localhost를 쓸 경우 remote 접속이 불가능하게 되므로 주의
FLUSH privileges;

CREATE DATABASE TestDB;

* 아래는 Grant 옵션을 example로 정리한 것이다
GRANT ALL privileges ON TestDB.* TO 'username'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH privileges;
-- username 사용자에게 TestDB에만 모든 권한을 준다. localhost 의 접속만 허용한다

GRANT SELECT ON TestDB.* TO 'username'@'%.domain.com' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH privileges;
-- username 사용자에게 TestDB에 대해 SELECT 권한을 준다. domain.com 도메인 내에서의 모든 호스트로부터의 접속을 허용한다

GRANT ALL privileges ON TestDB.* TO 'username'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH privileges;
-- username 사용자에게 TestDB에만 모든 권한을 준다. 모든 호스트로부터의 접속을 허용한다

GRANT ALL privileges ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH privileges;
-- root 사용자에게 모든 DB object에 모든 권한을 준다. 모든 호스트로부어의 접속을 허용한다


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


APM에서 UTF-8을 구현하려면 아래 여러 부분을 수정해야 한다.

1. apache 환경파일 편집 (httpd.conf)
2. php 환경파일 편집 (php.ini)
3. mysql 환경파일 편집 (my.cnf)
4. apache, mysql 서비스 재시작
5. mysql에서 캐릭터셋 확인 및 디비생성
6. php 소스코드에 mysql_query("set names utf8;"); 함수 추가
7. php 소스에 한글문자열이 있으면 파일저장할때 UTF-8 파일형식으로 저장
8. 웹브라우즈의 보기-인코딩-UTF-8로 선택

1. /etc/httpd/conf/httpd.conf 에서 캐릭터셋 수정
/*------------
AddDefaultCharset UTF-8

2. /etc/php.ini 에서 캐릭터셋 수정
/*------------
;default_charset = "iso-8859-1"
default_charset = "utf-8"

3. /etc/my.cnf(또는 /etc/mysql/my.cnf) 에서 캐릭터셋 수정
/*------------
[client]
#password = your_password
default-character-set=utf8

[mysqld]
init_connect=SET collation_connection = utf8_general_ci
init_connect=SET NAMES utf8
default-character-set=utf8
character-set-server=utf8
collation-server=utf8_general_ci

[mysql]
default-character-set=utf8

4. 환경변수를 모두 수정후 apache 및 mysql 서비스 재시작
/*------------

5. mysql에서 캐릭터셋 확인
/*------------
# mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 247 to server version: 4.1.10a

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use test
Database changed
mysql> show variables like 'c%';
+---------+-----------+
| Variable_name | Value |
+---------+-----------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
| collation_connection | utf8_general_ci |
| collation_database | utf8_general_ci |
| collation_server | utf8_general_ci |
| concurrent_insert | ON |
| connect_timeout | 5 |
+---------+-----------+
12 rows in set (0.00 sec)

* MySql에서 데이터베이스 생성
mysql>CREATE DATABASE 디비명 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

1. MySQL 서버의 타임존 설정방법에 관하여


일반적으로 MySQL 설치시 timezone에 대해서 별도 옵션을 지정하지 않으면
태평양표준시인 PST(Pacific Standard Time) 으로 설정된다(PST/PDT 등에 대해서는 여기 참조).

* 참고로 Ubuntu에서 시스템의 표준시를 KST(대한민국 표준시)로 바꾸려면
# ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

(MySQL 관련한 세부 정보 및 사용법은 http://www.mysqlkorea.com 참조)

DB 서버에 클라이언트로 접속해서 타임존 설정을 확인해 보자


mysql> select @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| PST                |
+--------------------+
1 row in set (0.00 sec)

이 값은 설정 후에는 변경되지 않으며, 따라서 DB엔진 입장에서는 시스템의 설정 값을 가져다 쓰는 것이다.


실제로 MySQL 내애서 사용하기 위한 타임존 값은 서버가 기동중일 때 사용하는 시스템 변수인
time_zone 이라는 값으로, 이 값은


(1)서버 기동시에 --default-time-zone='timezone' 으로 지정하거나
(2) MySQL root 권한을 이용해서


mysql> SET GLOBAL time_zone='timezone;
이라고 설정해 주거나, 또는


(3) 클라이언트 접속시에 이미 설정된 time_zone 변수의 값을 명시적으로 자체적인(세션에 국한된)  time_zone 값으로


mysql> SET time_zone='timezone;


와 같이 세션변수 갑으로 설정하여 사용할 수도 있다.

(2), (3) 의 결과를 아래에서 확인한다.


mysql> select @@global.time_zone, @@session.time_zone;
+--------------------+---------------------+
| @@global.time_zone | @@session.time_zone |
+--------------------+---------------------+
| SYSTEM             | Asia/Seoul          |
+--------------------+---------------------+
1 row in set (0.00 sec)


*** 최초 기본 설정 상태의 time_zone 변수의 값을 확인한 결과
mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| SYSTEM      |
+-------------+
1 row in set (0.00 sec)

*** 이 상태에서 Quiery로 시간 값을 조회해 보면,
mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2009-12-29 04:51:21 |
+---------------------+
1 row in set (0.00 sec)
===> 실제 시간은 21:51:21 이므로 한국 현재 시간 -17 시간이 된다

*** 이제 타임존을 서울로 설정하고 시간을 조회해보면
mysql> set time_zone = 'Asia/Seoul';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| Asia/Seoul  |
+-------------+
1 row in set (0.00 sec)

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2009-12-29 21:57:45 |
+---------------------+
1 row in set (0.00 sec)


'timezone' 의 값은 아래의 여러 가지 포맷으로 줄 수 있으며, 대소문자 구분이 없다(보다 자세한 사항은 MySQLkorea.com의 매뉴얼을 참고한다)
  - 'SYSTEM' 은 타임존이 시스템의 타임존과 동일하도록 설정할 때 쓴다
  - '+10:00' 또는 '-6:00' 과 같이 GMT/UTC기준 offset을 가리키는 문자열로 쓸 수도 있다
  - 'US/Eastern', 'Asia/Seoul' 과 같은 named timezone 형태의 값을 줄 수도 있다.


2. Named timezone 설정 및 사용 방법


이번 내용에서는 위의 named timezone 형태의 값을 시스템 설정파일에서 불러내어 MySQL 시스템오브젝트(테이블)에 등록하고 사용하는 방법을 정리한다.

MySQL을 설치하면 'mysql' 이라는 데이터베이스 내에 time_zone, time_zone_name, time_zone_transition,
time_zone_transition_type, time_zone_leap_second 의 시스템 테이블이 생성되지만 실제로 값이 들어 있지는 않다.

사용하려고 하는 MySQL 데이터베이스가 Global한 서비스를 하게 될 경우의 시간 값이 중요해지는 상황의 IT환경이라면 시스템에 내장되어 있는 타임존 설정값들을 읽어서 위의 테이블들에 등록해 주어야 한다.

MySQL이 설치되는 OS가 Linux, Solaris 계열, BSD계열(물론 Mac OS X도 여기에 해당)이라면
방법은 아주 간단하다. 타임존에 해당하는 설정데이터들은 주로 /usr/share/zoneinfo 디렉토리 아래에 존재하는데 MySQL에서 제공하는 utility query인 mysql_tzinfo_to_sql 을 이용해서 간단히 등록할 수 있다.


root 계정 명령라인에서 아래와 같이 실행하면 된다.


root@ubuntu:/home/somewhere# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -prootpassword mysql

이제 데이터베이스에 접속하여 텅 비어 있던 타임존 관련 테이블들에 데이터가 등록 되었는지 확인해 보자.

mysql> select count(*) from mysql.time_zone;
+----------+
| count(*) |
+----------+
|     1724 |
+----------+
1 row in set (0.00 sec)

mysql> select b.name, a.time_zone_id  from mysql.time_zone a, mysql.time_zone_name b where a.time_zone_id = b.time_zone_id and b.name like '%Seoul';
+------------------+--------------+
| name             | time_zone_id |
+------------------+--------------+
| Asia/Seoul       |          287 |
| posix/Asia/Seoul |          862 |
| right/Asia/Seoul |         1437 |
+------------------+--------------+
3 rows in set (0.00 sec)

만약 MySQL이 설치되는 OS가 Windows 계열 또는 HP/UX 등이라면 MySQL 사에서 제공하는
MyISAM 파일들을 http://dev.mysql.com/downloads/timezones.html 에서 다운 받은 다음
MySQL 데이터베이스를 중단시키고 'mysql' 서브디렉토리에 직접 복사해 넣어야 한다.

이제 여기서 설정된 named timezone 값들을 1번에서와 같이 'timezone' 값으로 설정하여
마음대로 사용하면 된다.


- Barracuda -


저작자 표시 비영리 변경 금지
신고
블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들