반응형
반응형

데이터를 풀백업을 11시에 했을 경우 11 30분에 장애가 나면 Oracle이나 MSSQL 같은 경우

redo log나 트랜잭션 로그를 사용하여 데이터를 복원합니다.

 

그리고 mysql에서도 undo/redo log를 사용하여 시작할 때 데이터를 복구가 가능합니다.

(그런 장애가 난 적이 없고 해당하는 부분은 저도 조금 더 공부를 해야봐 알겠네요.

 일단 여러 참고자료에서는 가능하다고 적혀 있어서 적어 놓았습니다.)

 

그런데 11시에 풀백업이 되고 11 30분에 장애가 나거나 실수로 쿼리를 잘못 날렸을 경우 

실수로 실행한 쿼리문 이전으로 복구하는 방법을 알려 드리고자 합니다.

 

 

빈로그 복원에 대한 시나리오

1. 11시에 데이터가 풀백업되었다.

2. 테이블 생성 후 프로시저로 TESTDB에 해당 테이블에 10000개의 데이터 입력

3. 11시 반에 데이터에 문제가 발생한다.

   (지금은 11시 반에 TESTDB drop database로 날렸다는 가정)

4. 11시 데이터를 먼저 복원 후에 binlog를 이용하여 11 30분까지의 데이터를 복원한다.

 

 

1. TESTDB에 테스트 테이블 생성

create table seq_test(a int, b int);

 

2. 10000개의 데이터를 입력 할 procedure 생성

DELIMITER $$

USE `TESTDB`$$

DROP PROCEDURE IF EXISTS `pGet_TESTDB_Insert_data`$$

 

CREATE DEFINER=`username`@`localhost` PROCEDURE `pGet_TESTDB_Insert_data`()

BEGIN

set @i = 0;

while (@i < 10000) DO

           set @insert_member = concat("insert into seq_test values(",@i,", ",@i,")");

           SELECT @insert_member;

  PREPARE stmt FROM @insert_member;

  EXECUTE stmt;

  set @i = @i + 1;

end while;

end$$

 

DELIMITER ;

 

3. procedure 실행

call pGet_TESTDB_Insert_data();

 

4. database 날림

drop database TESTDB;

 

5. bin로그를 전부 취합

/usr/local/mysql5/bin/mysqlbinlog -u username -p /usr/local/mysql5/data/mysql-bin.000001 >> /test_db/mysql-bin.sql

/usr/local/mysql5/bin/mysqlbinlog -u username -p /usr/local/mysql5/data/mysql-bin.000002 >> /test_db/mysql-bin.sql

/usr/local/mysql5/bin/mysqlbinlog -u username -p /usr/local/mysql5/data/mysql-bin.000003 >> /test_db/mysql-bin.sql

/usr/local/mysql5/bin/mysqlbinlog -u username -p /usr/local/mysql5/data/mysql-bin.000004 >> /test_db/mysql-bin.sql

/usr/local/mysql5/bin/mysqlbinlog -u username -p /usr/local/mysql5/data/mysql-bin.000005 >> /test_db/mysql-bin.sql

 

6. 백업한 11시 데이터를 복원

create database TESTDB;

/usr/local/mysql5/bin/mysql -u username -p TESTDB < TESTDB_11hour.sql

 

6. 11 00분부터 11 30분까지의 데이터를 남기고 mysql-bin.sql 나머지 데이터를 전부 삭제

/*!*/; <- 이 문구 나오기 전까지 자름

#End of log file 이후는 자름

 

7. binlog 데이터 복원

/usr/local/mysq5/bin/mysql -u username -p TESTDB < mysql-bin.sql

 

저는 이렇게 해서 해당 DATA를 복구하였습니다.

해당하는 기술은 엄청나게 유용하게 사용됩니다.

나중에 장애나 쿼리를 잘못 실행했을 때 사용해 보실 수 있으실 겁니다.



http://blog.cafe24.com/1659


반응형
반응형

MySQL 은 테이블 생성시 또는 테이블 컬럼의 제약 사항에 따라

ERROR 를 내어야 하는 statement (syntax error는 아니며 제약 사항에 위배되는 statement  ) 에 대해서 sql_mode 가 어떻게 설정되느냐에 따라서 그냥 warning 만 내고

Statement 를 완료 시킵니다.

 

예를 들어 default 가 설정되지 않은 not null 컬럼에 아무 값도 넣지 않으면… 빈 문자열을 넣고 ( mysql 에서 빈문자열 ‘’ 이 null 이 아니네요… 오라클에선 그런 것  같은데 기억이 가물 )

Warning 만 하고 statement를 완료 시킵니다.                                                                                                                           

 

컬럼이 int 형이면 0 을 넣어버리는 등  default 값을 임의대로 넣어버리고 statement를 완료 시킵니다.

 

대부분의 개발이 이런 특성을 고려해서 개발 되는 것이 아니기 때문에 statement에 실수가 발생해도 그대로 진행되어서

나중에 의도 하지 않은 결과들을 볼 수 있는 위험이 있습니다.

 

관련 sql_mode 옵션 : STRICT_TRANS_TABLES

 

또 한 가지 테이블 생성시 엔진명이 틀리거나 명시하지 않으면 그냥 default storage engine으로 설정해서 테이블 생성해 버립니다.

 

Warning 제대로 안 보다간 Error도 안나니 전혀 의도 하지 않은 엔진으로 테이블 생성하고 나중에 문제가 될 수 있습니다.

 

 

그 외에도 여러 가지가 있는데 위 두 가지가 중요한 것 같습니다.

 

그래서 5.6 부터는 default my.cnf my.ini 파일에 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 로 기본 설정하고 있습니다.  

 

 

 

그리고 MySQL 에서 warning 확인은 절대적이네요..

Warning 발생시 꼭 확인 필요 ^^;;

 

https://blogs.oracle.com/supportingmysql/entry/mysql_server_5_6_default

 

http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.html

 

If a value could not be inserted as given into a transactional table, abort the statement. For a nontransactional table, abort the statement if the value occurs in a single-row statement or the first row of a multiple-row statement. More detail is given later in this section.

 

Control automatic substitution of the default storage engine when a statement such as CREATE TABLE or ALTER TABLEspecifies a storage engine that is disabled or not compiled in.

Because storage engines can be pluggable at runtime, unavailable engines are treated the same way:

With NO_ENGINE_SUBSTITUTION disabled, for CREATE TABLE the default engine is used and a warning occurs if the desired engine is unavailable. For ALTER TABLE, a warning occurs and the table is not altered.

With NO_ENGINE_SUBSTITUTION enabled, an error occurs and the table is not created or altered if the desired engine is unavailable.

테스트 )

1. Insert 될 수 없는 statement를 임의 처리 하는 CASE

 

create table test_strict(

id bigint(20) not null auto_increment,

a varchar(50) not null,

b varchar(50) not null,

primary key (id)

)engine=innodb default charset=utf8;

 

 

insert into test_strict(id,a)values(1,'a');

 

 

insert into test_strict(id,a)values(2,'c');

 

 

mysql> select @@sql_mode;

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

| @@sql_mode |

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

|            |

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

1 row in set (0.00 sec)

 

mysql> create table test_strict(

    -> id bigint(20) not null auto_increment,

    -> a varchar(50) not null,

    -> b varchar(50) not null,

    -> primary key (id)

    -> )engine=innodb default charset=utf8;

Query OK, 0 rows affected (0.05 sec)

 

mysql> insert into test_strict(id,a)values(1,'a');   ß b not null 인데도 error 없이 statement 완료 . Warning 

Query OK, 1 row affected, 1 warning (0.01 sec)

 

mysql> select * from test_strict;

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

| id | a | b |

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

|  1 | a |   |

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

1 row in set (0.00 sec)

 

mysql> select b from test_strict;

+---+

| b |

+---+

|   |

+---+

1 row in set (0.00 sec)

 

mysql> set @@sql_mode = 'strict_trans_tables';

Query OK, 0 rows affected (0.00 sec)

 

mysql>

mysql>

mysql> insert into test_strict(id,a)values(2,'c');

ERROR 1364 (HY000): Field 'b' doesn't have a default value  ß sql_mode = strict_trans_tables 설정시 error return

 

 

 

create table test_strict(

id bigint(20) not null auto_increment,

a varchar(50) not null,

b varchar(50) not null,

c int not null,

primary key (id)

)engine=innodb default charset=utf8;

 

mysql> set @@sql_mode='';

Query OK, 0 rows affected (0.00 sec)

 

 

 

 

mysql> drop table test_strict;

Query OK, 0 rows affected (0.00 sec)

 

mysql> create table test_strict(

    -> id bigint(20) not null auto_increment,

    -> a varchar(50) not null,

    -> b varchar(50) not null,

    -> c int not null,

    -> primary key (id)

    -> )engine=innodb default charset=utf8;

Query OK, 0 rows affected (0.03 sec)

 

mysql> insert into test_strict(id,a)values(1,'a');

Query OK, 1 row affected, 2 warnings (0.00 sec)

 

mysql> select * from test_strict;

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

| id | a | b | c |

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

|  1 | a |   | 0 | ß--- int의 경우 0으로 설정

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

1 row in set (0.00 sec)

 

mysql> insert into test_strict(id,a)values(2,'c');

Query OK, 1 row affected, 2 warnings (0.01 sec)

 

mysql> show warnings\G

*************************** 1. row ***************************

  Level: Warning

   Code: 1364

Message: Field 'b' doesn't have a default value

*************************** 2. row ***************************

  Level: Warning

   Code: 1364

Message: Field 'c' doesn't have a default value

2 rows in set (0.00 sec)

 

 

 

2. Create table storage engine 지정이 잘못 되었을시 default engine으로 대체

 

create table test_engine(f1 int) engine = kpt;

 

 

mysql> create table test_engine(f1 int) engine = kpt;

Query OK, 0 rows affected, 2 warnings (0.00 sec)

 

mysql> show warnings\G

*************************** 1. row ***************************

  Level: Warning

   Code: 1286

Message: Unknown storage engine 'kpt'

*************************** 2. row ***************************

  Level: Warning

   Code: 1266

Message: Using storage engine InnoDB for table 'test_engine'

2 rows in set (0.00 sec)

 

mysql> show create table test_engine;

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

| Table       | Create Table                                                                                  |

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

| test_engine | CREATE TABLE `test_engine` (

  `f1` int(11) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

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

1 row in set (0.00 sec)

 

 

mysql> show global variables like '%default%';

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

| Variable_name          | Value  |

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

| default_storage_engine | InnoDB |

| default_week_format    | 0      |

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

2 rows in set (0.00 sec)

반응형
반응형

Ubuntu에 깔려있는 MySQL을 업그레이드했는데, 뭔가 잘못됐는지 다음과 같은 메시지와 함께 실행이 안되었다.

error: 'Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)'


데비안이나 우분투에서 MySQL을 관리하다보면 debian-sys-maint계정이 접근권한이 없어서 mysql데몬을 관리하는 것이 안되는 경우가 발생한다. 이것은 /etc/init.d/mysql스크립트를 start,stop,restart등등을 할때 /etc/mysql/debian.cnf의 debian-sys-maint게정과 암호를 사용하기 때문이다. 
그런데 debian.cnf파일의 password부분이 encryption이 된것으로 알았는데 그냥 clear-text라고 한다... 
따라서, debian-sys-maint계정의 암호를 잃어버렸을 경우에는 이 파일의 password부분에 임의의 랜덤 문자열로 암호를 넣어주고 아래와 같이 mysql에서 debian-sys-maint에 대한 암호를 변경한다.


mysql> update user set password = password('랜덤스트링') where user = 'debian-sys-maint' and host = 'localhost'; 
mysql> flush privileges;

[출처] 'Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)'|작성자 미친푸우

 

 

 

****************************************************************************************

다른 방법

 

error: 'Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)'
http://mirzmaster.wordpress.com/2009/01/16/mysql-access-denied-for-user-debian-sys-maintlocalhost/

So, what is this “debian-sys-maint” user? Well, this MySQL user is created for the Ubuntu to be able to start/stop the database and to carry out other maintenance operations.

Sounds well enough, but then why do I keep running into the “access denied” problem for this user? Well, the issue is that with each update to MySQL, the user’s password in the database is overwritten. Ubuntu seems to go to the file /etc/mysql/debian.cnf in order to find this user’s password, but obviously the password is out of sync after the update has been applied.

As a result of this behaviour, I’ll run into the “access denied”problem every so often. Thankfully, the solution to this issue is fairly simple.



cat /etc/mysql/debian.cnf
password = 값

mysql> GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '값';


댓글에 달린 내용---------

You do NOT need to grant all permissions, this is a bad habit to get into from a security standpoint.

All you need to grant is this (as root or whoever):

GRANT SHUTDOWN ON *.* TO ‘debian-sys-maint’@'localhost’;
GRANT SELECT ON `mysql`.`user` TO ‘debian-sys-maint’@'localhost’;

Because it needs to shutdown/startup, and does a test select from the users table as a sanity check to ensure the root user exists. This select is usually done by /usr/share/mysql/debian-start.inc.sh which is loaded by /etc/mysql/debian-start


반응형
반응형

안녕하세요.

오늘은 (제 스타일의) ERD 작성시 Table / Column Comment 를 추출하는 쿼리 공유드리고자 합니다.

 

저희가 지원하는 서비스의 경우, Life Time 이 너무 짧아 ERD 를 꾸준히 관리하지는 못하지만,

초기 서비스를 시작할 때 관련담당자들(DB, DEV, DW, 사업PM)의 이해도를 높이기 위해 ERD 를 그리곤 합니다.

 

경험상 대부분의 모델링 도구들이 '한글' 또는 '영문'명만 표시해주면서 실제 코딩시 활용도가 낮은데,

"영문컬럼명 [한글정의]" 형태로 ERD 를 그림으로써 다소나마 가시성을 높여 사용하고 있습니다.

(생각해보니 DA# 에서 이런 형태로 보여주는 기능이 있네요. Padding 이 안되어 이쁘진 않지만... ㅎㅎ)

 

■ ERD 예제

 

 

 

■ 추출쿼리

=====================================
쿼리 Type
=====================================

select concat(rpad(column_name, a.start_no, ' '),'[',trim(b.column_comment),']') as col_desc
     , b.table_schema, b.table_name, b.column_name, b.column_comment, a.start_no
  from (select table_schema, table_name, max(length(column_name))+2 as start_no
          from information_schema.columns
         where table_schema not in ('information_schema','common_schema','mysql','performance_schema','ps_helper')
         group by table_schema, table_name) a
      , information_schema.columns b
 where a.table_schema = b.table_schema
   and a.table_name   = b.table_name
 order by b.table_schema, b.table_catalog, b.table_schema, b.table_name, b.ordinal_position;


show full columns from information_schema.columns;

 

=====================================
프로시져 Type
=====================================

use test;

DROP PROCEDURE IF EXISTS usp_show_table_desc;

delimiter //

CREATE PROCEDURE usp_show_table_desc()
BEGIN

   DECLARE done           INT DEFAULT 0;

   DECLARE v_table_schema VARCHAR(50);
   DECLARE v_table_name   VARCHAR(50);
   DECLARE v_max_length   INT;

   DECLARE cur1 CURSOR
   FOR 
   select table_schema, table_name, max(length(column_name))+2 as max_length
     from information_schema.columns
    where table_schema not in ('information_schema','common_schema','mysql','performance_schema','ps_helper')
    group by table_schema, table_name
    order by table_schema, table_name;

   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

   OPEN cur1;

   read_loop:
   LOOP

      FETCH cur1 INTO v_table_schema, v_table_name, v_max_length;

      -- select v_table_schema, v_table_name, v_max_length;

      select "===============================================" as "___comments___"
       union
      select concat(table_name, ' [',trim(table_comment),']')  as "___comments___"
        from information_schema.tables
       where table_schema = v_table_schema
         and table_name   = v_table_name
       union all
      select "==============================================="
       union all
      select concat(rpad(column_name, v_max_length, ' '),'[',trim(column_comment),']') as col_desc
        from (
             select column_name, column_comment
               from information_schema.columns
              where table_schema = v_table_schema
                and table_name   = v_table_name
              order by ordinal_position
             ) x
       union all
      select "==============================================="
       union all
      select ""
       union all
      select "";

      IF done = 1 THEN
         LEAVE read_loop;
      END IF;

   END LOOP;

   CLOSE cur1;

END
//

delimiter ;

call usp_show_table_desc();

 

-- shell 에서 실행

mysql -u root -p --skip-column-names -e "use test; call usp_show_table_desc();" > tab_col_desc.txt


-- Output 확인

vi tab_col_desc.txt
-------------------------------------------------------------------
...
===============================================
user_stage [유저별 스테이지 정보]
===============================================
usr_id        [유저 고유번호]
stage_id      [스테이지 고유번호]
stage_level   [스테이지 현재등급]
wins          [(누적) 승수]
kills         [(누적) 킬수]
===============================================

...
-------------------------------------------------------------------

 


반응형
반응형



innodb tablespace structure.pptx




반응형
반응형

시스템을 구성하고 시스템의 IO 상황이 어떤지 확인할 필요가 있습니다. 특히, DBMS와 같이 IO에 의존하는 시스템은 반드시!!! 시스템의 IO 현황을 확인해야 합니다. IO 현황을 확인할 때 사용하는 iostat의 출력값을 해석하는 방법을 서술해 봅니다.

 

아래의 예와 초록색 표시한 부분을 따라서 읽어보면 됩니다그리고 일반적인 해결 방법도 제일 아래에 붙입니다.

%util은 현재 응용 프로그램이 얼마나 I/O에 연관된 것인가를 보여주는 지표입니다. 아래 식으로 계산합니다.

 

%util = ((Write operation 개수 + Read operation 개수) * 평균 처리 시간)  / 측정 interval

 

:
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await  svctm  %util
dm-0              0.00     0.00  611.40  414.23 20286.60  1656.93 42.79    17.50   17.33   0.96  98.57

  • Device: the block device whose performance counters are being reported
  • r/s and w/s: number of read and write requests issued per second to the device (in this case 611 and 414)
  • rsec/s and wsec/s  number of sectors read/written per second
  • rkB/s and wkB/s  number of kilobytes read/written per second
  • avgrq-sz  average number of sectors per request (for both reads and writes). ie (rsec + wsec) / (r + w)
  • avgqu-sz  average queue length in the monitoring interval (in this case 42.79)
  • await  average time that each IO Request took to complete. This includes the time that the request was waiting in the queue and the time that the request took to be serviced by the device
  • svctim  average time each IO request took to complete  during the monitoring interval
  • Note: await includes svctim. Infact await (average time taken for each IO Request to complete) = the average time that each request was in queue (lets call it queuetime) PLUS the average time each request took to process (svctim)
  • %util: This number depicts the percentage of time that the device spent in servicing requests. This can be calculated with the above values. In the above example the total number of reads and writes issued per second is 611 + 414 => 1025. Each request takes 0.96 ms to process. Therefore 1025 requests would take 1025 x 0.96 => 984 ms to process. So out of the 1 second that these requests were sent to the device in, 984 ms were taken to process the requests. This means the device utilization is 984/1000 * 100 => ~98.4%. As you can see in the above iostat output the %util does show ~ 98.5%

일반적으로 %util 80%를 넘으면 문제를 해결하는 방법은 아래와 같습니다.

    • increasing RAM so dependence on disk reduces
    • increasing RAID controller cache so disk dependence decreases
    • increasing number of disks so disk throughput increases (more spindles working parallely)
    • horizontal partitioning
    • [출처] iostat의 %util 계산하는 방법|작성자 정일동



http://blog.naver.com/idjung/150082332311

반응형

'연구개발 > MYSQL' 카테고리의 다른 글

Table / Column Comment 추출하는 쿼리  (0) 2014.12.16
InnoDB tablespace 구조  (0) 2014.12.16
파티션 삭제시 Exchange Partition 기능 활용  (0) 2014.12.11
SHOW PROCESSLIST  (0) 2014.12.11
MySQL 5.5 Semisynchronous Replication v1.0  (0) 2014.12.10
반응형

로그성 데이터를 파티션 테이블로 보관하는 경우가 많은데, 보관주기가 지난 파티션을 drop 하는 경우에 MySQL 에서는 전체 파티션에 테이블 락이 걸리는 문제가 있습니다.

다행히 파티션의 물리적인 파일과 내부 메타 데이터 갱신 정도만 발생하기에 테이블 락 유지 시간이 길지는 않지만, ext3 파일시스템을 사용하거나 파티션 당 데이터 사이즈가 크면 문제가 되는 경우가 있겠습니다.

 

다행히 MySQL 5.6 버전부터는 파티션 Exchange 기능이 지원되어서, 테이블 락으로 인한 영향을 최소화하면서 파티션 삭제를 할 수 있겠습니다. 


* 샘플 데이터

 : 하루에 3200만건(테이블스페이스 파일 사이즈 10GB) 정도 데이터가 저장되는 일자별 파티셔닝 테이블

mysql> show create table ptest\G

*************************** 1. row ***************************

       Table: ptest

Create Table: CREATE TABLE `ptest` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `regdt` date NOT NULL DEFAULT '0000-00-00',

  `pad` char(255) DEFAULT NULL,

  PRIMARY KEY (`id`,`regdt`)

) ENGINE=InnoDB AUTO_INCREMENT=167108865 DEFAULT CHARSET=utf8

/*!50100 PARTITION BY RANGE ( to_days (regdt) )

(PARTITION p20140420 VALUES LESS THAN (735709) ENGINE = InnoDB,

 PARTITION p20140421 VALUES LESS THAN (735710) ENGINE = InnoDB,

 PARTITION p20140422 VALUES LESS THAN (735711) ENGINE = InnoDB,

 PARTITION p20140423 VALUES LESS THAN (735712) ENGINE = InnoDB,

 PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */

1 row in set (0.00 sec)

 

mysql> select TABLE_NAME, PARTITION_NAME, TABLE_ROWS from information_schema.PARTITIONS where TABLE_NAME='ptest';      

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

| TABLE_NAME | PARTITION_NAME | TABLE_ROWS |

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

| ptest      | p20140420      |   32934515 |

| ptest      | p20140421      |   32939678 |

| ptest      | p20140422      |   32935000 |

| ptest      | p20140423      |   32935471 |

| ptest      | pMAXVALUE      |          0 |

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

5 rows in set (0.01 sec)


# 데이터 디렉토리에서 파일을 조회해보면... 

-rw-rw---- 1 seuis398 seuis398 9.9G 2014-04-25 22:03 ptest#P#p20140420.ibd

-rw-rw---- 1 seuis398 seuis398 9.9G 2014-04-25 22:08 ptest#P#p20140421.ibd

-rw-rw---- 1 seuis398 seuis398 9.9G 2014-04-25 22:34 ptest#P#p20140422.ibd

-rw-rw---- 1 seuis398 seuis398 9.9G 2014-04-25 22:39 ptest#P#p20140423.ibd

-rw-rw---- 1 seuis398 seuis398  96K 2014-04-25 22:39 ptest#P#pMAXVALUE.ibd

 

* 테스트1 (파티션 DROP) ==> 테이블 락 유지시간 0.59초 (사이즈에 따라 늘어남)

 : 다행히 테스트에 사용한 시스템은 ext4라서 10GB 삭제하는데 0.6초 정도 밖에 안걸리긴 했습니다.

   물론 파티션 사이즈가 더 커지거나 일자별 파티셔닝이 아니라 월별 파티셔닝을 한다면 삭제시 문제가 발생할 수 있겠습니다.

mysql> alter table ptest drop partition p20140420;

Query OK, 0 rows affected (0.59 sec)

Records: 0  Duplicates: 0  Warnings: 0 


* 테스트2 (파티션 Exchange) ==> 테이블 락 유지시간 : 0.04초 (균일하게 유지)

// 테스트 테이블의 파티션 1개와 동일한 구조의 테이블을 생성

mysql> create table empty_ptest like ptest; 

Query OK, 0 rows affected (0.07 sec) 

 

mysql> alter table empty_ptest remove partitioning;   

Query OK, 0 rows affected (0.17 sec)

Records: 0  Duplicates: 0  Warnings: 0

 

// 위에서 생성한 빈 테이블과 삭제한 파티션(20140421)을 Exchange

mysql> alter table ptest exchange partition p20140421 with table empty_ptest;   

Query OK, 0 rows affected (0.04 sec)

 

mysql>  select TABLE_NAME, PARTITION_NAME, TABLE_ROWS from information_schema.PARTITIONS where TABLE_NAME='ptest';

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

| TABLE_NAME | PARTITION_NAME | TABLE_ROWS |

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

| ptest      | p20140421      |          0 |

| ptest      | p20140422      |   32209112 |

| ptest      | p20140423      |   32184620 |

| ptest      | pMAXVALUE      |          0 |

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

4 rows in set (0.00 sec)

 

// 불필요한 데이터 일괄 삭제

mysql> alter table ptest drop partition p20140421;

Query OK, 0 rows affected (0.00 sec)

Records: 0  Duplicates: 0  Warnings: 0

 

mysql> drop table empty_ptest;

Query OK, 0 rows affected (0.58 sec) 



http://cafe.naver.com/mysqlpg/426


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

InnoDB tablespace 구조  (0) 2014.12.16
iostat의 %util 계산하는 방법  (0) 2014.12.12
SHOW PROCESSLIST  (0) 2014.12.11
MySQL 5.5 Semisynchronous Replication v1.0  (0) 2014.12.10
Buffer Cache 초기화 후, Data Caching 을 위한 Script  (0) 2014.12.10
반응형

1. closing tables
스레드는 테이블 체크 오퍼레이션을 실행중이다.

2. Closing tables
스 레드가 변경된 테이블 데이터를 디스크로 쏟아내고 사용된 테이블을 닫는 것을 의미한다. 이것은 빠른 오퍼레이션이다. 만약 그렇지 않다면, 풀(full) 디스크를 가지고 있지 않은지 그리고 디스크가 너무 과중하게 사용되지는 않는지 체크해야 한다.

3. Connect Out
리플리케이션 슬레이브는 그것의 마스터와 연결되어 있다.

4. Copying to tmp table
서버는 메모리에 있는 테이블로 복사한다.

5. Copying to tmp table on disk
서버가 디스크에 있는 임시 테이블로 복사한다. 임시 결과 세트는 tmp_table_size 보다 크고, 스레드는 메모리를 절약하기 위해서 인-메모리에서 디스크 기반 포멧으로 임시 테이블을 변경시킨다.

6. Creating tmp table
스레드는 쿼리의 결과 일부를 기억장치에 남겨두기 위해 임시 테이블을 생성한다.

7. deleting from main table
서버는 복함-테이블 삭제의 두 번째 부분을 실행하며, 다른 테이블로부터 매치된 로우를 삭제한다.

8. Flushing tables
스레드는 FLUSH TABLES를 실행하고 그 테이블을 종료하기 위해서 모든 스레드를 기다린다.

9. FULLTEST initialization
서버는 자연 언어처리 전문 검색을 준비한다.

10. Killed
누 군가 KILL 문을 스레드에 보내면 kill 플래그를 체크하여 다음에 중단해야 한다. 플래그는 MySQL의 각각의 메이저 루프에서 점검된다. 그러나 몇몇의 경우, 스레드가 멈추는데 짧은 시간이 걸리곤 한다. 만약 스레드가 몇몇 다른 스레드에 의해 잠겨 있다면, kill은 다른 스레드가 잠금을 해제하자마자 효력을 나타낸다.

11. Locked
쿼리는 다른 쿼리에 의해 잠긴다.

12. Sending data
스레드는 SELECT문으로 로우를 프로세싱하며 데이터를 클라이언트로 보낸다.

13. Sorting group
스레드는 GROUP BY 를 만족시키도록 정렬된다.

14. Sorting for order
스레드는 ORDER BY를 만족시키도록 정렬된다.

15. Opening tables
스레드는 테이블을 열러고 한다. 무언가 오픈을 방해하지 않는다면, 이것은 매우 빠를 프로시져이다. 예를 들어, ALTER TABLE 또는 LOCK TABLE 문은 문이 끝날 때 까지 테이블 오픈을 방해할 수 있다.

16. Reading from net
서버는 네트워크로 부터 패킷을 읽는다.

17. Removing duplicates
초 기단계에서 개별 오퍼레이션을 최적화 할 수 없는 것과 같은 그런 방법에서 쿼리는 SELECT DISTINCT를 사용하고 있다. 이런 이유로 결과를 클라이언트에게 전달하기 전에 모든 중복된 로우를 제거하기 위해서 MySQL은 별도의 단계가 필요하다.

18. Reopen table
스레드는 테이블을 잠갔다. 그러나 잠근 이후에 뒤에 숨은 테이블 구성이 변경되었다는 것을 인지한다. 잠금을 해제하고 테이블을 종료하며 그것을 다시 오픈하려 한다.

19. Repair by sorting
복구 코드는 인덱스를 생성하기 위해 사용된다.

20. Repair with keycache
복구 코드는 키 캐쉬 메모리를 통해 하나씩 키를 생성하는데 사용한다. 이것은 Repair by soting 보다 훨씬 느리다.

21. Searching rows for update
스레드는 로우를 업데이트하기 전에 모든 부합하는 로우를 찾기 위해 첫번째 단계를 행한다. UPDATE가 관련된 로우를 찾는데 사용된 인덱스를 변경시킨다면, 이것은 실행해야 한다.

22. Sleeping
새로운 문을 보내기 위해서 스레드는 클라이언트를 기다린다.

23. statistics
서버는 쿼리 실행 플랜을 발전시키기 위해 통계를 계산한다.

24. System lock
스레드는 테이블의 외부 시스템 잠금을 기다린다. 같은 테이블에 액세스하는 복합 mysqld 서버를 사용하지 않는다면, --skip-external-locking 옵션을 이용해 시스템 잠금 기능을 억제할 수 있다.

25. unauthenticated user
클라이언트 커넥션과 결합되었으나 클라이언트 유저의 인증을 아직 받지 못한 스레드의 상태

26. Upgrading lock
INSERT DELAYED 핸들러는 로우를 삽입하기 위해 테이블을 잠그려고 한다.

27. Updating
스레드는 업데이트할 로우를 찾아 업데이트 한다.

28. updating main table
서버는 복합-테이블 업데이트의 첫 번째 부분을 실행한다. 그것은 오로지 첫번째 테이블만 업데이트 하며, 다른 (레퍼런스) 테이블을 업데이트하는데 사용될 필드와 오프셋을 절약한다.

29. updating reference tables
서버는 복합-테이블 업데이트의 두 번째 부분을 실행하고, 다른 테이블로부터 부합하는 로우를 업데이트 한다.

30. User Lock
스레드는 GET_LOCK()을 기다린다.

31. Waiting for tables
스 레드는 테이블의 기초가 되는 체계가 변경되었다는 통보를 받았고, 새로운 체계를 만들기 위해 테이블을 다시 오픈할 필요가 있다. 그러나 테이블을 다시 열기 위해서, 모든 다른 스레드가 본 건에 대해 테이블을 종료할 때까지 기다려야 한다.

다른 스레드가 FLUSH TABLES를 사용하거나 또는 다음 문들 중 하나를 테이블에서 사용하면, 이런 경고가 발생한다. :FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE,REPAIR TABLE, ANALYZE TABLE, 또는 OPTIMIZE TABLE.

32. waiting for handler insert
INSERT DELAYED 핸들러는 모든 팬딩된 삽입을 실행하고 새로운 것을 기다린다.

33. Writing to net
서버는 네트워크에 패킷을 쓴다.



http://ziugae80.blog.me/71765559

반응형
반응형

이 문서는 dev.mysql.com 을 번역해 만들었음을 밝힌다.

 

1.    Semisynchronous Replication

MySQL 5.5 부터 기존의 built-in asynchronous replication  semisynchronous replication 이 추가되었다.

 

MySQL replication 은 기본적으로 asynchronous replication 을 사용한다. Master  Slave  Binary log 에 언제 엑세스를 했는지 혹은 수행을 했는지 아무정보가 없다.

Master crash 의 경우 Commit 된 정보가 어떤 Slave 로도 전송되지 말아야 한다. (하지만 Asynchronous Replication 에서는 이를 확인할 길이 없다.)

그 결과 Master 에서 Slave 로의 failover 시 누락된 트랜젝션이 발생하게 된다.

 

Semisynchronous Replication  asynchronous replication 의 대안이 될 수 있다.

 

l  semisynchronous-capable slave  master 에 접속시 이를 알린다.

l  master 에서 semisynchronous replication 활성 시 반드시 하나 이상의 semisynchronous slave 를 가져야 한다.

Master block  transaction commit 을 수행하는 쓰레드는 commit 의 완결과 하나 이상의

semisynchronous slave 로부터 트랜잭션에 대한 모든 정보를 받았음에 대한 확인이나 timeout 발생을 대기한다.

l  Slave 는 이벤트가 relay log 에 쓰였고 disk  flush 되었음을 알린다.

l  만약 모든 slave  transaction 에 대한 확인에 대한 알림없이 timeout 이 나는 경우 asynchronous replication 으로 변경된다. 이후 최소 하나 이상의 Slave 에 대해 확인이 되면 semisynchronous slave 로 변경된다.

l  Semisynchronous replication  master  slave 모두 활성화 되어야 한다. 만약 semisynchronous replication  master 상에서 비활성화 되어 있거나 Slave 가 없는 경우 master  asynchronous 를 사용한다.

 

마스터가 블로킹 상태 (commit 수행 후 slave 로부터 알림을 기다리는 상태) 중에는 transaction 을 수행중인 세션으로 돌아가지 않는다. 블록이 끝나면 다른 구문을 수행하기 위해 세션으로 돌아간다. 이 시점에 마스터 사이드의 트랜젝션은 commit 되며 그 이벤트에 대한 확인이 최소 하나 이상의 Slave 에 의해 알려진다.

/*+ 해석 다시 볼 것 Ref.A */

 

블록킹은 binay log 에 쓰여진 rollbacks 후에도 발생하며, nontransactional table 에 대한 수정이 rollback 될 때 일어난다. rolled-back transaction 은 그것이 transactional table 에 아무 영향이 없더라도 로깅된다. 그 이유는 nontransactional tables 에 대한 변경은 rollback 될 수 없으며 slave 에 반드시 전달되야하기 때문이다.

 

semisynchronous replication  semi 를 이해하기 위해선 asynchronous  full synchronous replication 을 비교한다.

 

l  asynchronous replication 에서는 master  events 를 바이너리 로그에 기록하며 slaves 는 받을 준비가 되면 요청한다. 이 과정엔 event  slave 에 도달한다는 보증이 없다.

l  full synchronous  replication 에서는 마스터가 transaction  commit 하면 마스터가 세션으로 돌아가 transaction 을 수행하기 전에 모든 slave  transaction 에 대해 commit 해야 한다. 이로 인해

transaction 종료까지 많은 delay 가 생길 수 있다.

l  semisynchronous replication  asynchronous  full synchronous Replication 사이에 위치한다. 마스터는 다만 하나이상의 slave  event 를 받고 기록했음을 대기한다. 이는 모든 slave 에 대해 대기하지는 않는다.  slave side 에서 완전히 다 실행되었고 commit 되었는가에 대한 대기가 아니다.

 

Asynchronous replication 에 대해 semisynchronous replication 은 보다 향상된 데이터 무결성을 제공한다. commit 이 성공적으로 완료되었을 때 데이터가 최소한 두 곳에 존재함을 알 수 있다. (master , 최소하나의 slave) 만약 master  commit 했지만 master  Slave 의 확인을 대기중에 crash 가 발생한 경우 트랜젝션이 아무 slave 에도 도달하지 못했음을 알 수 있다.

 

semisynchronous replication 은 성능상 부하가 있을 수 있다. 그 이유는 slave 를 대기하는 시간으로 인해 commit 이 느려지기 때문이다. 이 지연은 최소한 slave  commit 을 보내고 slave 로부터 확인을 받기위한 TCP/IP roundtrip 시간만큼 발생할 것이다.

이것이 의미하는 바는 가까운 네트워크에 구성 시 잘 동작하겠지만 거리가 있는 서버의 경우 부하가 커짐을 의미한다.

 

2.    Semisynchronous Replication Administrative Interface

이 기능을 사용하기 위해 두개의 플러그인이 필요하며, 하나는 Master 다른 하나는 Slave 를 위한 플러그인이다.

 

system 환경변수가 plugin 의 행동을 컨트롤한다.

아래는 몇가지 예이다.

 

rpl_semi_sync_master_enabled

semisync 기능의 활성화 master 에서 사용. 1:enable, 0:disable 을 의미

rpl_semi_sync_master_timeout

timeout 시간을 지정. 단위는 밀리세컨드.  : 1000 (10second)

rpl_semi_sync_slave_enabled

semisync 기능의 활성화 Slave 에서 사용. 1:enable, 0:disable

 

status 변수로 semisynchronous replication 모니터링이 가능하다.

rpl_semi_sync_master_clients

semisynchronous slave 

rpl_semi_sync_master_status

1 : plugin 사용가능하며 commit acknowledgement 가 발생했음.
0 : plugin 
이 사용가능하지 않거나 commit acknowledgement timeout 으로 asynchronous replication 으로 변경됨

rpl_semi_sync_master_no_tx

slave 로부터 승인받지 못한 수

rpl_semi_sync_masger_yes_tx

slave 로부터 승인받은 수

rpl_semi_sync_slave_status

slave 상태를 조회하는 것으로 
1 : pugin 
 enabled 상태이며 I/O Thread 가 수행중

0 : 기타

 

위의 system  status 변수들은 master  slave 에 플러그인이 ‘INSTALL PLUGIN’ 을 통해 설치 된 경우 사용가능하다.

 

3.    Semisynchronous Replication Installation and Configuration

semisynchronous replication 을 사용하기 위해서는 다음의 조건을 만족해야 한다.

 

l  MySQL 5.5 나 그 이상의 버전이 설치되어 있어야 한다.

l  plugin 설치에는 MySQL server  dynamic loading 을 지원해야 한다. 이를 확인하기 위해서는 system 변수 have_dynamic_loading 변수가 YES 인지를 확인한다. Binary 배포버전은 dynamic loading 을 지원해야 한다.

l  Replication 이 이미 구성되어 있고 동작중이어야 한다.

 

Semisynchronous replication 구성을 위해서는 다음의 명령이 필요하다. INSTALL PLUGIN, SET GLOBAL, STOP SLAVE, START SLAVEJ. 이 명령어는 SUPER 권한으로 수행되어야 한다.

 

semisynchronous replication plugins  MySQL 배포버전에 포함되어 있다.

플러그인 위치는 system variable plugin_dir 을 확인한다.

 

 

On the master :

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

 

On the slave :

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

 

linux  plugin 설치시 다음과 같은 에러메시지를 확인하면 libimf 의 설치가 필요하다.

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

ERROR 1126 (HY000): Can't open shared library

'/usr/local/mysql/lib/plugin/semisync_master.so' (errno: 22 libimf.so: cannot open

shared object file: No such file or directory)

 

semisynchronous replication plugin 이 설치되면 disabled 상태이다.

plugin 을 활성화 시키기 위해서는 system variables 셋팅해야 한다. 이는 runtime  set global 을 사용해 가능하다. (option file + restart 도 가능)

 

<Runtime >

 

On the Master  :

mysql> SET GLOBAL rpl_semi_sync_master_enabled = {0|1};

mysql> SET GLOBAL rpl_semi_sync_master_timeout = N;

 

On each slave :  

mysql> SET GLOBAL rpl_semi_sync_slave_enabled = {0|1};

 

위 작업 후 slave io thread 를 정지했다 기동해야한다. 이 과정을 생략하면 replication  asynchronous 로 동작한다.

 

On each slave :

mysql> STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;

 

<Runtim 이 아닌경우 : optionfile + restart>

 

On the master’s option file

[mysqld]

rpl_semi_sync_master_enabled=1

rpl_semi_sync_master_timeout=1000 # 1 second

 

On each slave’s option file

[mysqld]

rpl_semi_sync_slave_enabled=1

 

4.    Semisynchronous Replication Monitoring

다음의 명령을 통해 semi synchronous replication 구성을 확인할 수 있다.

 

<system variables>

mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';

 

<slave status>

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';

 

5.    Practice

기존에 Replication 구성이 되어 있음을 가정한다.

 

<DG1>

IP : 192.168.137.201

MySQL Port : 3306

<DG2>

IP : 192.168.137.202

MySQL Port : 3306

 

DG1 ,DG2  Semisynchronous Replication 조회를 한 결과 아무 결과가 나오지 않았다.

 

mysql> show variables like 'rpl_semi%';

Empty set (0.00 sec)

 

mysql> show status like 'Rpl_semi%';

Empty set (0.00 sec)

 

Semisynchronous Replication 사용을 위해 Plugin 위치를 조회했다.

 

mysql> show variables like 'plugin_dir';

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

| Variable_name | Value                        |

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

| plugin_dir    | /home/mysql/mysql/lib/plugin |

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

1 row in set (0.00 sec)

 

사실 설치에 사용한 5.5 binary 버전 자체가 플러그인을 가지고 있는 상태로 위 조회는 plugin 을 수동으로 다운 받아 위치시킬때나 필요하다.

 

<on the master side>

mysql> show variables like 'plugin_dir';

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

| Variable_name | Value                        |

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

| plugin_dir    | /home/mysql/mysql/lib/plugin |

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

1 row in set (0.00 sec)

 

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

Query OK, 0 rows affected (0.00 sec)

 

mysql> set global rpl_semi_sync_master_enabled=1;

Query OK, 0 rows affected (0.00 sec)

 

mysql> set global rpl_semi_sync_master_timeout=100;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show variables like 'rpl_semi_sync%';

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

| Variable_name                      | Value |

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

| rpl_semi_sync_master_enabled       | ON    |

| rpl_semi_sync_master_timeout       | 100   |

| rpl_semi_sync_master_trace_level   | 32    |

| rpl_semi_sync_master_wait_no_slave | ON    |

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

4 rows in set (0.00 sec)

 

PLUGIN 설치 후 Global Variable 변경을 통해 활성화 하였다.

위 과정 이후 Variables 조회를 하자 Semisynchronous 와 관련된 파라미터가 나왔다.

 

<on each slave>

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

Query OK, 0 rows affected (0.00 sec)

 

mysql> set global rpl_semi_sync_slave_enabled=1;

Query OK, 0 rows affected (0.00 sec)

 

 

mysql> show slave status\G

*************************** 1. row ***************************

               Slave_IO_State: Waiting for master to send event

                  Master_Host: 192.168.137.201

                  Master_User: repl

                  Master_Port: 3306

                Connect_Retry: 60

              Master_Log_File: mysql-bin.000001

          Read_Master_Log_Pos: 107

               Relay_Log_File: dg2-relay-bin.000002

                Relay_Log_Pos: 253

        Relay_Master_Log_File: mysql-bin.000001

             Slave_IO_Running: Yes

            Slave_SQL_Running: Yes

              Replicate_Do_DB:

          Replicate_Ignore_DB:

           Replicate_Do_Table:

       Replicate_Ignore_Table:

      Replicate_Wild_Do_Table:

  Replicate_Wild_Ignore_Table:

                   Last_Errno: 0

                   Last_Error:

                 Skip_Counter: 0

          Exec_Master_Log_Pos: 107

              Relay_Log_Space: 407

              Until_Condition: None

               Until_Log_File:

                Until_Log_Pos: 0

           Master_SSL_Allowed: No

           Master_SSL_CA_File:

           Master_SSL_CA_Path:

              Master_SSL_Cert:

            Master_SSL_Cipher:

               Master_SSL_Key:

        Seconds_Behind_Master: 0

Master_SSL_Verify_Server_Cert: No

                Last_IO_Errno: 0

                Last_IO_Error:

               Last_SQL_Errno: 0

               Last_SQL_Error:

  Replicate_Ignore_Server_Ids:

             Master_Server_Id: 1

1 row in set (0.00 sec)

 

mysql> stop slave io_thread;

Query OK, 0 rows affected (0.00 sec)

 

mysql> start slave io_thread;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show status like 'Rpl_semi_sync%';

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

| Variable_name              | Value |

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

| Rpl_semi_sync_slave_status | ON    |

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

1 row in set (0.00 sec)

 

Slave 에도 Semisynchronous Replication 사용을 위해 Plugin 설치와 Variable 설정을 했다. 다만 셋팅 전이나 셋팅 후나 show slave status\G 의 결과는 변함이 없었다.

 

DG2 (Slave)  slave status (start / slave) 에 따라 Master 에서 변하는 값이 있는데 이는 show status 명령을 통해 관찰할 수 있었다. ( show variables like ‘rep%’ 로는 변함이 없었다.)

 

<on the Master side>

mysql> show status like 'rpl%';

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

| Variable_name                              | Value       |

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

| Rpl_semi_sync_master_clients               | 1           | à slave stop 인 경우 0 으로 나온다.

| Rpl_semi_sync_master_net_avg_wait_time     | 0           |

| Rpl_semi_sync_master_net_wait_time         | 0           |

| Rpl_semi_sync_master_net_waits             | 0           |

| Rpl_semi_sync_master_no_times              | 0           |

| Rpl_semi_sync_master_no_tx                 | 0           |

| Rpl_semi_sync_master_status                | ON          |

| Rpl_semi_sync_master_timefunc_failures     | 0           |

| Rpl_semi_sync_master_tx_avg_wait_time      | 0           |

| Rpl_semi_sync_master_tx_wait_time          | 0           |

| Rpl_semi_sync_master_tx_waits              | 0           |

| Rpl_semi_sync_master_wait_pos_backtraverse | 0           |

| Rpl_semi_sync_master_wait_sessions         | 0           |

| Rpl_semi_sync_master_yes_tx                | 0           |

| Rpl_status                                 | AUTH_MASTER |

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

 

6.    References

A.     MySQL 5.5 Reference Manual :: 15 Replication :: 15.3 Replication Solutions :: 15.3.8 Semisynchronous Replication | http://dev.mysql.com/doc/refman/5.5/en/replication-semisync.html

B.     MySQL 5.5 Reference Manual :: 15 Replication :: 15.3 Replication Solutions :: 15.3.8 Semisynchronous Replication :: 15.3.8.1 Semisynchronous Replication Administrative Interface | http://dev.mysql.com/doc/refman/5.5/en/replication-semisync-interface.html

C.     MySQL 5.5 Reference Manual :: 15 Replication :: 15.3 Replication Solutions :: 15.3.8 Semisynchronous Replication :: 15.3.8.2 Semisynchronous Replication Installation and Configuration | http://dev.mysql.com/doc/refman/5.5/en/replication-semisync-installation.html

D.     MySQL 5.5 Reference Manual :: 15 Replication :: 15.3 Replication Solutions :: 15.3.8 Semisynchronous Replication :: 15.3.8.3 Semisynchronous Replication Monitoring |

http://dev.mysql.com/doc/refman/5.5/en/replication-semisync-monitoring.html

반응형
반응형

■ 목적

점검시 DB Restart 가 진행되어 Buffer Memory 가 초기화 되었을 때,

점검 오픈전 데이터들을 일부 Buffer Memory 로 Caching 함으로서

유저유입시 발생하는 Disk IO 충격을 완화함

 

 Reference

- MySQL NF 5.6 - InnoDB Buffer Pool Warm-Up (5.6.3~)

  : http://cafe.naver.com/mysqlpg/102

- MariaDB InnoDB Buffer Pool Warm-Up

  : http://cafe.naver.com/mysqlpg/75

 

 dba_cache_data.sh

 

#!/bin/bash

 

source  /usr1/mysql/dba/.env.ini

i

f [ -z "$1" ]
then
   SLEEP_TIME=1;
else
   SLEEP_TIME=$1;
fi

 

LoginPathStatus=`$MySQL_HOME/bin/mysql_config_editor print --all | grep dbmon | wc -l`

if [ $LoginPathStatus -eq 1 ];
then
   DBMonIdPwd=`echo --login-path=dbmon`
else
   DBMonIdPwd=`echo --user="${_DB_MON_UID}" --password="${_DB_MON_PWD}"`
fi

 

$MySQL_HOME/bin/mysql ${DBMonIdPwd} --skip-column-names -s < dba_cache_data.sql > dba_cache_data_tmp.sql
$MySQL_HOME/bin/mysql ${DBMonIdPwd} --skip-column-names -s < dba_cache_data_tmp.sql

 

 

 dba_cache_data.sql

 


select replace(sql_text, "count(*)", concat('count(*) as "[',rno,'] ', table_name, '"')) xxx
  from (
          select @no := @no + 1 as rno
                 , concat(table_schema, '.', table_name)                              as table_name
                 , concat('select count(*) from ', table_schema, '.', table_name,';') as sql_text
            from (select @no := 0 as rno) x, information_schema.tables
         where table_schema not in ('information_schema','common_schema','moniter'
                                                ,' mysql','perf_mon','performance_schema','ps_helper','test','zzdba','sys','mysql')
            and table_name not like '%log%'
            and table_name not like 'z_drop%'
            and table_name not like '%tmp%'
            and table_name not like '%temp%'
            and table_name not like '%event%'
            and table_name not like '%hist%'
            and engine not in ('FEDERATED')
            and engine is not null
) z;

 

 

 dba_cache_data_old.sql

 

select concat('select "[', rno, '] ', table_name,'"; ', sql_text) xxx
  from (
          select @no := @no + 1 as rno
                 , concat(table_schema, '.', table_name)                              as table_name
                 , concat('select count(*) from ', table_schema, '.', table_name,';') as sql_text
            from (select @no := 0 as rno) x, information_schema.tables
         where table_schema not in ('information_schema','common_schema','moniter'

                                                ,' mysql','perf_mon','performance_schema','ps_helper','test','zzdba','sys','mysql')
            and table_name not like '%log%'
            and table_name not like 'z_drop%'
            and table_name not like '%tmp%'
            and table_name not like '%temp%'
            and table_name not like '%event%'
            and table_name not like '%hist%'
) z;

 

 


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

SHOW PROCESSLIST  (0) 2014.12.11
MySQL 5.5 Semisynchronous Replication v1.0  (0) 2014.12.10
Warm-up InnoDB Buffer Pool  (0) 2014.12.10
Use login-paths (.mylogin.cnf)  (0) 2014.12.10
Mysql: Daily Checklist  (0) 2014.12.09
반응형


http://blog.naver.com/bomyzzang/220118755731


MySQL 5.6 새로운 기능 (Percona Server and MariaDB​ 지원)

 

InnoDB 설정 중 innodb_buffer_pool_size, 기본적으로 메모리에 InnoDB의 데이터와 인덱스를 저장하는 방식.

 

MySQL 서버를 재시작 할 경우, 버퍼-풀이 비어진 상태이기 때문에, 보통의 경우 버퍼의 워밍업에 약간의 시간이 소요됨.

 

이럴경우, 사용하는 방식이다.

 

 

1. mysql>  SET GLOBAL innodb_buffer_pool_dump_at_shutdown = 1;

 

MySQL 서버를 재기동하기 전에 해당 명령어 사용, shutdown 할 경우, 버퍼-풀 덤프 받음.

 

MySQL 서버를​ 중지할 때, ib_buffer_pool 이라는 파일이 MySQL의 DATADIR 에 생성되어짐.

 

 

 

2. ( my.cnf 설정 추가)  

 

[mysqld]

innodb_buffer_pool_dump_at_shutdown = 1

innodb_buffer_pool_load_at_startup = 1 

 

 

3. MySQL 재기동 (mysql.err 로그 확인 또는 status 확인)

 

2014-09-11 14:18:24 7fba24d5a700 InnoDB: Loading buffer pool(s) from /data/mysql_data/ib_buffer_pool

2014-09-11 14:18:24 7fba24d5a700 InnoDB: Buffer pool(s) load completed at 140911 14:18:24 

 

 ​mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

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

| Variable_name                                    | Value                                 |

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

| Innodb_buffer_pool_load_status            | Loaded 5121/6441 pages     |

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

1 row in set (0.00 sec)

 

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

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

| Variable_name                         | Value                                                               |

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

| Innodb_buffer_pool_load_status | Buffer pool(s) load completed at 140911 14:18:24 |

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

 

 

4. innodb_buffer_pool_dump_now ,innodb_buffer_pool_load_now.​ 사용하여

 

재기동 없이 즉시 버퍼-풀 적용하는 방법

 

 

 

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 3

Server version: 5.6.19-log MySQL Community Server (GPL)

 

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

 

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

 

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

 

mysql> show global variables like "innodb_buffer_pool_dump_now";

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

| Variable_name                              | Value    |

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

| innodb_buffer_pool_dump_now       | OFF      |

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

1 row in set (0.00 sec)

 

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

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

| Variable_name                                    | Value                                                                               |

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

| Innodb_buffer_pool_load_status            | Buffer pool(s) load completed at 140911 14:57:18                |

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

1 row in set (0.00 sec)

 

mysql> set global innodb_buffer_pool_dump_now = on ;

Query OK, 0 rows affected (0.00 sec)

 

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';

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

| Variable_name                                    | Value                                                                               |

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

| Innodb_buffer_pool_dump_status          | Buffer pool(s) dump completed at 140911 14:58:05              |

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

1 row in set (0.00 sec)

 

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

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

| Variable_name                                    | Value                                                                               |

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

| Innodb_buffer_pool_load_status            | Buffer pool(s) load completed at 140911 14:57:18                |

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

1 row in set (0.00 sec)

 

mysql> set global innodb_buffer_pool_load_now = on ;

Query OK, 0 rows affected (0.00 sec)

 

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

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

| Variable_name                                    | Value                                                                               |

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

| Innodb_buffer_pool_load_status            | Buffer pool(s) load completed at 140911 14:58:41                |

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

1 row in set (0.00 sec)

 


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

MySQL 5.5 Semisynchronous Replication v1.0  (0) 2014.12.10
Buffer Cache 초기화 후, Data Caching 을 위한 Script  (0) 2014.12.10
Use login-paths (.mylogin.cnf)  (0) 2014.12.10
Mysql: Daily Checklist  (0) 2014.12.09
스키마 검수  (0) 2014.12.09
반응형

The best way to specify server connection information is with your .mylogin.cnf file. Not only is this file encrypted, but any logging of the utility execution will not expose the connection information. Thus, no user names, passwords, ports, etc. are visible in the log. This is the preferred method for using MySQL Utilities to connect to servers.

Note: MySQL Utilities version 1.2.1 and later support login-paths.

Utilities support the use of login-paths in the connection string provided they use the following format login-path-name[:port][:socket] where the port and socket parameters are optional. If used, these optional parameters override the respective options from the specified login-path.

When using login-paths, there are no default values except on Posix systems when specifying a socket. In this case, the host option defaults to localhost. This means that combining the values specified in the login-path with the two optional values port and socket, one needs to specify at least a user, a hostname and a port or socket.

Use the mysql_config_editor tool (http://dev.mysql.com/doc/en/mysql-config-editor.html) to add the connection information as follows.

shell> mysql_config_editor set --login-path=instance_13001 --host=localhost --user=root --port=13001 --password
Enter password: <Password is prompted to be inserted in a more secure way>

Next, use the following command to confirm that the login-path data was correctly added to .mylogin.cnf (the encrypted file):

shell> mysql_config_editor print --login-path=instance_13001
[instance_13001]
user = root
password = *****
host = localhost
port = 13001

Once your .mylogin.cnf file is configured, you need only specify the section of the .mylogin.cnf file for the server connection. For example, the section created in the previous example is 'instance_13001'. Thus, we use --server=instance_13001. The following shows the execution of a utility specifying the login-path section.

shell> mysqlserverinfo --server=instance_13001 --format=vertical

# Source on localhost: ... connected.
*************************       1. row *************************
server: localhost:13001
config_file: /etc/my.cnf, /etc/mysql/my.cnf
binary_log: clone-bin.000001
binary_log_pos: 341
relay_log:
relay_log_pos:
version: 5.6.17-log
datadir: /Volumes/Source/source/temp_13001/
basedir: /Volumes/Source/source/bzr/mysql-5.6
plugin_dir: /Volumes/Source/source/bzr/mysql-5.6/lib/plugin/
general_log: OFF
general_log_file:
general_log_file_size:
log_error:
log_error_file_size:
slow_query_log: OFF
slow_query_log_file:
slow_query_log_file_size:
1 row.
#...done.

See the online MySQL Reference Manual for more information about login-paths, the .mylogin.cnf file, and themysql_config_editor client.





MySQL 5.6 에 보안을 위한Tool (mysql_config_editor)이 추가되어 테스트 해보았습니다.

mysql 접속시 암호를 넣지않고 접속할 수 있네요.


 

--===========================================================================

--mysql_config_editor — MySQL Configuration Utility

--===========================================================================

-- http://dev.mysql.com/doc/refman/5.6/en/mysql-config-editor.html

-- http://anothermysqldba.blogspot.kr/2013/05/mysql-users-grants-mysqlconfigeditor.html

-- http://mysqlblog.fivefarmers.com/2012/08/16/understanding-mysql_config_editors-security-aspects/

--===========================================================================


mysql_config_editor set --login-path=local_test --host=localhost--user=root --password --socket=/tmp/mysql.sock --port=15615


mysql_config_editor print --all


  [local_test]

  user = root

  password = *****

  host = localhost

  socket = /tmp/mysql.sock

  port = 3306


ls -l ~/.mylogin.cnf

  -rw-------. 1 root root 192 Dec 26 17:15 /root/.mylogin.cnf


cat ~/.mylogin.cnf

  ;z?rr_喘픕톄

  }}??F??C_- ?`?


  --> Binary file 로 되어있어서읽지못함


mysql --login-path=local_test

  Welcome to the MySQL monitor.  Commands end with ; or \g.

  Your MySQL connection id is 11

  Server version: 5.6.15-log MySQL Community Server (GPL)


  Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

  Oracle is a registered trademark of Oracle Corporation and/or its

  affiliates. Other names may be trademarks of their respective

  owners.


  Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

  [localhost] ((none)) 17:16>


mysql --login-path=local_test TEST

  Welcome to the MySQL monitor.  Commands end with ; or \g.

  Your MySQL connection id is 11

  Server version: 5.6.15-log MySQL Community Server (GPL)


  Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

  Oracle is a registered trademark of Oracle Corporation and/or its

  affiliates. Other names may be trademarks of their respective

  owners.


  Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

  [localhost] (TEST) 17:17>

 

mysql_config_editor remove --login-path=local_test

mysql_config_editor print --all


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

Buffer Cache 초기화 후, Data Caching 을 위한 Script  (0) 2014.12.10
Warm-up InnoDB Buffer Pool  (0) 2014.12.10
Mysql: Daily Checklist  (0) 2014.12.09
스키마 검수  (0) 2014.12.09
jmeter 스트레스 툴  (0) 2014.12.09
반응형

Then leave a small post on how to mount an automatic notification via mail that tells us what is the status of our database. For example we can manage it a bit before starting our work day and before we leave or while on vacation (jaja. ..). This example is about a MySQL 5.x running on Debian. Steps as follows:

  • Check server uptime, memory and disk space.
     
  • Check the latest backups or logs of the same
     
  • Obtaining the status of the database
     
  • Error logs from the database.
     
  • Notification via mail.

The system is to build a script that builds our report in a file and then mail it. Moreover, in this example the state of the database I get to mysqlreport *. This gives us enough information to know that has happened recently in the database and can detect any problem if we know what the baseline.

* Be careful because it is available from version 5.x

Step 1) Edit the script based báscia checklist.sh. As you can see has no secret because it is always just redirect the output of a specific command to a temporary file which is then attached as the body of mail or attachment. The format and style and are things of each ...

 

 

 

#!/bin/bash

#

#  Mysql Daily Checklist

#

# Parameters

LOG=/scripts/checklist/check.txt

 

# Here starts the longline action

TXT=''

SL=''

#  State Machine

TXT='>>> 0.UPTIME'

echo $TXT > $LOG

w >> $LOG

# Server Memory

TXT='>>> 1.MEMORY'

echo $SL >> $LOG

echo $TXT >> $LOG

free -m >> $LOG

# Disk Space

TXT='>>> 2.DISK ESPACE  '

echo $SL >> $LOG

echo $TXT >> $LOG

df -h >> $LOG

# Latest backups

TXT='>>>3.BACKUPS'

echo $SL >> $LOG

echo $TXT >> $LOG

ls -lh -t /var/backups_mysql/ >> $LOG

# State mysql

TXT='>>>4.State   MYSQL'

echo $SL >> $LOG

echo $TXT >> $LOG

mysqlreport –user root –password pwd –all >> $LOG

 

#  Notificatiojn via email

echo “Checklist”|mail .s “MYSQL > Daily Checklist ” ilmasacratore@dataprix.com < $LOG

# Delete temp file

rm $LOG

 

 

 

 

 

Step 2) Execute Permissions and programming

For Unix systems you can use crontab to schedule the execution, after assigning execute permissions to the file for the user who will put it in cron

Example email:

 

 

 

 

0.UPTIME
 09:00:01 up 13:20,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT

>>> 1.MEMORY
             total       used       free     shared    buffers     cached
Mem:           884        877          6          0         44        745
-/+ buffers/cache:         88        795
Swap:          737          0        737

>>> 2.Disk Space
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1              17G  8.4G  7.9G  52% /
tmpfs                 443M     0  443M   0% /lib/init/rw
tmpfs                 443M     0  443M   0% /dev/shm

>>> 3.BACKUPS
>>> 4.MYSQL STATE

MySQL 5.0.32-Debian_7et  uptime 0 13:9:20       Wed Jul 14 09:00:01 2010

__ Key _________________________________________________________________
Buffer used   387.00k of  16.00M  %Used:   2.36
  Current       1.84M            %Usage:  11.52
Write ratio      0.03
Read ratio       0.10

__ Questions ___________________________________________________________
Total           7.61k    0.16/s
  Com_          5.47k    0.12/s  %Total:  71.93
  COM_QUIT        807    0.02/s           10.61
  DMS             665    0.01/s            8.74
  +Unknown        602    0.01/s            7.92
  QC Hits          61    0.00/s            0.80
Slow                6    0.00/s            0.08  %DMS:   0.90
DMS               665    0.01/s            8.74
  SELECT          648    0.01/s            8.52         97.44
  UPDATE           12    0.00/s            0.16          1.80
  DELETE            4    0.00/s            0.05          0.60
  INSERT            1    0.00/s            0.01          0.15
  REPLACE           0    0.00/s            0.00          0.00
Com_            5.47k    0.12/s           71.93
  show_create   1.15k    0.02/s           15.10
  show_status     797    0.02/s           10.48
  show_variab     797    0.02/s           10.48

__ SELECT and Sort _____________________________________________________
Scan            3.92k    0.08/s %SELECT: 605.09
Range               0    0.00/s            0.00
Full join           1    0.00/s            0.15
Range check         0    0.00/s            0.00
Full rng join       0    0.00/s            0.00
Sort scan           7    0.00/s
Sort range          1    0.00/s
Sort mrg pass       0    0.00/s

__ Query Cache _________________________________________________________
Memory usage  106.50k of  16.00M  %Used:   0.65
Block Fragmnt   0.68%
Hits               61    0.00/s
Inserts            65    0.00/s
Prunes              1    0.00/s
Insrt:Prune      65:1    0.00/s
Hit:Insert     0.94:1

__ Table Locks _________________________________________________________
Waited              0    0.00/s  %Total:   0.00
Immediate       1.32k    0.03/s

__ Tables ______________________________________________________________
Open               64 of   64    %Cache: 100.00
Opened          2.01k    0.04/s

__ Connections _________________________________________________________
Max used            3 of  100      %Max:   3.00
Total             810    0.02/s

__ Created Temp ________________________________________________________
Disk table      1.19k    0.03/s
Table           3.52k    0.07/s
File                5    0.00/s

 

 

Now, who likes or knows a little of topic you can think a thousand things to add or things that are missing. For some specific queries as the number of processos so we can use from the command line mysqladmin-u-p <user> <key> <option> for more interesting facts ... Everyone who makes it his own way!

반응형

'연구개발 > MYSQL' 카테고리의 다른 글

Warm-up InnoDB Buffer Pool  (0) 2014.12.10
Use login-paths (.mylogin.cnf)  (0) 2014.12.10
스키마 검수  (0) 2014.12.09
jmeter 스트레스 툴  (0) 2014.12.09
스트레스 테스트 툴 super-smack  (0) 2014.12.08
반응형

https://common-schema.googlecode.com/svn/trunk/common_schema/doc/html/install.html




PLUK2012-commonschema-dbas-framework-mysql.pdf


반응형
반응형

http://odysseymoon.tistory.com/53

반응형

'연구개발 > MYSQL' 카테고리의 다른 글

Mysql: Daily Checklist  (0) 2014.12.09
스키마 검수  (0) 2014.12.09
스트레스 테스트 툴 super-smack  (0) 2014.12.08
MySQL에서 무중단으로 스키마 변경하기(Alter) pt-online-schema-change  (0) 2014.12.08
프로시저 처리  (0) 2014.12.08
반응형
# 리눅스 환경에서 MySQL 스트레스 테스트 툴 super-smack 1.3 설치 및 사용방법
1. 참고 사이트
2. super-smack 1.3 다운로드
3. super-smack 1.3 설치
tar -zxvf super-smack-1.3.tar.gz
cd super-smack-1.3
./configure --prefix=/usr/local/super-smack --with-mysql --with-mysql-lib=/usr/local/mysql/lib/mysql --with-mysql-include=/usr/local/mysql/include/mysql
make && make install
4. 사용방법
super-smack 소스를 압출을 해제한 디렉토리로 이동하면 smacks 디렉토기가 보이며 아래와 같은 파일이 존재한다.
select-key.smack
update-select.smack
테스트를 진행하고자하는 용도에 맞는 파일을 이용하면 된다.
/usr/local/super_smack/bin/super_smack ./select-key.smack 10 100
* 10명이 100개의 쿼리를 동시에 실행할 경우
Query Barrel Report for client smacker1
connect: max=35ms min=0ms avg= 9ms from 10 clients
Query_type num_queries max_time min_time q_per_s
select_index 2000 0 0 9990.86


http://blog.naver.com/junhomb/110143921611


[출처] super-smack |작성자 몽키D루피


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

스키마 검수  (0) 2014.12.09
jmeter 스트레스 툴  (0) 2014.12.09
MySQL에서 무중단으로 스키마 변경하기(Alter) pt-online-schema-change  (0) 2014.12.08
프로시저 처리  (0) 2014.12.08
my.cnf  (0) 2014.12.08
반응형

중단없이 온라인상에서 MySQL의 테이블 스키마 변경 작업에 대해서 알아본다.
무중단으로 스키마를 변경할 수 있는 방법으로는 현재, openark kit의 "oak-online-alter-table", Percona의 "pt-online-schema-change"와 Facebook의 "OSC(Online Schema Change for MySQL)"를 가장 많이 사용할 것 같다.

oak-online-alter-table과 pt-online-schema-change 차이는 oak-online-alter-table에는 지원안하는 포린키와 슬래이브 상태 고려 등을 빼고는 비슷하다. 그래서 좀 더 기능이 보완된 pt-online-schema-change 도구를 가지고 하는 방법을 설명해 본다. Facebook에서 사용하는 툴은 아직 분석하지 못했다. ^^

pt-online-schema-change는 Percona Toolkit의 여러 기능 중에 하나이고, Percona Toolkit은 Maatkit과 Aspersa를 기반으로해서 탄생되었다.
참고로 MySQL 5.6에서는 ALTER TABLE ... ADD INDEX / DROP INDEX 중 이어도 참조·갱신이 함께 실행이 될 수 있다고 하니 참고하면 될 듯 하다.
그리고 TokuDB를 사용할 경우에도 온라인상에서 스키마변경이 자유롭다.


Alter Table의 이슈

Alter Table 명령을 날리면 보통 아래와 같은 순서대로 진행된다.(innodb의 경우)

  1. 해당 테이블을 TL_WRITE_ALLOW_READ로 잠근다. 즉, READ는 허용하고 WRITE를 차단한다는 의미이다.
  2. 새로운 테이블의 빈 임시 테이블을 만들고.
  3. 이전 테이블에서 새 테이블에 데이터를 복사하며.
  4. 새 테이블을 이전 테이블과 같은 이름으로 바꾸고 이전 테이블은 삭제한다.
  5. 새로운 테이블에 차단했던 WRITE를 푼다.

이렇듯 Alter를 진행하게 되면 해당 테이블의 쓰기 잠금이 발생하여 일반적으로 온라인상에서는 테이블의 스키마 변경은 할 수 없는 구조이다. 스키마 변경을 할 시에는 데이터를 복사하게 되므로 해당 테이블의 사이즈만큼 스토리지 공간이 필요하게 된다.
Alter는 테이블의 행 수가 증가에 따라 선형적으로 시간이 길어지는 것은 아니다. 실제는 더 늦어질 수 있다는 의미이다. 왜냐하면 인덱스 재구성은 O (N log N)의 시간이 걸리기 때문이다. 그래서 테이블의 건수를 기준으로 절대적인 시간을 예측하기 보다는 실제 건수를 만들어서 테스트를 해보기를 권장한다. 거기에 Alter는 한번의 명령에 몰아서 처리해야 테이블 복사를 한번만 할 수 있다. 예를 들면 아래와 같다.

mysql> ALTER TABLE t1 DROP INDEX idx01, DROP INDEX idx02... ADD INDEX (idxN);



pt-online-schema-change의 방식은?

이 방식은 기존 MySQL의 Alter 방식의 프로세스를 수작업으로 자동화(스크립트화)시켰다고 보면 된다. Write 잠금 기능을 제거하고 그 기능을 trigger로 풀어서 원본 테이블의 R/W를 가능하게 했고 수행 순서를 보면 알겠지만, trigger를 통해 데이터 동기화를 이루었다. pt-online-schema-change의 방식의 기본적인 프로세스는 아래와 같다.

1. 새로운 임시 테이블 생성
기존 테이블에 앞에는 prefix 인자를 넣으면 prefix가 붙고 _에 원본 테이블명, 그리고 뒤에는 _new를 붙여 네이밍한 다음 임시 테이블을 만든다.
create_new_table()함수를 보면,

my $prefix = $args{prefix} || '_';
my $suffix = '_new';
my $table_name = $orig_tbl->{tbl}.$suffix;
$table_name = $prefix.$table_name;


2. 새로운 임시테이블 Alter
alter 인자로 주어진 ddl구문을 실행해서 임시 테이블에 칼럼 및 인덱스 등을 생성한다.

my $sql = "ALTER TABLE $new_tbl->{name} $alter";
print $sql, "\n" if $o->get('print');
PTDEBUG && _d($sql);
eval {
  $cxn->dbh()->do($sql);
};


3. 트리거 생성
원본 테이블의 변경사항을 임시 테이블에 반영해서 동기화하는 부분에 해당된다. 원래 테이블에 AFTER INSERT, AFTER UPDATE, AFTER DELETE 등 세 트리거를 만든다.
실행부분은 아래와 같고.

my @trigger_names = eval {
    create_triggers(
    orig_tbl => $orig_tbl,
    new_tbl => $new_tbl,
    columns => \@common_cols,
    Cxn => $cxn,
    Quoter => $q,
    OptionParser => $o,
  );
};


실제로 트리거문 구성을 살펴보면 아래와 같다. 참고로 MySQL의 트리거는 각각의 이벤트에 하나 밖에 만들 수 없기 때문에 이미 트리거 존재하는 테이블에 pt-online-schema-change을 사용할 수 없다.

my $insert_trigger
= "CREATE TRIGGER `${prefix}_ins` AFTER INSERT ON $orig_tbl->{name} "
. "FOR EACH ROW "
. "REPLACE INTO $new_tbl->{name} ($qcols) VALUES ($new_vals)";

my $update_trigger
= "CREATE TRIGGER `${prefix}_upd` AFTER UPDATE ON $orig_tbl->{name} "
. "FOR EACH ROW "
. "REPLACE INTO $new_tbl->{name} ($qcols) VALUES ($new_vals)";

my $delete_trigger
= "CREATE TRIGGER `${prefix}_del` AFTER DELETE ON $orig_tbl->{name} "
. "FOR EACH ROW "
. "DELETE IGNORE FROM $new_tbl->{name} "
. "WHERE $del_index_cols";


INSERT 이벤트에 대해서는 REPLACE문, UPDATE 이벤트는 REPLACE 문, DELETE 이벤트에 대해 DELETE 문을 발생시킨다. 그리고 DELETE 문은 임시 테이블에 레코드가 없을 경우 무시해 버리게 해 놨다.



4. 데이터 복사
INSERT LOW_PRIORITY IGNORE INTO ... 구문을 가지고 nibble_iter를 통해 원본 테이블의 데이터를 임시 테이블로 복사를 시작한다.
이렇게하면 응용 프로그램 측의 처리가 잠금 대기 시간에서 실패하는 것을 막으려하고 있다. 또한 시스템이 과부하되는 것을 방지하기 위해 1,000 레코드 처리할 때마다 대기 시간을 가질 수 있게 되어 있다.



5. 테이블 리네임(swap)
원본 테이블과 임시테이블을 교체한다. 기존 테이블은 _기존테이블_old로 바꾸고 신규 임시 테이블은 기존 테이블로 리네임한다.

eval {
  $old_tbl = swap_tables(
    orig_tbl => $orig_tbl,
    new_tbl => $new_tbl,
    suffix => '_old',
    Cxn => $cxn,
    Quoter => $q,
    OptionParser => $o,
  );
};
RENAME TABLE.. TO .. TO ...


6. foreign key 업데이트
존재할 경우 처리.

7. OLD 테이블 DROP


온라인상에서 스키마 변경 테스트

간단하게나마 pt-online-schema-change 살펴보았다. 다음으로는 실제 이 스크립트가 제대로 동작하는 지 살펴볼 차례다. 다음은 pt-online-schema-change을 사용하기 위한 방법을 기술한다.

#perl 모듈 설치(설치 안되었을 경우)
cpan> install DBI
cpan> install DBD::mysql
cpan> install Term::ReadKey
# 해당 스크립트 단운로드
> wget http://www.percona.com/redir/
 downloads/percona-toolkit/LATEST/percona-toolkit-2.1.7.tar.gz

# 테스트 테이블
CREATE TABLE t1 (
username char(25) not null primary key,
pass char(25),
uid integer not null,
gid integer not null
) Engine=InnoDB DEFAULT CHARSET=utf8";


아래는 super-smack을 통해 update 트랜젝션을 일으키면서 실제 온라인상에서 테이블 스키마 변경을 테스트해 본다.

> /database/server/super-smack/bin/super-smack \
./update-select.smack 10 100 >> /samples/data/log5.txt

> /percona-toolkit-2.1.7/bin> ./pt-online-schema-change \
--execute --ask-pass --user=root --chunk-time=1 \
--nodrop-old-table --alter-foreign-keys-method auto \
--alter "add column t_date char(15) default null" D=test,t=t1,h=localhost

Enter MySQL password: 
No foreign keys reference `test`.`t1`; ignoring --alter-foreign-keys-method.
Altering `test`.`t1`...
Creating new table...
Created new table test._t1_new OK.
Altering new table...
Altered `test`.`_t1_new` OK.
Creating triggers...
Created triggers OK.
Copying approximately 90000 rows...
Copied rows OK.
Swapping tables...
Swapped original and new tables OK.
Dropping triggers...
Dropped triggers OK.
Successfully altered `test`.`t1`.


간단하게 옵션에 대한 설명을 곁들인다. 

  • alter : 실행 alter 문.
  • h : 호스트 정보.
  • D : 데이터베이스 명.
  • t : 테이블 정보.
  • ask-pass : 암호를 표준 입력 가능함.
  • alter-foreign-keys-method : 변경 대상 테이블에 외래 키 설정이 되어있는 경우 처리 방법. auto, rebuild_constraints, drop_swap, none을 지정할 수 있음. 외부 참조의 데이터 건수가 많으면 drop_swap 됨.
  • nocheck-replication-filters : replication의 filter 설정.
  • execute : 이를 지정하지 않으면 실행되지 않음. 또한, dry-run에서 테스트 할 수 있음.


[참고 사이트]


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

jmeter 스트레스 툴  (0) 2014.12.09
스트레스 테스트 툴 super-smack  (0) 2014.12.08
프로시저 처리  (0) 2014.12.08
my.cnf  (0) 2014.12.08
InnoDB 테이블 손상(깨어진)시 강제 복구  (0) 2014.12.08
반응형

use CommonDB;


CREATE TABLE `log_error` (
  `partkey_month` int(11) NOT NULL COMMENT '파티션키',
  `log_error_idx` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '키 IDENTITY',
  `procedure_name` varchar(50) not null comment '프로시저명',
  `sql_state` varchar(10) not null comment 'sqlstate',
  `msg` varchar(500) not null comment '에러메시지',
  `reg_date` datetime NOT NULL COMMENT '등록일',
  PRIMARY KEY (`log_error_idx`,`partkey_month`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY LIST (partkey_month)
(PARTITION p0 VALUES IN (0) ENGINE = InnoDB,
 PARTITION p1 VALUES IN (1) ENGINE = InnoDB,
 PARTITION p2 VALUES IN (2) ENGINE = InnoDB,
 PARTITION p3 VALUES IN (3) ENGINE = InnoDB,
 PARTITION p4 VALUES IN (4) ENGINE = InnoDB,
 PARTITION p5 VALUES IN (5) ENGINE = InnoDB,
 PARTITION p6 VALUES IN (6) ENGINE = InnoDB,
 PARTITION p7 VALUES IN (7) ENGINE = InnoDB,
 PARTITION p8 VALUES IN (8) ENGINE = InnoDB,
 PARTITION p9 VALUES IN (9) ENGINE = InnoDB,
 PARTITION p10 VALUES IN (10) ENGINE = InnoDB,
 PARTITION p11 VALUES IN (11) ENGINE = InnoDB,
 PARTITION p12 VALUES IN (12) ENGINE = InnoDB) */;

create table test ( 
 i int 
);




DROP PROCEDURE IF EXISTS usp_RegUser;


delimiter //

CREATE PROCEDURE usp_RegUser (

IN pi_site_user_id VARCHAR(30)

, IN pi_site_type INT

, OUT po_result bigint

, OUT po_date datetime

)

BEGIN


    DECLARE v_date DATETIME DEFAULT now();

    DECLARE v_gamedb_shard_cnt SMALLINT DEFAULT 16;

    DECLARE v_logdb_shard_cnt SMALLINT DEFAULT 16;

    DECLARE v_account_idx BIGINT DEFAULT 0;

    DECLARE v_gamedb_idx INT DEFAULT 0;

    DECLARE v_logdb_idx INT DEFAULT 0;

    

    DECLARE v_sqlstate VARCHAR(5) DEFAULT '00000';

    DECLARE v_msg                            VARCHAR(500);

    DECLARE v_err_no INT;

    

    DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING

    BEGIN

GET DIAGNOSTICS CONDITION 1 v_sqlstate = RETURNED_SQLSTATE

, v_err_no = MYSQL_ERRNO

, v_msg = MESSAGE_TEXT;

ROLLBACK;

                ## 에러 처리 시 테이블에 저장

                insert into log_error ( partkey_month, procedure_name, sql_state, msg, reg_date ) values ( month(sysdate()), "usp_RegUser ", v_sqlstate, v_msg, sysdate());

        SET po_result = v_err_no * -1;

        

    END;

    

    SET po_date = v_date;

    

    BEGIN

    

START TRANSACTION;

        

        INSERT INTO user2db (

    gamedb_idx

            ,logdb_idx

            ,user_status

            ,site_type

            ,site_user_id

            ,site_user_seq

            ,reg_date

            ,upd_date

        )

        VALUES (101, 301, 'R', pi_site_type, pi_site_user_id, 1, v_date, v_date);

        

        SET v_account_idx := LAST_INSERT_ID();

        

        SELECT gamedb_idx, logdb_idx

        INTO v_gamedb_idx, v_logdb_idx

        FROM shard2db

        WHERE shard2db_idx = mod(v_account_idx, 16) +1;

        

        UPDATE user2db a

        SET a.gamedb_idx = v_gamedb_idx

    , a.logdb_idx = v_logdb_idx

            , a.user_status = 'N'

WHERE a.site_user_id = pi_site_user_id

AND a.site_type = pi_site_type

              AND a.account_idx = v_account_idx;

    

COMMIT;

    

    END;

    

    SET po_result = v_account_idx;    


END //

delimiter ;




TRUNCATE TABLE user2db;


SET @po_result = -999;

CALL usp_RegUser('TestUser1', 1, @po_result, @po_date);

SELECT @po_date, @po_result;

SELECT * FROM user2db;



set @po_result = -999;

call usp_RegUser('TestUser2',1, @po_result, @po_date);

call usp_RegUser('TestUser3',1, @po_result, @po_date);

call usp_RegUser('TestUser4',1, @po_result, @po_date);

call usp_RegUser('TestUser5',1, @po_result, @po_date);

select @po_date, @po_result;

SELECT * FROM user2db;


반응형
반응형

## ---------------------------------------------------------------------------------------

## [SERVER] MySQL Server Configuration 

## ---------------------------------------------------------------------------------------


[mysqld]

## MySQL Server Default Option ------------------------------------------------------------------

server-id = 1


user                            = mysql 

port                            = 3306  

datadir                         = /wemade/database/data

tmpdir                          = /tmp

socket                          = /tmp/mysql.sock


character_set_server            = utf8

collation-server                = utf8_general_ci

default-storage-engine          = InnoDB

skip-name-resolve

skip-external-locking



## MySQL - event-scheduler = ON(true)/OFF(false)

event-scheduler                 = ON   

sysdate-is-now # 함수 sysdate()와 now() 동일하게 처리


back_log                        = 100 # 동시 접속시 대기시킬 수 있는 커넥션 개수

max_connections                 = 300

max_connect_errors              = 999999

thread_cache_size               = 50 # 다쓴 쓰레드를 스레드풀에 저장할 개수


#table_open_cache = 400 # 각 쓰레드별 오픈할 테이블 수


max_allowed_packet              = 32M # 요청된 쿼리의 최대 길이의 값

max_heap_table_size             = 32M # MEMORY 테이블의 최대 크기

tmp_table_size                  = 2M # 메모리 내의 임시테이블 크기 (초과 시 디스크에 저장)


# For Per Connection

sort_buffer_size                = 512K # 정렬에 필요한 버퍼의 크기 order by 또는 group by 연산 속도와 관련

join_buffer_size                = 512K # 조인이 테이블을 풀스캔하기 위해 사용하는 버퍼크기

read_buffer_size                = 512K # 테이블 스캔에 필요한 버퍼크기

read_rnd_buffer_size            = 512K # 디스크 검색을 피하기 위한 랜덤 읽기 버퍼크기


query_cache_size                = 32M #쿼리 결과를 캐싱하기 위해 할당된 메모리 크기

query_cache_limit               = 2M # 이 변수 값보다 큰 값은 캐싱이 안됨


group_concat_max_len            = 1024 # GROUP_CONCAT() 함수 사용 시 컬럼값 최대 크기


## MySQL Isolation

transaction-isolation = READ-COMMITTED



## InnoDB Plug-in Option -----------------------------------------------------------------------------

innodb_adaptive_flushing        = ON

innodb_adaptive_hash_index      = 1

innodb_autoinc_lock_mode        = 1

innodb_change_buffering         = all

innodb_file_format              = barracuda

innodb_io_capacity              = 600

innodb_max_dirty_pages_pct      = 90

innodb_old_blocks_time          = 500

innodb_read_io_threads          = 6

innodb_stats_on_metadata        = 1

innodb_stats_sample_pages       = 8

innodb_strict_mode              = 0

innodb_use_sys_malloc           = 1

innodb_write_io_threads         = 6

ignore_builtin_innodb           = OFF




## InnoDB Default Option  -----------------------------------------------------------------------------

innodb_additional_mem_pool_size = 32M # 데이터 디렉토리 정보와 내부 데이타 구조를 저장하는 메모리 풀의 크기

innodb_autoextend_increment     = 100 # 테이블 스페이스 자동 확장 시 크기

innodb_buffer_pool_size         = 22G # 데이터와 인덱스를 캐시하기 위해 사용하는 메모리버퍼크기(innodb에서 사용할 메모리 양으로 전체 메모리의 50~80% 정도로 설정)

innodb_buffer_pool_instances    = 4

innodb_commit_concurrency       = 0 # 동시에 커밋할 수 있는 쓰레드 수. 이 변수가 0(default)이면 동시에 커밋하기 위해 어떤 수 많은 트랜잭션도 허용한다.

innodb_concurrency_tickets      = 500   

innodb_data_file_path = ibdata1:3G;ibdata2:3G;ibdata3:3G;ibdata4:100M:autoextend  

innodb_data_home_dir            = /wemade/database/data # innodb 홈디렉토리 경로

innodb_doublewrite              = 1 # 이중 쓰기 버퍼 활성 (이 옵션은 데이터 정합성을 마줘주는 중요한 변수라 웬만해서는 끄지 않는 변수)

innodb_sync_spin_loops = 20 # 쓰레드가 지연되기 전에 (suspended) 풀어 주기 위해 Innodb 뮤텍스(mutex)를 기다리는 쓰레드의 대기 시간

innodb_file_per_table           = 1 # 테이블 단위로 테이블 스페이스 할당, 활성 시 확장자 .ibd 파일이 생성됨

innodb_flush_log_at_trx_commit  = 1

# innodb_flush_log_at_trx_commit 이 0으로 설정되면, 로그 버퍼는 초당 한 번씩 로그 파일이 기록이 되고 디스크 연산에 대한 플러시는 로그 파일에서 실행되지만

# 트랙잭션 실행 시점에는 아무것도 실행되지 않게 된다. 이 값이 1(default)로 설정되면, 로그 버퍼는 각 트랜잭션이 실행될 때마다 로그 파일에 기록되고 로그 파일에서 디스크 연산에

# 대한 플러시가 실행된다. 2로 설정되면 로그 버퍼는 각 실행시점마다 파일로 기록되지만, 디스크 연산에 대한 플러시는 실행되지 않는다. 하지만 로그 파일에 대한 플러시는

# 값이 2일 때에도 초당 한번씩 실행된다. 초당 1회의 플러시는 모든 초당 이루어진다고는 장담할 수가 없는데, 그 이유는 프로세스 스케쥴링 문제 때문이라는 점을 알아두자.

# 이 변수의 디폴트 값은 1이며, 이 값은 ACID와의 호환성을 위해 요구되는 값이다. 여러분은 이 값을 1이외의 값으로 설정해서 보다 좋은 성능을 얻을 수는 있겠지만,

# 크래쉬가 나게 되면 한 순간에 모든 것을 잃어 버릴 수도 있다.

# 만약 이 값을 0으로 설정한다면, 어떠한 mysqld 프로세스 크래시라도, 만일 이 값을 2로 설정한다면, os크래시 또는 전원 불량을 통해서만 마지막 초 순간의 트랜잭션이 지워지게 된다.

# 하지만 innodb의 크래시 복구는 영향을 받지 않으며 따라서 크래시 복구는 변수 값에 상관없이  실행된다. 대대수의 os와 몇몇 디스크들은 디스크에 대한 플러시 연산을 제대로 실행하지 못한다는 점을 알아두자.


innodb_flush_method             = O_DIRECT # 더블 버퍼링을 막아줌. (성능을 위해 메모리에서 직접 액세스하도록 한다면 O_DSYNC 를 사용)

innodb_force_recovery           = 0 # 크래쉬 복구 모드 설정 ( http://head1ton.tistory.com/entry/InnoDB-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%86%90%EC%83%81%EA%B9%A8%EC%96%B4%EC%A7%84%EC%8B%9C-%EA%B0%95%EC%A0%9C-%EB%B3%B5%EA%B5%AC )

innodb_lock_wait_timeout        = 60 # 롤백이 진행되기 전에 LOCK을 대기하는 시간(초)

innodb_log_buffer_size          = 16M # Redo 로그 버퍼크기 

innodb_log_file_size            = 1G # 로그 파일 사이즈로 버퍼풀 사이즈의 25% 정도로 설정

innodb_log_files_in_group       = 2 # 로그 파일 그룹

innodb_log_group_home_dir       = /wemade/database/data

#innodb_log_arch_dir = /wemade/database/data # 로그 디렉토리 정보

innodb_max_purge_lag            = 0   

innodb_support_xa               = OFF # 트랜잭션 two-phase commit(분산데이터 기능) 지원, 디스크 플러시 횟수를 줄여 성능향상

innodb_table_locks              = 1 # LOCK TABLES 는 autocommit = 0 경우에 innodb로 하여금 내부적으로 테이블을 잠금

innodb_thread_concurrency       = 0 # innodb 내에 쓰레드 갯수, 변수 0은 쓰레드 간 동시성 비활성화 (core * 2로 설정?)

innodb_thread_sleep_delay       = 1000 # thread가 queue에 들어오기 전에 innodb 쓰레드가 일시 정지(sleep)하는 시간

innodb_fast_shutdown = 0 # 0은 shutdown 전에 full purge와 buffer merge, 1은 내부적 수행(메모리 구조 정리, 인덱스 버퍼정리 작업)을 skip, 2는 log만 flush하고

# shutdown-mysql이 깨지고  커밋되지 않은 트랜잭션은 잃어버림.


## MyISAM Option -----------------------------------------------------------------------------

## Even if you're not using MyISAM tables, you should still set it to 8-64M as it will also be

## used for internal temporary disk tables.

## If you use MYISAM, you can set still key_buffer_size=4GB(max)

key_buffer_size                 = 32M # index 블록을 위해 사용되는 buffer 크기

bulk_insert_buffer_size         = 32M # myisam이 빠른 대량 insert를 하기 위한 size, 쓰레드 당 각각 할당됨

myisam_sort_buffer_size         = 1M # repair, index, alter 정렬에 사용되는 메모리

myisam_max_sort_file_size       = 1G # repair, alter load 등 index 재생성 시 사용되는 임시 파일 크기

myisam_repair_threads           = 1 # 정렬 복구 시 사용될 쓰레드 갯수

myisam_recover # myisam 테이블을 열었을 시 테이블 자동 복구

ft_min_word_len                 = 3 # 하나의 fulltext 인덱스에 포함되는 단어의 최소 길이 값. 변경 후 repair table tbl_name QUICK 으로 재 구축해야함.



## Logging Option -----------------------------------------------------------------------------

pid-file                        = /wemade/database/data/mysqld.pid

log-warnings                    = 1

log-error                       = /wemade/database/data/mysqld



## "SET GLOBAL general_log = 1" (true)

#general_log                     = 1

#general_log_file                = /wemade/database/data/mysqld


log_slow_admin_statements # DDL쿼리도 슬로우 쿼리에 기록

slow-query-log                  = 1

long_query_time                 = 1

slow_query_log_file             = /wemade/database/data/slow_query.log

log-output = FILE



### Replication Option ------------------------------------------------------------------------

## Master Server

log-bin                       = /wemade/database/binlog/mysql-master-bin

binlog_cache_size             = 128K

max_binlog_size               = 512M  

expire_logs_days               = 15    

log-bin-trust-function-creators = 1

sync_binlog                   = 1

binlog_format = mixed

binlog-ignore-db = information_schema

binlog-ignore-db = performance_schema

binlog-ignore-db = mysql

binlog-ignore-db = test




## Slave Server

# relay-log                     = /wemade/database/binlog/relay_log

# relay_log_purge               = TRUE  

# read_only



## Slave Server = Master Server

## This option tells the slave to log the updates performed by its SQL thread to its own binary log

# log-slave-updates




## ---------------------------------------------------------------------------------------

## [CLIENT] MySQL Common Client Configuration

## ---------------------------------------------------------------------------------------


[client]

socket                          = /tmp/mysql.sock

port                            = 3306  



## ---------------------------------------------------------------------------------------

## [MYSQL CLIENT] MySQL Command line client(mysql) Configuratin

## ---------------------------------------------------------------------------------------


[mysql]

default-character-set = utf8

no-auto-rehash # 자동 완성 기능 비활성화

show-warnings # 경고 발생시 메세지 자동 출력

prompt=\d\_\R:\m:\\s> # SQL 프롬프트 설정

#pager="less -n -i -F -X -E" # 데이터  출력시 페이징처리


반응형
반응형
MyISAM과 달리 InnoDB 테이블들은 매우 안정적이며, 왠만해서는 데이터 파일이 깨어지는 경우는 거의 경험하지 못했다.
하지만, 데이터 파일이 깨어진다면 어떻게 해야 할까 ?. DBMS 벤더를 불문하고 손상된(깨어진) 데이터 파일을 복구한다는 것은 쉽지 않은 문제이며 위험도 크다.
이런 비 정상적인 현상은 어느 DBMS에서나 발생할 수 있는 현상이며, 이를 위해서 우리는 데이터베이스를 그렇게 열심히 백업하고 있었던 것이다.
만약, 백업마저도 복구가 안 된다면, 결국 지금의 깨어진 데이터 파일이라도 어떻게든 복구를 해야 한다.
하지만, InnoDB myisamchk와 같은 별도의 복구 도구를 제공하지 않는다.
손상된 InnoDB 테이블의 복구는 우선 MySQL을 기동시켜서 데이터를 덤프(mysqldump, SELECT INTO OUTFILE…)를 받는 것이 유일한 방법이다.
하지만, InnoDB Boot-up 과정에서 여러 가지 체크 및 정리 작업들을 하게 되는데, 이 중에서 하나라도 문제가 있을 경우 시작이 되지 않는다. (MySQL이 시작도 안 되는데 어떻게 덤프를 받지? ㅠㅠ)
그래서 MySQL의 설정 옵션 중에서 "innodb_force_recovery" 라는 설정 변수를 제공하고 있다
아래와 같이 MySQL의 설정 파일(my.cnf, my.ini)에 설정하면, 이 설정 값에 의해서 InnoDB에게 어떤 체크나 정리 작업을 건너뛰어야 할지를 알려 줄 수 잇다.

## 0 ~ 6까지의 값 중에서 하나를 설정 (0은 정상 상태인 경우이며 그 이상의 경우 강제 복구모드에 해당됨)
innodb_force_recovery = 1


기본 설정 값은 "0" 인데, 이는 InnoDB에게 모든 체크와 정리 작업을 정상적으로 실행하도록 명령하는 것이다.

그 이외의 설정 값은 모두 비 정상적인 상황을 위한 설정 값이며, 일반적인 서비스 환경에서는 사용하면 안 된다.
또한 "0"이 아닌 그 이외의 값을 설정하게 되면, InnoDB는 복구 모드라고 가정하고 SELECT 이외의 데이터를 변경하는 SQL들은 모두 처리를 거절해 버린다.


각 설정값별 복구 내용과 방식을 간단히 살펴보자. 

·         1 ( SRV_FORCE_IGNORE_CORRUPT )
데이터 파일의 손상된 페이지가 발견되어도 무시하고 MySQL을 기동시킨다.  일단 MySQL이 기동되면, SELECT * FROM tbl_name; 명령문을 실행하여 데이터를 덤프하여 다시 적재하거나 다른 데이터베이스로 이전하는 것이 좋다. 이 때, 손상된 인덱스 레코드와 페이지는 모두 건너뛰게 된다. (, 무시해 버리므로 데이터를 잃게 된다.)
에러 로그 파일에 "Database page corruption on disk or a failed "라고 출력되는 경우, 대부분 이 케이스인데 이는 테이블 스페이스의 페이지가 손상되어서 발생하는 문제이다. 이 경우에는 이 모드로 MySQL의 기동 후, mysqldump SELECT INTO OUTFILE...을 이용하여 덤프 및 재 적재가 가능하다.

·         2 ( SRV_FORCE_NO_BACKGROUND )
InnoDB의 여러 가지 Background thread들 중에서 Main thread를 시작하지 않고 MySQL을 기동시킨다. InnoDB의 경우 트랜잭션과 동시성 향상(MVCC)을 위해서 Undo 정보를 보존하게 되는데,  Undo 정보는 변경되기 전 데이터를 가지게 된다. 이러한 Undo 정보는 여러 가지 상황에 맞춰서 적절한 시점에 삭제가 되어야 하는데 이 작업을 Main thread가 처리한다 (이 작업을 Purge라고도 부른다.). 그런데 만약 MySQL의 시작 과정에서 InnoDB가 이러한 Purge 작업 중 오류를 발생시킨다면, MySQL의 기동 시에 Main thread를 시작시키지 않기 때문에 Purge작업 중의 오류를 피할 수 있게 되므로, 일단 MySQL을 시작시킬 수는 있게 된다. Undo 정보는 InnoDB의 시스템 테이블 스페이스에 관리되기 때문에, 이 경우에는 전체 데이터베이스를 덤프 받은 후 다시 MySQL 서버를 구성해야 한다.

·         3 ( SRV_FORCE_NO_TRX_UNDO )
MySQL을 종료하던 시점에 만약 진행 중인 트랜잭션이 있었다면, MySQL은 그냥 단순히 그 Connection을 강제로 끊어 버리게 된다. 그 이후 별도의 정리 작업은 진행하지 않게 된다.  MySQL은 종료되었지만, 진행 중이던 트랜잭션의 정리 작업은 하지 않게 되는 것이다. MySQL이 다시 시작하게 되면, InnoDB 엔진은 트랜잭션 로그(Redo log라고도 함)를 읽어서 다시 처리 해주고(이 작업을  Roll forward라고 함), 최종적으로 어떤 트랜잭션이 완료되지 않고 Connection이 종료되었는지 판단 후, 그 트랜잭션들은 InnoDB 엔진이 Rollback을 시키게 되는데,만약 Undo 영역이나 다른 관련된 데이터들이 손상된 경우에는 Rollback 처리를 해줄 수 없게 되는데, 이 경우에 사용하는 복구 모드이다.이 경우에는 사실은 Rollback되어야 하지만, 실제 데이터 파일에는 그 데이터가 남아 있을 수 있다. (이 부분은 Binary log Application의 로그를 통해서 수동으로 보완해 주거나 무시하는 방법밖에 없다.)

·         4 ( SRV_FORCE_NO_IBUF_MERGE )
MySQL InnoDB INSERT, UPDATE, DELETE 등의 데이터 변경 작업으로 발생하는 인덱스 변경 작업들을 상황에 따라서 즉시 실행할 수도 또는 나중에 처리하도록 지연시킬 수 도 있다. 이렇게 나중에 처리하도록 지연시키기 위해서는 변경 내용을 어딘가에 기록해 두어야 하는데,그 용도로 사용되는 버퍼가 "Insert Buffer"이다.  Insert Buffer의 내용은 언제 데이터 파일에 병합(Merge)될지 알 수 없다. MySQL을 종료해도 병합되지 않을 수 있는데, 만약 MySQL이 재 시작 되면서 Insert Buffer의 손상을 감지하게 되면 Insert Buffer의 병합 작업이 실패하고 MySQL이 기동하지 못하게 된다. 이 경우 사용할 수 있는 강제 복구 모드이다. (이 경우에는 테이블 통계 정보 갱신을 유발하는 작업들을 해서는 안 된다. 주로 DDL이나 ANALYZE 명령 등). Insert Buffer는 실제 데이터와 관련된 부분이 아니라 인덱스에 관련된 부분이라 테이블을 덤프 후 다시 적재하면 처리될 수도 있고, 아니면 단순히 "ALTER TABLE tbl_name ENGINE=InnoDB;" 명령만으로 해결될 수도 있다.

·         5 ( SRV_FORCE_NO_UNDO_LOG_SCAN )
복구 모드 3 ( SRV_FORCE_NO_TRX_UNDO )의 처리와 비슷하며, 이 모드에서는 Undo 로그를 완전히 무시하고 완전히 종료되지 않은 트랜잭션(COMMIT/ROLLBACK되지 않은)을 모두 COMMIT된 것으로 처리해 버린다.  또한 이 모드에서는 Undo 로그를 전혀 참조하지 않는 형태로 강제 복구 시킨다.

·         6 ( SRV_FORCE_NO_LOG_REDO )
이것은 MySQL 서버가 재 시작되기 전 가장 뒤에 발생한 체크 포인트 이후의 모든 트랜잭션을 버리고 복구 시키는 모드이다. 당연히 Redo로그를 참조하지 않으므로 Roll forward라는 작업도 하지 않고 강제 복구시키게 된다. Redo 로그가 손상된 경우 이 모드로 강제 복구가 가능하다.

여기서 설명된 강제 복구 모드는 그 설정 값이 높아질수록 손실되는 데이터가 많아지기(복구 가능한 데이터가 적어지기) 때문에, 가능한 강제 복구 모드를 낮은 것(1 -> 2 -> 3 -> 4 -> 5 -> 6)부터 시도해 볼 것을 추천한다.

아래 내용은 HighPerformanceMySQL 블로그에서 발췌한 내용을 번역한 것인데, 같이 참조하면 좋을 듯 하다.
InnoDB 테이블이 손상되는 경우는 상당히 희박
Double write, Checksum 그리고 기타 Validation 로직들과 버그 보완으로 인해서, 실제로 MyISAM에 비해서 InnoDB 테이블 스페이스 및 데이터 파일은 상당히 안정적이다.

대부분의 손상은 인덱스에서 발생
많은 사람들이 경험하는 InnoDB 데이터 파일의 손상은 80~90% 정도가 InnoDB 인덱스 (Secondary index)에 발생한 손상인 경우이며, 이 경우에는 단순히 ALTER TABLE 또는 데이터 덤프 및 재 적재만으로 해결된다. 복구 모드 "1 ( SRV_FORCE_IGNORE_CORRUPT )" 참조.

이 이외의 InnoDB 테이블의 문제점들의 경우는 덤프 및 적재
이 이외의 복잡한 형태의 장애에 대해서는, (아주 심한 경우가 아니라면)데이터베이스 전체를 덤프하고 다시 적재하는 것으로 해결될 수 있다. 하지만, 가장 최근의 백업에 Binary log Replay (재 실행)해주는 것보다 빠를지는 상황을 적절히 판단해서 결정하는 것이 좋을 듯 하다.


이래도 저래도 안 되는 경우에는(대표적으로 InnoDB의 시스템 테이블 스페이스가 손상된 경우) 아래 URL의 도구를 참조하는 것도 도움이 될 수 있을 듯 하다.
(사용해 본 경험이 없어서, 얼마나 작동할지는 잘 모르겠다.)



출처 : http://intomysql.blogspot.kr/2010/12/innodb_3017.html


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

프로시저 처리  (0) 2014.12.08
my.cnf  (0) 2014.12.08
mysql> show status  (0) 2014.12.03
MySQL 테이블 데이터 암호화  (0) 2014.11.27
일렬로 된 데이터를 5줄로 정렬하여 데이터를 조회하는 방법  (0) 2014.11.27
반응형

Aborted_clients
클라이언트가 비정상으로 종료한 접속 건수
Aborted_connects
접속을 시도했으나 실패한 건수
Bytes_received
모든 클라이언트로부터 받은 바이트 수
Bytes_sent
모든 클라이언트에게 보낸 바이트 수
Com_xxx
xxx 명령이 실행된 횟수
Connections
서버로 접속을 시도한 횟수
Created_tmp_disk_tables
디스크에 만들어진 임시 테이블 수
Created_tmp_tables
메모리에 만들어진 임시 테이블 수
Created_tmp_files
mysqld가 만든 임시 파일 수
Delayed_insert_threads
사용중인 delayed insert handler의 스레드 수
Delayed_writes
insert delayed로 기록된 row의 수
Delayed_errors
insert delayed로 기록할 때 에러가 발생한 row의 수
Flush_commands
Flush 명령이 실행된 횟수
Handler_commit
내부적으로 commit한 횟수
Handler_delete
row가 테이블에서 삭제된 횟수
Handler_read_first
첫 엔트리가 인덱스에서 읽혀진 횟수
즉, full index scan 횟수
Handler_read_key
key에 의해서 row가 읽히도록 요청받은 횟수
수치가 높으면 잘 인덱스 되었음을 의미
Handler_read_next
key order로 다음 row를 읽도록 요청받은 횟수
index scan, 제약된 범위로 index column을 질의하면 증가함
Handler_read_prev
key order로 앞 row를 읽도록 요청받은 횟수
즉, order by...desc를 사용한 횟수
Handler_read_rnd
지정한 위치로부터 row를 읽도록 요청 받은 횟수
즉, 소팅한 횟수
Handler_read_rnd_next
데이터 파일에서 다음 row를 읽도록 요청 받은 횟수
즉, 테이블 scan의 횟수로 테이블이 적절하게 인덱스 되어 있지 않음을 가리킴
Handler_rollback
내부적으로 rollback한 횟수
Handler_update
테이블에서 row의 갱신을 요청 받은 횟수
Handler_write
테이블에서 row에 insert를 요구한 횟수
Key_blocks_used
key cache에서 사용된 block의 수
Key_read_requests
cache로부터 key block을 읽도록 요청받은 횟수
Key_reads
디스크에서 key block를 실제로 읽은 횟수
Key_write_requests
cache에 key block을 기록하도록 요구한 횟수
Key_writes
디스크에 key block을 실제로 기록한 횟수
Max_used_connections
동시에 사용토록 허용된 최대 접속 수
Not_flushed_key_blocks
변경된 것이 디스크에 flush되지 않은 key cache의 key block 수
Not_flushed_delayed_rows
insert delay에 의해서 아직 기록되지 않고 기다리는 row의 수
Open_tables
open되어 있는 테이블의 수
Open_files
open되어 있는 파일의 수
Open_streams
open되어 있는 stream의 수(주로 logging에 사용)
Opened_tables
열어본 테이블의 수
Questions
서버에 질의를 보낸 횟수
Qcache_queries_in_cache
0
Qcache_inserts
0
Qcache_hits
0
Qcache_lowmem_prunes
0
Qcache_not_cached
0
Qcache_free_memory
0
Qcache_free_blocks
0
Qcache_total_blocks
0
Rpl_status
안전조치 복제 상태
Select_full_join
key 없이 join한 횟수(0이 아니면, 테이블의 인덱스를 검토요망)
Select_full_range_join
참조 테이블에서 range search로 join한 횟수
Select_range
첫 테이블에서 range를 사용하여 join한 횟수
Select_range_check
key 없이 join한 횟수(0이 아니면, 테이블의 인덱스를 검토요망)
Select_scan
첫 테이블중 full scan한 곳에서 join한 횟수
Slave_open_temp_tables
slave가 현재 열고 있는 임시 테이블 수
Slave_running
ON이면 master에 접속한 slave가 있음
Slow_launch_threads
create시 slow_launch_time보다 더 걸린 스레드의 수
Slow_queries
long_query_time보다 더 시간이 걸린 질의의 수
Sort_merge_passes
sort 알고리즘을 통과한 merge의 수
값이 크면 sort_buffer의 증가를 고려해야함
Sort_range
range 내에서 소팅한 수
Sort_rows
소팅한 row의 수
Sort_scan
테이블을 스캔닝하여 소팅한 수
ssl_xxx
SSL이 사용한 변수
Table_locks_immediate
테이블 lock이 직접 요구된 횟수
Table_locks_waited
테이블 lock이 기다려야 했던 횟수
수치가 크면, 퍼포먼스에 문제 있으므로 optimize요망
Threads_cached
thread cache에 있는 스레드의 수
Threads_created
접속을 유지하기 위해서 만들었던 스레드의 수
Threads_connected
현재 열려서 접속되어 있는 스레드 수
Threads_running
sleeping하지 않고 작동중인 스레드의 수
Uptime
서버의 작동 시간(초)


위 변수에서
 Opened_tables가 크면, 
    table_cache 변수는 작을 수 있다..
 Key_reads가 크면,  
    key_buffer_size는 작을 수 있다.
 Handler_read_rnd가 크면, 
    더 많은 쿼리를 한다.
 Thread_created가 크면,   
    thread_cache_size를 크게해야 될지도 모른다.
 Created_tmp_disk_tables가 크면, 
    tmp_table_size를 크게 해야 될지도 모른다.

[출처] mysql> show status|작성자 만박



반응형
반응형

1. 데이터 암호화 방식
   1) 단방향 암호화
       MD5, SHA1 같은 방법으로 암호화(Encrypt) 후 원래대로 복호화(Decrypt)가 필요 없는 경우
       예) 패스워드, 주민번호(복호화 불필요시)등
   2) 쌍방향 암호화
       DES, DES3, ENC, COMPRESS 같은 방법으로 암호화(Encrypt) 후 원래대로 복호화(Decrypt)가 필요한 경우
       예) 이름, 아이디, 주민번호(나이계산, 생일), 메일주소, 주소, 닉네임, 나이, 생일

 

2. MySQL에서 지원하는 암호화 함수
   1) 쌍방향 암호화 (암호화, 복호화) 지원
       ▶ AES_ENCRYPT, AES_DECRYPT

 drop table member_info;
 create table member_info
 (user_id varbinary(16) primary key, 
 passwd varbinary(100),
 age    int,
 sex    int
 );

 insert into member_info values('themade', hex(aes_encrypt('themade','aaaa')), 32, 1)
                             ,('swpark', hex(aes_encrypt('swpark','aaaa')), 24, 1);

 select * from member_info;

 select AES_DECRYPT(UNHEX(passwd), 'aaaa') as passwd 
 from member_info;

 

       ▶ DES_ENCRYPT, DES_DECRYPT (해당 암호화는 mysql 설정 시, --with-ssl을 추가해 줘야 실행할 수 있다.)

 drop table member_info2;
 create table member_info2
 (user_id varbinary(16) primary key, 
 passwd varbinary(100),
 age    int,
 sex    int
 );

 insert into member_info2 values('themade', DES_ENCRYPT('themade','aaaa'), 32, 1)
                                            ,('swpark', DES_ENCRYPT('swpark','aaaa'), 24, 1);

 select * from member_info2;

 select DES_DECRYPT(passwd, 'aaaa') as passwd from member_info2;

 

       ▶ DECODE, ENCODE

 drop table member_info3;
 create table member_info3
 (user_id varbinary(16) primary key, 
 passwd varbinary(100),
 age    int,
 sex    int
 );

 insert into member_info3 values('themade', ENCODE('themade','aaaa'), 32, 1)
                              ,('swpark', ENCODE('swpark','aaaa'), 24, 1);
                              
 select * from member_info3;

 select DECODE(passwd, 'aaaa') as passwd from member_info3;

 

       ▶ COMPRESS, UNCOMPRESS

 

   2) 단방향 암호화 지원

       ▶ MD5, SHA

 drop table member_info;
 create table member_info
 (user_id varbinary(16) primary key, 
 passwd varbinary(100),
 age    int,
 sex    int
 );

 insert into member_info values('themade', md5('themade'), 32, 1)
                             ,('swpark', sha('swpark'), 24, 1);

 select * from member_info;

 

       ▶ password, old_password

           MySQL 내의 함수로 password함수는 5.1부터 나온 함수이고, 5.1에서는 이전 password 함수를 old_password라고 한다.

           4.0에서 사용하던 password함수가 5.1까지는 old_password로 변경이 되었는데 5.5부터는 old_password조차 지원하지

           않는다. 해당 mysql 테이블 권한을 주었다면 상관없지만 해당 함수로 서비스에서 사용하는 패스워드로 적용하지 않는 것이

           좋다.

 drop table member_info;
 create table member_info
 (user_id varbinary(16) primary key, 
 passwd varbinary(100),
 age    int,
 sex    int
 );

 insert into member_info values('themade', password('themade'), 32, 1)
                             ,('swpark', password('swpark'), 24, 1);

 select * from member_info;

 

3. 암호화 과정에서의 주의사항

    ▶ MySQL 테이블 암호화는 암호화하는 과정에서 CPU도 많은 부분 사용하기 때문에 기존에 있는 컬럼을 암호화시 서버에 부하가

        되는지 먼저 테스트해보아야 한다.

    ▶ 암호화의 데이터 길이를 고려하여 컬럼 길이와 타입을 변경해야 한다.

        잘못하면 암호화 시킨 데이터가 입력이 안되는 경우가 발생할 수도 있다.

    ▶ TEST 서버에서 충분한 테스트를 진행해야 한다.

 

4. 문제 발생시 빠른 테이블 전환

 // 데이터 백업
 create table member_info_old_20131111
 select * from member_info;

 // 테이블명 변경
 drop table member_info;
 alter table member_info_old_20131111 rename to member_info;

 


반응형
반응형

CREATE TABLE Code_Column (code varchar(10));


INSERT INTO Code_Column VALUES

('0001'),('0002'),('0003'),('0004'),('0005'),('0006'),('0007'),('0008'),('0009'),('0010'),

('0011'),('0012'),('0013'),('0014'),('0015'),('0016'),('0017'),('0018'),('0019'),('0020'),

('0021'),('0022'),('0023'),('0024'),('0025'),('0026'),('0027'),('0028'),('0029'),('0030'),

('0031'),('0032'),('0033'),('0034'),('0035'),('0036'),('0037'),('0038'),('0039'),('0040');


SELECT * FROM Code_Column;



SELECT

    MAX(CASE seq MOD 5 WHEN 0 THEN code ELSE NULL END) code1,

    MAX(CASE seq MOD 5 WHEN 1 THEN code ELSE NULL END) code2,

    MAX(CASE seq MOD 5 WHEN 2 THEN code ELSE NULL END) code3,

    MAX(CASE seq MOD 5 WHEN 3 THEN code ELSE NULL END) code4,

    MAX(CASE seq MOD 5 WHEN 4 THEN code ELSE NULL END) code5

FROM

    (SELECT (@seq := @seq + 1) as seq, code FROM Code_Column, (SELECT @seq := -1) x ) y

GROUP BY seq DIV 5;




select case when tmp.seq = 1 then code else '' end as code1,

         case when tmp.seq = 2 then code else '' end as code2,

         case when tmp.seq = 3 then code else '' end as code3,

         case when tmp.seq = 4 then code else '' end as code4,

         case when tmp.seq = 5 then code else '' end as code5,

   case when @y < 5 then @z else @z := @z + 1 end as seq, 

   case when @y >= 5 then @y := 1 else @y := @y +1 end as seq2

from (

select code, 

case when @x <5 then @x:= @x+ 1 

else @x :=1 

end as seq

from Code_Column i, (select @x := 0) x1

) tmp, (select @z:=1, @y := 0) y1





select max(code1) as code1, max(code2) as code2, max(code3) as code3

     , max(code4) as code4, max(code5) as code5

from

 (select case when tmp.seq = 1 then code else '' end as code1,

         case when tmp.seq = 2 then code else '' end as code2,

         case when tmp.seq = 3 then code else '' end as code3,

         case when tmp.seq = 4 then code else '' end as code4,

         case when tmp.seq = 5 then code else '' end as code5,

   case when @y < 5 then @z else @z := @z + 1 end as seq, 

   case when @y >= 5 then @y := 1 else @y := @y +1 end as seq2

 from (select code, case when @x <5 then @x:= @x+ 1 else @x :=1 end as seq

       from Code_Column i, (select @x := 0) x1) tmp, (select @z:=1, @y := 0) y1

) tmp1 

group by seq;



반응형
반응형

CREATE TABLE Code_Row (

idx int not null auto_increment,

code1 varchar(10) not null,

code2 varchar(20) not null,

code3 varchar(30) not null,

code4 varchar(30) not null,

code5 varchar(30) not null,

primary key (idx)

) engine=innodb charset=utf8mb4;


insert into Code_Row (code1, code2, code3, code4, code5) Values 

('0001', '0002', '0003', '0004', '0005'), ('0006', '0007', '0008', '0009', '0010')

, ('0011', '0012', '0013', '0014', '0015'), ('0016', '0017', '0018', '0019', '0020')

, ('0021', '0022', '0023', '0024', '0025'), ('0026', '0027', '0028', '0029', '0030')

, ('0031', '0032', '0033', '0034', '0035'), ('0036', '0037', '0038', '0039', '0040');


select * from Code_Row;



select code1, @x1 := @x1 + 1 as seq1,

code2, @x1 := @x1 + 1 as seq2,

code3, @x1 := @x1 + 1 as seq3,

code4, @x1 := @x1 + 1 as seq4,

code5, @x1 := @x1 + 1 as seq5

from Code_Row, (select @x1 := 0) x1



CREATE TABLE seq_num (num int not null auto_increment, primary key (num));


delimiter //

create procedure `num_sp` ()

begin


declare idx int default 1;

while idx < 51 do

insert into seq_num values (idx);

set idx = idx + 1;

end while;


end //

delimiter ;


call num_sp();



select * from seq_num;


explain

select if(x.seq1 = y.num, code1, '') as code1,

if(x.seq2 = y.num, code2, '') as code2,

if(x.seq3 = y.num, code3, '') as code3,

if(x.seq4 = y.num, code4, '') as code4,

if(x.seq5 = y.num, code5, '') as code5

from (

select code1, @x1 := @x1 + 1 as seq1,

code2, @x1 := @x1 + 1 as seq2,

code3, @x1 := @x1 + 1 as seq3,

code4, @x1 := @x1 + 1 as seq4,

code5, @x1 := @x1 + 1 as seq5

from Code_Row, (select @x1 := 0) x1

) x inner join seq_num y

on x.seq1 = y.num or x.seq2 = y.num or x.seq3 = y.num or x.seq4 = y.num or x.seq5 = y.num




select concat(code1, code2, code3, code4, code5) as code

from (

select if(x.seq1 = y.num, code1, '') as code1,

if(x.seq2 = y.num, code2, '') as code2,

if(x.seq3 = y.num, code3, '') as code3,

if(x.seq4 = y.num, code4, '') as code4,

if(x.seq5 = y.num, code5, '') as code5

from (

select code1, @x1 := @x1 + 1 as seq1,

code2, @x1 := @x1 + 1 as seq2,

code3, @x1 := @x1 + 1 as seq3,

code4, @x1 := @x1 + 1 as seq4,

code5, @x1 := @x1 + 1 as seq5

from Code_Row, (select @x1 := 0) x1

) x inner join seq_num y

on x.seq1 = y.num or x.seq2 = y.num or x.seq3 = y.num or x.seq4 = y.num or x.seq5 = y.num

) t

where code1 is not null

and code2 is not null

and code3 is not null

and code4 is not null

and code5 is not null;

반응형
반응형

MySQL 5.6 내에 InnoDB는 프러싱 작업을 수행하기 위한 전용쓰레드(page_cleaner)를 가지고 있다.

In MySQL 5.6 InnoDB has a dedicated thread (page_cleaner) that’s responsible for performing flushing operations.

 

Page_cleaner는 두가지 사실에 근거하여 버퍼풀로부터 더티 페이지의 플러싱을 수행한다.

Page_cleaner performs flushing of the dirty pages from the buffer pool based on two factors:

더티   : InnoDB 버퍼풀에 변경된 데이터

플러싱 : 더티 데이터를 디스크로 영구히 기록하는 작업

 

- access pattern – 가장 최근에 사용된 페이지들은 버퍼풀이 더 이상 프리 페이지를 가지지 못할 때 LRU List로부터 LRU flusher에 의해 플러시 되어 진다.

- access pattern  -  the least recently used pages will be flushed by LRU flusher from LRU_list when buffer pool has no free pages anymore;

- age – 가장 오래 전에 수정된 플러시되지 않은 페이지들은 flush_list 구조의 일부이며 여러가지 추론의 근거하여 flush_list flusher에 의해 플러시 된다.

- age – the oldest modified non-flushed pages are part of flush_list structure and will be flushed by flush_list flusher based on several heuristics.

 

LRU_list flusher

 

           MRU(Most Recently Used)          LRU(Least Recently Used)

<---------------------------------------------------><------------------------->

0%                                         62.5%                 100%

자주 사용되는 페이지들을 모아둔 곳           최근 사용된 페이지들을 모아둔 곳

 

innodb_old_blocks_pct 시스템 변수의 값을 변경해서 MRU LRU의 기준점을 변경할 수 있다.

 

Flush_list flusher

RDBMS의 리구 로그 작동 방식(Write Ahead Log) 특성상 리두 로그와 더티 페이지 중에서 항상 리두 로그가

먼저 디스크로 플러시되어야 한다. 그리고 InnoDB 버퍼 풀에서 더티 페이지가 디스크로 완전히

플러시되어야만 그 더티 페이지와 연관을 가지고 있던 리두 로그 슬롯이 재사용될 수 있다.

이때 버퍼 풀에서 더피 테이지들을 빠르게 찾도록 하기 위해서 더티 페이지들의 변경 시간 순서대로 목록을

관리하는데 이를 Flush_List 라고 한다.

 

Page_cleaner에 대한 개요이며 MySQL 5.6내에 플러싱에 대한 몇 가지 세부적인 사실을 여기서 찾아볼 필요가 있다.  아래에 나는 아직 적용하기 않은 플러시_list의 여러가지 추가 요소를 설명하였다.

There is a good overview of the page_cleaner and also here you may find some details about flushing in MySQL 5.6. Below I describe several additional aspects of the flush_list flushing that was not really covered yet.

 

 

flush_list flushing and checkpoint age

flush_list의 유지하기 위해 가능한 세 페이지들의 양은 innodb log 파일의 조합된 사이즈에 의해 제한 되어진다.

The amount of the aged pages that is possible to keep in the flush_list is limited by the combined size of the innodb log files.

 

그래서 flush_list 플러싱의 주 목적은 항상 로그 파일에 충분한 여유 공간을 허용하는 비율로 페이지(더티페이지)를 플러싱하는 것이다.

So the main purpose of the flush_list flushing is to flush pages from this list with such a rate that will also always allow enough free space in the log files.

 

반면에 너무 공격적인 플러싱은 덜된 읽기 조합, I/O 서브시스템에 대한 불필요한 로그, 너무 큰 리두 로그의 최종 실행 취소 성능상의 이점이다.

On the other hand, too aggressive flushing means less write combining, unnecessary load on the I/O subsystem, in the end undoing performance benefits of having larger redo logs.

 

MySQL 5.6에서는 플러시하기 위한 페이지의 양은 공식에 따라 현재 checkpoint age를 근거로 적용된 루틴에 따라 InnoDB내에서 계산되어졌다.

In MySQL 5.6 the amount of pages to flush is calculated in the InnoDB adaptive routine based on the current checkpoint age with the following formula:

 

InnoDB에서는 마지막 체크포인트가 발생한 시점의 리두 로그 위치(LSN, log sequence number)에서부터 마지막리두 로그 슬롯의 위치까지의 길이를 체크포인트 에이지(checkpoint age)라고 한다. 체크포인트 에이지가 중요한

이유는 InnoDB 모두 리두 로그의 전체 공간 크기의 체크포인트 에이지의 길이를 이용해서 플러시를 실행해야 할

더티 페이지의 개수를 결정하기 때문이다.

또한, 체크포인트 에이지가 얼마나 되는지에 따라서 InnoDB의 쿼리가 일부만 블로킹되거나 전부 블로킹 될 수도

있기 때문이다.

 

flush_list flushing and io_capacity

InnoDB는 백그라운드 플러싱 비율을 컨트롤하는 것을 허용하는 두가지 변수를 제공한다.

( innodb_io_capacity innodb_io_capacity_max )

 

- innodb_io_capacity_max는 실제로 플러싱 비율을 제한하는 것으로 적용하는 플러싱인 경우 가장 중요한 변수이다.

- innodb_io_capacity_max is the most important variable in case of adaptive flushing as only that variable actually limiting the flushing rate.

 

innodb_io_capacity_max

InnoDB에 대해 긴급한 경우 innodb_io_capacity로 값을 늘리는 것은 허용되지만 최대값을 제한한다.

The limit up to which InnoDB is allowed to extend the innodb_io_capacity setting in case of emergency.  

 

만약 당신은 mysql 시작시 innodb_io_capacity를 지정하고 innodb_io_capacity_max값을 지정하지 않았다면, innodb_io_capacity의 두배가 디폴트가 된다. 2000을 넘지는 않는다.

If you specify an innodb_io_capacity setting at startup and do not specify a value for innodb_io_capacity_max, the innodb_io_capacity_max value defaults to twice the value of innodb_io_capacity, with a lower limit of 2000.

 

2000 innodb_io_capacity_max 설정값의 초기 값이다.

2000 is also the initial default innodb_io_capacity_max configuration value.

 

Innodb_io_capacity_max는 모든 버퍼풀 인스턴스들에 대한 총 제한값이다.

The innodb_io_capacity_max setting is a total limit for all buffer pool instances.

 

- innodb_io_capacity는 서버비활성화/셧다운의 경우에 인서버버퍼의 병합과 플러싱하는 동안 IO동작을 제한하기

위해 사용되어졌다.

- innodb_io_capacity is used for limiting IO operations during merging of the insert buffer and flushing in cases of server inactivity/shutdown.

innodb_io_capacity

기본값은 200이다. The default value is 200.

 

Innodb_io_capacity 매개변수는 인서트버퍼로부터 데이터를 머징하고 버퍼풀로부터 페이지를 플러싱하는 거와 같이 InnoDB 백그라운드에 의해 수행되는 I/O 활성화는 제한을 설정할 수 있다.

The innodb_io_capacity parameter sets an upper limit on the I/O activity performed by the InnoDB background tasks, such as flushing pages from the buffer pool and merging data from the insert buffer.

 

높은 I/O 비율을 보이는 바쁜 시스템의 경우, 당신은 서버 스타트업에서 높은 값을 설정할 수 있다.

(서버는 행 변경의 높은 비율과 관련된 백그라운드 유지보수 작업을 처리하기 위해)

For busy systems capable of higher I/O rates, you can set a higher value at server startup, to help the server handle the background maintenance work associated with a high rate of row changes.

 

각각의 5400 RPM 또는 7200 RPM 드라이브로 구성된 시스템에서는 당신은 100보다 낮은 값으로 기본값을 해야 한다.

For systems with individual 5400 RPM or 7200 RPM drives, you might lower the value to the former default of 100.

 

이 매개변수는 시스템이 초당 수행  수있는 I / O 동작의 대략 값으로 설정되어야 한다.

This parameter should be set to approximately the number of I/O operations that the system can perform per second.

 

일반적으로, 부분적으로 빠른 드라이브 능력을 요구한다면 InnoDB I/O로 사용되는 드라이버에 대해 이 변수값을 증가시킬 수 있다.

In general, you can increase the value as a function of the number of drives used for InnoDB I/O, particularly fast drives capable of high numbers of IOPS.

 

예를 들어, 다수의 디스크나 SSD에 대한 InnoDB 시스템은 이 매개변수를 조절하여 이득을 볼 수 있다.

For example, systems that use multiple disks or solid-state disks for InnoDB are likely to benefit from the ability to control this parameter.

 

innodb_io_capacity_max 의해 정의  최대 개수 (100) 이상으로 innodb_io_capacity 값을 설정할  있다.

You can set the innodb_io_capacity value to any number 100 or greater to a maximum defined by innodb_io_capacity_max.

 

MySQL 옵션 파일 (my.cnf 파일 또는 my.ini 파일)에서이 매개 변수의 값을 설정하거나 SUPER 권한 필요 SET GLOBAL 명령을 동적으로 변경할  있다.

You can set the value of this parameter in the MySQL option file (my.cnf or my.ini) or change it dynamically with the SET GLOBAL command, which requires the SUPER privilege.

 

- 만약 활성화 상태인 MySQL 서버라면 당신은 플러싱 비율을 증가/감소하는 innodb_io_capacity_max값을 조정할 필요가 있다.

- if  the MySQL server is in an active state (serving user requests) you need to adjust innodb_io_capacity_max to increase/decrease flushing rate.

 

- MySQL 서버가 유휴 상태 또는 flush_list에서 페이지 종료 플러싱 수행하는 경우 innodb_io_capacity  의해서만 제한됩니다

- if the MySQL server is in an idle state or performing shutdown flushing of the pages from flush_list will be limited byinnodb_io_capacity value only.

 

출처 :

http://www.percona.com/blog/2013/10/30/innodb-adaptive-flushing-in-mysql-5-6-checkpoint-age-and-io-capacity/

http://dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html#sysvar_innodb_io_capacity_max

 

Real MaiaDB p378 ~ p385


반응형
반응형

http://seuis398.blog.me/70186283219



MySQL Replication 구조는 Master에서 아무리 많은 쿼리를 처리하더라도 Slave가 Master의 처리량을 따라갈 수 없는 근본적인 문제를 가지고 있다.

이는 Master에서는 다량의 세션에서 동시에 쿼리를 수행하지만 Slave는 항상 Single Thread로 복제를 처리하기 때문인데, MySQL 5.6 버전에서는 이런 부분들을 조금 완화할 수 있는 parallel slave 기능이 도입되었다.

 

MySQL 5.6의 parallel slave는 database 단위로 별도의 worker thread가 생성되고, 기존 복제 처리를 하던 SQL Thread가 작업 관리 역할을 하면서 각 worker thread에게 작업을 할당해 주는 방식으로 처리된다.

 


 

slave_parallel_workers 파라미터를 변경한 후 단순히 복제를 재시작하는 것만으로 간단하게 기능을 활성화 할 수 있는데, processlist 상에서도 IO/SQL Thread 이외 SQL Thread(Coordinator)로부터 작업 할당을 대기하거나 작업을 처리하고 있는 worker thread를 확인할 수 있다. 

mysql> set global slave_parallel_workers=4;

mysql> stop slave ; start slave;

...

mysql> show processlist;

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

| Id | User        | Host | db   | Command | Time | State                                                                       | Info             |

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

| 31 | system user |      | NULL | Connect | 6500 | Waiting for master to send event                                            | NULL             |

| 32 | system user |      | NULL | Connect | 5548 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL             |

| 33 | system user |      | NULL | Connect | 5592 | Waiting for an event from Coordinator                                       | NULL             |

| 34 | system user |      | NULL | Connect | 5592 | Waiting for an event from Coordinator                                       | NULL             |

| 35 | system user |      | NULL | Connect | 5594 | Waiting for an event from Coordinator                                       | NULL             |

| 36 | system user |      | NULL | Connect | 5587 | Waiting for an event from Coordinator                                       | NULL             |

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

 

mysql> show processlist;

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

| Id | User        | Host | db      | Command | Time | State                                            | Info                                                                                                 |

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

| 31 | system user |      | NULL    | Connect |  831 | Waiting for master to send event                 | NULL                                                                                                 |

| 32 | system user |      | NULL    | Connect |    0 | Waiting for Slave Workers to free pending events | NULL                                                                                                 |

| 33 | system user |      | sbtest1 | Connect |   31 | update                                           | INSERT INTO sbtest10(k, c, pad) VALUES (0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt'), |

| 34 | system user |      | sbtest4 | Connect |   30 | update                                           | INSERT INTO sbtest4(k, c, pad) VALUES (0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt'),( |

| 35 | system user |      | sbtest3 | Connect |   32 | update                                           | INSERT INTO sbtest4(k, c, pad) VALUES (0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt'),( |

| 36 | system user |      | sbtest2 | Connect |   32 | update                                           | INSERT INTO sbtest4(k, c, pad) VALUES (0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt'),( |

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

 

실제 어느 정도의 효과가 있는지 아래와 같은 시나리오로 테스트를 해보았다.

▶ sysbench로 테스트 database를 8개 생성 (sbtest1~8)

 sysbench oltp 테스트 부하를 sbtest1~8에 동시에 인입 =>  Master db 기준으로 초당 40,000~45,000 정도의 쿼리가 처리됨

▶ Slave db에서 slave_parallel_workers 파라미터를  0(기존방식), 2, 4, 8로 증가하면서 복제 처리량 측정 

 

테스트 결과 병렬 처리를 하지 않았을 때에 비해서 database 개수만큼 병렬 처리를 했을 때 거의 6배 정도의 복제 처리량이 증가하는 것을 확인할 수 있었다.

물론 부하모델에 따라서 수치는 차이가 나겠고, Master에 비해서는 여전히 느리게 복제가 반영되겠지만, 충분히 메리트 있는 기능으로 보인다.




다만 5.6 버전 기준으로 이 기능을 사용하기 위해서는 몇가지 유의해야 될 부분들이 있다.

(1) 당연한 얘기겠지만 database 단위로 worker thread가 생성되기 때문에, database가 1개인 경우에는 이득이 없다.

(2) worker thread는 트랜잭션을 고려하지 않고 반영을 하기 때문에 각 database가 독립적인 구조가 아니라 트랜잭션으로 묶여서 사용되는 환경에서는 Master-Slave 간 데이터 정합성을 보장할 수 없다.

(3) database 단위로 복제를 처리하지만, 한쪽 database에서 지연이 발생하면 전체 database에도 복제 지연이 발생하게 된다.  

     즉, 병렬 처리의 효과를 극대화하기 위해서는 각 database에 인입되는 부하가 균일해야 하며, 짧은 쿼리들 위주이어야 한다.

     (SQL Thread가 특정 worker thread에게 작업 할당을 해야 되는데, 해당 thread가 이전 작업을 완료하지 못했으면 SQL Thread는 대기)

(4) 5.6.16 버전까지는 특정 상황에서 parallel slave 기능을 사용했을 때 memory leak이 발생할 수 있다. (5.6.17에서 패치됨)

     http://bugs.mysql.com/bug.php?id=71197

 

※ 특정 database에 lock을 걸어서 의도적으로 복제 적용하지 못하도록 처리했을 때의 나머지 worker thread가 대기하는 상태

mysql> lock table sbtest1.sbtest write;

Query OK, 0 rows affected (0.00 sec)

 

mysql> show processlist;

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

| Id | User        | Host            | db      | Command | Time | State                                            | Info                                                                                                 |

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

| 31 | system user |                 | NULL    | Connect |  853 | Waiting for master to send event                 | NULL                                                                                                 |

| 32 | system user |                 | NULL    | Connect |    0 | Waiting for Slave Workers to free pending events | NULL                                                                                                 |

| 33 | system user |                 | sbtest1 | Connect |   37 | Waiting for table metadata lock                  | INSERT INTO sbtest(k, c, pad) VALUES (0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt'),(0 |

| 34 | system user |                 | NULL    | Connect |   32 | Waiting for an event from Coordinator            | NULL                                                                                                 |

| 35 | system user |                 | NULL    | Connect |   32 | Waiting for an event from Coordinator            | NULL                                                                                                 |

| 36 | system user |                 | NULL    | Connect |   32 | Waiting for an event from Coordinator            | NULL                                                                                                 |

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

 


반응형
반응형

[설치]

 

1. 다운
#apt-get install sysbench 또는

#wget http://downloads.mysql.com/source/sysbench-0.4.12.5.tar.gz


 

2. 압축해제
#gzip -d sysbench-0.4.12.5.tar.gz 

#tar xvf sysbench-0.4.12.5.tar

 

3. 설치
#cd sysbench-0.4.12.5
#./autogen.sh
#./configure --prefix=${SYSBENCH_HOME} --with-mysql-includes=${MYSQL_HOME}/include/mysql --with-mysql-libs=${MYSQL_HOME}/lib/mysql
#make
#make install

 

===========예외 케이스==============
<./autogen.sh 예외처리>
   - aclocal 미존재하여 에러 발생시
   #yum install automake
   - libtoolize 미존재하여 에러 발생시
   #yum install libtool

 

<./configure 예외처리>
   -자신의 디렉토리에 맞게 명령어를 입력하면된다
    (./configure --prefix=/usr/local --with-mysql-includes=/usr/include/mysql --with-mysql-libs=/usr/lib64/mysql)
   -헤더파일이 없을경우 make 실행하면 아래와 같은 에러가 발생한다. 

 

<에러>
    drv_mysql.c:35:19: error: mysql.h: No such file or directory
    drv_mysql.c:36:26: error: mysqld_error.h: No such file or directory
   -헤더파일을 설치해야 할 경우 mysql-devel 설치후 다시 ./configure 실행하고 make 할 것
   #yum install mysql-devel
===================================

 

 

 

 

 

 

 

 

 

[I/O test]
#sysbench --num-threads=16 --test=fileio --file-total-size=2G --file-test-mode=rndrw prepare

#sysbench --num-threads=16 --test=fileio --file-total-size=2G --file-test-mode=rndrw run

 

[OLTP test]

<데이터적재>

>create database sbtest;

#sysbench --test=oltp --mysql-table-engine=innodb --oltp-table-size=1000000 --mysql-user=root --mysql-password=cjsgkanwjr --mysql-socket=/var/lib/mysql/mysql.sock prepare

 

<테스트 시작1>

#sysbench --num-threads=16 --max-requests=100000 --test=oltp --oltp-table-size=1000000 --mysql-user=root --mysql-password=cjsgkanwjr --mysql-socket=/var/lib/mysql/mysql.sock --oltp-read-only run

<테스트 시작2>

#sysbench --num-threads=16 --max-time=60 --max-requests=100000 --test=oltp --oltp-table-size=1000000 --mysql-user=root --mysql-password=cjsgkanwjr --mysql-socket=/var/lib/mysql/mysql.sock --oltp-read-only=off --oltp-test-mode=complex run

 

 

<실행 옵션>

--oltp-table-size=[테이블-레코드-건수]

--num-threads=[동시-스레드-개수]

--max-requests=[쿼리-요청-개수]
--max-time=[테스트-시간]  // 0이면 지정된 횟수만큼 모두 완료해야 종료, 그외는 초단위로 지정된 시간만큼 실행
--mysql-host=[호스트명]
--mysql-user=[DB-USER]
--mysql-password=[DB-USER-비밀번호]
--mysql-db=[테스트-데이터베이스명]
--mysql-table-engine=[테이블-엔진-종류]
--mysql-socket=[MySQL-소켓-파일-경로]
--mysql-port=[MySQL-포트-번호]
--oltp-test-mode=[simple|complex|nontrx]  // simple 은 select만 하고, complex는 select,insert,delete,update 중 랜덤하게 실행
--oltp-read-only=[on|off]






Sysbench 설치

 yum install -y mysql-devel
 tar xvfz sysbench-0.4.12.tar
 cd sysbench-0.4.12
 ./autogen.sh
 ./configure --prefix=${SYSBENCH_HOME} --with-mysql-includes=${MYSQL_HOME}/include/mysql \

 --with-mysql-libs=${MYSQL_HOME}/lib/mysql
 make
 make install

 

Sysbench 옵션

 일반옵션
  --num-threads=N                    사용하는 쓰레드 수
  --max-requests=N                  쿼리 요청 개수
  --max-time=N                         테스트 시간
  --forced-shutdown=STRING     --max-time 후에 강제종료여부 on/off ( 기본값 : off )
  --thread-stack-size=SIZE        쓰레드당 스텍 사이즈 ( 기본값 : 32K )
  --init-rng=[on|off]                  initialize random number generator [off]
  --test=STRING                       test to run
  --debug=[on|off]                   디버깅 정보 출력 [off]
  --validate=[on|off]                  perform validation checks where possible [off]
  --help=[on|off]                      도움말 출력
  --version=[on|off]                  버전 출력

  --oltp-table-size                    테이블 레코드 건수

 

 Compiled-in tests:
  fileio - File I/O test
  cpu - CPU performance test
  memory - Memory functions speed test
  threads - Mutex locking / unlocking을 통해 Job Scheduler 성능 측정
  mutex - Mutex performance test
  oltp - OLTP test (Point Query, Range Query, Sum, Order by, Group by, Distinct 등의 쿼리를 수행하여 OLTP 쿼리 성능 측정

 

 fileio 모드 :

  --file-num                              생성된 파일 수  : 기본값 128

  --file-block-size                     모든 I/O 작동에 사용하는 블록사이즈수  : 기본값 16K

  --file-total-size                       파일의 총 크기 : 기본값 2G

  --file-test-mode                      작업유형 ( seqwr, seqrewr, seqrd, rndrd, rndrw, rndwr ) : 기본값 required

  --file-io-mode                         I/O 모드 ( sync, async, fastmmap, slowmmap ) : 기본값 sync

  --file-async-backlog               쓰레드당 큐의 비동기화 동작 수 (only for --file-io-mode=async) : 기본값 128

  --file-fsync-freq                      Do fsync() after this number of requests (0 - don't use fsync()) : 기본값 100

  --file-fsync-all                        Do fsync() after each write operation : 기본값 no

  --file-fsync-end                      Do fsync() at the end of the test : 기본값 yes

  --file-fsync-mode                    동기화 사용 방법 ( fsync, fdatasync ) : 기본값 fsync

  --file-merged-requests            Merge at most this number of I/O requests if possible (0 - don't merge) : 기본값 0

  --file-rw-ratio                         reads/writes ration for combined random read/write test : 기본값 1.5

 

File  I/O 성능 측정

 #sysbench --num-threads=16 --test=fileio --file-total-size=1G --file-test-mode=rndrw prepare

 

 sysbench 0.4.12:  multi-threaded system evaluation benchmark

 128 files, 8192Kb each, 1024Mb total
 Creating files for the test...
 -------------------------------------------------------------------------------------------
 # sysbench --num-threads=16 --test=fileio --file-total-size=1G --file-test-mode=rndrw run
 sysbench 0.4.12:  multi-threaded system evaluation benchmark

 Running the test with following options: 
 Number of threads: 16

 Extra file open flags: 0
 128 files, 8Mb each
 1Gb total file size
 Block size 16Kb
 Number of random requests for random IO: 10000
 Read/Write ratio for combined random IO test: 1.50
 Periodic FSYNC enabled, calling fsync() each 100 requests.
 Calling fsync() at the end of test, Enabled.
 Using synchronous I/O mode
 Doing random r/w test
 Threads started!
 Done.

 

 Operations performed:  5999 Read, 4001 Write, 12800 Other = 22800 Total
 Read 93.734Mb  Written 62.516Mb  Total transferred 156.25Mb  (18.646Mb/sec)
 1193.37 Requests/sec executed

 Test execution summary:
    total time:                          8.3796s
    total number of events:              10000
    total time taken by event execution: 46.8871
    per-request statistics:
         min:                                  0.01ms
         avg:                                  4.69ms
         max:                                223.05ms
         approx.  95 percentile:              38.94ms

 Threads fairness:
    events (avg/stddev):           625.0000/90.00
    execution time (avg/stddev):   2.9304/0.41

 

MySQL DB OLTP(Online Transaction Processing) 성능 측정

 /usr/local/mysql55/bin/mysql -utheswice -p
 mysql> create database sbtest;
 mysql> use sbtest;
 mysql> \q

 

 

 # sysbench --debug=off --mysql-host=themade.com --mysql-user=theswice --mysql-password=XXXX \
 --test=oltp --oltp-table-size=1000000 prepare   // 데이터 준비

 

 sysbench 0.4.12:  multi-threaded system evaluation benchmark

 No DB drivers specified, using mysql
 Creating table 'sbtest'...
 Creating 1000000 records in table 'sbtest'...
 ----------------------------------------------------------------------------------------

// 실행 회수 기반의 테스트(시간 관계없이 1000000번 요청 실행)
 #  sysbench --debug=off --mysql-host=theswice.com --mysql-user=theswice --mysql-password=XXXX \
 --test=oltp --oltp-table-size=1000000 --num-threads=10 --max-requests=100000 run  // 실행

 

 sysbench 0.4.12:  multi-threaded system evaluation benchmark

 No DB drivers specified, using mysql
 Running the test with following options:
 Number of threads: 10

 Doing OLTP test.
 Running mixed OLTP test
 Using Special distribution (12 iterations,  1 pct of values are returned in 75 pct cases)
 Using "BEGIN" for starting transactions
 Using auto_inc on the id column
 Maximum number of requests for OLTP test is limited to 100000
 Threads started!

 OLTP test statistics:
     queries performed:
         read:                            1400000                                      // 읽기수(페이지수)
         write:                           500000
         other:                           200000
         total:                           2100000
     transactions:                        100000 (195.92 per sec.)            // 초당 트랜잭션 195건
     deadlocks:                           0      (0.00 per sec.)                 // 데드락
     read/write requests:                 1900000 (3722.43 per sec.)     // 초당 쿼리 실행 3722건
     other operations:                    200000 (391.83 per sec.)          // 기타 작업에 의한 초당 작업수

 Test execution summary:
     total time:                          510.4193s                                   // 총시간(초)
     total number of events:              100000                                 // 이벤트수
     total time taken by event execution: 5103.3788                        // 이벤트 실행에 의한 총 시간
     per-request statistics:
          min:                                  3.98ms
          avg:                                 51.03ms
          max:                                628.10ms
          approx.  95 percentile:              90.11ms

 Threads fairness:
     events (avg/stddev):           10000.0000/57.31                       // 이벤트(평균/표준편차)
     execution time (avg/stddev):   510.3379/0.00                         // 실행시간(평균/표준편차)

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

 //실행 시간 기반의 테스트 (요청 수에 관계 없이 20초 동안 실행)

 ./sysbench --test=oltp --oltp-table-size=10000000 --num-threads=8 --max-requests=0 --max-time=20 \

 --mysql-host=localhost --mysql-user=theswice --mysql-password=XXXX \
 --mysql-db=THESWICEDB --mysql-table-engine=innodb --mysql-create-options= \
 --mysql-socket=/tmp/mysql.sock \
 --mysql-port=3306 \
 --oltp-test-mode=complex \
 --oltp-read-only=off run

 

주의사항

1. Sysbench 용 데이터를 prepare 한 후, 처음 실행하는 benchmark는 Buffer pool이 Warming-up되지 않았을 수 있음

2. ​테스트하고자 하는 것이 CPU-Bound인지 I/O-Bound인지 명확히 구분하여, Buffer pool 사이즈와 --oltp-table-size를 적절히 조절해야 한다.
   일반적으로 InnoDB 스토리지 엔진 사용시, record건수가 10,000,000건인 경우 2.3G 정도의 ibd 파일이 생성되며,

   100,000,000 건인 경우 23G 정도의 ibd 파일이 생성된다.

3. ​이 테스트로 인해서 산출된 tpmC 값은 시스템의 특성(MySQL Configuration이나 RAID 및 디스크 설정, CPU, 메모리,...)에 따른 상대적인

   값이므로, 동일 수준의 장비와 비교를 위한 수치만으로 고려해야 한다.

4. ​매번 테스트 시나리오를 변경할 때에는, MySQL 서버를 재 시작시키는 것이 가장 좋으며,
   재시작시에는
    mysql> set global innodb_fast_shutdown=0;
    shell$> mysqladmin -uroot -p shutdown
   와 같이 Clean shutdown을 해주는 것이 테스트 간의 영향도를 최소화시킬 수 있는 방법이다.





[출처] Sysbench|작성자 theswice







H/W 혹은 MySQL DB 환경(버전, 파라미터)의 변경으로 성능 비교가 필요한 경우, sysbench를 이용해서 간단하게 시스템, DB 성능을 측정할 수 있다.

Sysbench는 Oracle로 인수된 MySQL AB社에서 개발한 프로그램이다. 

 

sysbench는 아래와 같이 간단하게 설치가 가능하다.

# 다운로드 (sourceforge) 

http://sourceforge.net/projects/sysbench

 

# 압축 해제 

$ tar xfz sysbench-0.4.12.tar.gz

$ cd sysbench-0.4.12

 

# Config 및 Make

$ ./autogen.sh

$ ./configure --prefix=/usr/local --with-mysql-includes=$MYSQL_HOME/include --with-mysql-libs=$MYSQL_HOME/lib 

$ make

$ make install 

 

sysbench는 아래와 같은 항목으로 시스템과 MySQL DB의 성능을 측정한다.

(1) fileio - 디스크에 대한 sequential, random I/O 성능 측정
(2) cpu - 소수(prime number)를 이용한 연산으로 CPU 성능 측정

(3) memory - 메모리 I/O 성능 측정

(4) threads - Mutex locking / unlocking을 통해 Job Scheduler 성능 측정 
(5) mutex - Mutex lock 속도 측정
(6) oltp - Point Query, Range Query, Sum, Order by, Group by, Distinct 등의 쿼리를 수행하여 OLTP 쿼리 성능 측정 

 

테스트 항목별로 사용법에 차이가 나기 때문에, 자세한 사용법은 아래 메뉴얼을 참고하면 된다. ^^ 

http://sysbench.sourceforge.net/docs/

 

(예1) File I/O 성능 측정 

 

# sysbench --num-threads=16 --test=fileio --file-total-size=1G --file-test-mode=rndrw prepare
sysbench 0.4.12:  multi-threaded system evaluation benchmark

128 files, 8192Kb each, 1024Mb total
Creating files for the test...

 

# sysbench --num-threads=16 --test=fileio --file-total-size=1G --file-test-mode=rndrw run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 16

Extra file open flags: 0
128 files, 8Mb each
1Gb total file size
Block size 16Kb
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 1.50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
Done.

Operations performed:  5997 Read, 4003 Write, 12800 Other = 22800 Total
Read 93.703Mb  Written 62.547Mb  Total transferred 156.25Mb  (42.731Mb/sec)
 2734.80 Requests/sec executed

Test execution summary:
    total time:                          3.6566s
    total number of events:              10000
    total time taken by event execution: 4.9801
    per-request statistics:
         min:                                  0.01ms
         avg:                                  0.50ms
         max:                                211.79ms
         approx.  95 percentile:               0.03ms

Threads fairness:
    events (avg/stddev):           625.0000/149.44
    execution time (avg/stddev):   0.3113/0.15

 

# sysbench --num-threads=16 --test=fileio --file-total-size=1G --file-test-mode=rndrw cleanup 


(예2) MySQL DB OLTP 성능 측정

 

# sysbench --test=oltp --mysql-table-engine=innodb --oltp-table-size=1000000 --mysql-user=root --mysql-password=root --mysql-socket=/tmp/mysql.sock prepare             
sysbench 0.4.12:  multi-threaded system evaluation benchmark

No DB drivers specified, using mysql
Creating table 'sbtest'...
Creating 1000000 records in table 'sbtest'...

 

# sysbench --num-threads=16 --max-requests=100000 --test=oltp --oltp-table-size=1000000 --mysql-user=root --mysql-password=root --mysql-socket=/tmp/mysql.sock --oltp-read-only run  
sysbench 0.4.12:  multi-threaded system evaluation benchmark

No DB drivers specified, using mysql
Running the test with following options:
Number of threads: 16

Doing OLTP test.
Running mixed OLTP test
Doing read-only test
Using Special distribution (12 iterations,  1 pct of values are returned in 75 pct cases)
Using "BEGIN" for starting transactions
Using auto_inc on the id column

Maximum number of requests for OLTP test is limited to 100000
Threads started!
Done.

OLTP test statistics:
    queries performed:
        read:                            1400000
        write:                           0
        other:                           200000
        total:                           1600000
    transactions:                        100000 (872.40 per sec.)
    deadlocks:                           0      (0.00 per sec.)
    read/write requests:                 1400000 (12213.65 per sec.)
    other operations:                    200000 (1744.81 per sec.)

Test execution summary:
    total time:                          114.6259s
    total number of events:              100000
    total time taken by event execution: 1832.5973
    per-request statistics:
         min:                                  0.16ms
         avg:                                 18.33ms
         max:                              16946.78ms
         approx.  95 percentile:              26.99ms

Threads fairness:
    events (avg/stddev):           6250.0000/917.83
    execution time (avg/stddev):   114.5373/0.09 









# 벤치마킹용 데이터베이스 및 계정 생성
create database sysbench;

create user sysbench@'%' identified by 'sysbench';
create user sysbench@'localhost' identified by 'sysbench';
create user sysbench@'127.0.0.1' identified by 'sysbench';

grant all on sysbench.* to sysbench@'%';
grant all on sysbench.* to sysbench@'localhost';
grant all on sysbench.* to sysbench@'127.0.0.1';


# Sysbench building
$ wget http://downloads.sourceforge.net/project/sysbench/sysbench/0.4.12/sysbench-0.4.12.tar.gz?use_mirror=cdnetworks-kr-1
$ tar xvfz sysbench-0.4.12.tar.gz
$ cd sysbench-0.4.12
$ ./autogen.sh
$ ./configure --prefix=${SYSBENCH_HOME} --with-mysql-includes=${MYSQL_HOME}/include/mysql --with-mysql-libs=${MYSQL_HOME}/lib/mysql
$ make
$ make install


# 테스트를 위한 준비 (테이블 및 데이터 생성)
#  주어진 데이터베이스에 테스트용 테이블(default 테이블명은 sbtest)을 생성하고, 주어진 건수 만큼 레코드를 Insert
#  테스트용으로 만들어진 데이터를 초기화하는 방법은 sysbench 도구를 이용해도 되지만, 간단히 "drop table sbtest;"명령으로 삭제해도 됨
${SYSBENCH_HOME}/bin/sysbench --test=oltp --oltp-table-size=[테이블-레코드-건수] \
--max-requests=[쿼리-요청-개수] --max-time=[테스트-시간] \
--mysql-host=[호스트명] --mysql-db=[테스트-데이터베이스명] --mysql-user=[DB-USER] --mysql-password=[DB-USER-비밀번호] \
--mysql-table-engine=[테이블-엔진-종류] --myisam-max-rows=[MyISAM인 경우-레코드-최대-건수] --mysql-create-options= \
--mysql-socket=[MySQL-소켓-파일-경로] \
--mysql-port=[MySQL-포트-번호] \
--oltp-test-mode=[simple|complex|nontrx] \
--oltp-read-only=[on|off] \
prepare

예제)
./sysbench --test=oltp --oltp-table-size=10000000 --num-threads=8 \
--mysql-host=localhost --mysql-user=sysbench --mysql-password=sysbench \
--mysql-db=sysbench --mysql-table-engine=innodb --myisam-max-rows=10000000000 --mysql-create-options= \
--mysql-socket=/tmp/mysql.sock \
--oltp-test-mode=complex \
--oltp-read-only=off \
prepare

# 테스트 실행
${SYSBENCH_HOME}/bin/sysbench --test=oltp --oltp-table-size=[테이블-레코드-건수] --num-threads=[동시-스레드-개수] \
--max-requests=[쿼리-요청-개수] --max-time=[테스트-시간] \
--mysql-host=[호스트명] --mysql-user=[DB-USER] --mysql-password=[DB-USER-비밀번호] \
--mysql-db=[테스트-데이터베이스명] --mysql-table-engine=[테이블-엔진-종류] --mysql-create-options= \
--mysql-socket=[MySQL-소켓-파일-경로] \
--mysql-port=[MySQL-포트-번호] \
--oltp-test-mode=[simple|complex|nontrx] \
--oltp-read-only=[on|off] \
run

예제)
# 실행 회수 기반의 테스트 (시간 관계없이 10000번 요청 실행)
./sysbench --test=oltp --oltp-table-size=10000000 --num-threads=8 --max-requests=10000 --max-time=0 \
--mysql-host=localhost --mysql-user=sysbench --mysql-password=sysbench \
--mysql-db=sysbench --mysql-table-engine=innodb --mysql-create-options= \
--mysql-socket=/tmp/mysql.sock \
--mysql-port=20306 \
--oltp-test-mode=complex \
--oltp-read-only=off \
run

# 실행 시간 기반의 테스트 (요청 수에 관계 없이 20초 동안 실행)
./sysbench --test=oltp --oltp-table-size=10000000 --num-threads=8 --max-requests=0 --max-time=20 \
--mysql-host=localhost --mysql-user=sysbench --mysql-password=sysbench \
--mysql-db=sysbench --mysql-table-engine=innodb --mysql-create-options= \
--mysql-socket=/tmp/mysql.sock \
--mysql-port=20306 \
--oltp-test-mode=complex \
--oltp-read-only=off \
run

# 결과 분석
sysbench 0.4.12:  multi-threaded system evaluation benchmark
...
OLTP test statistics:
    queries performed:
        read:                            140014
        write:                           50005
        other:                           20002
        total:                           210021
    transactions:                        10001  (866.61 per sec.)   ==> 초당 트랜잭션 866 건
    deadlocks:                           0      (0.00 per sec.)
    read/write requests:                 190019 (16465.61 per sec.) ==> 초당 쿼리 실행 16465 건
    other operations:                    20002  (1733.22 per sec.)

Test execution summary:
...

# 테스트시 주의 사항
  • Sysbench 용 데이터를 prepare 한 후, 처음 실행하는 benchmark는 Buffer pool이 Warming-up되지 않았을 수 있음
  • 테스트하고자 하는 것이 CPU-Bound인지 I/O-Bound인지 명확히 구분하여,
    Buffer pool 사이즈와 --oltp-table-size를 적절히 조절해야 한다.
    일반적으로 InnoDB 스토리지 엔진 사용시, record건수가 10,000,000건인 경우 2.3G 정도의 ibd 파일이 생성되며,
    100,000,000 건인 경우 23G 정도의 ibd 파일이 생성됨
  • 이 테스트로 인해서 산출된 tpmC 값은 시스템의 특성(MySQL Configuration이나 RAID 및 디스크 설정, CPU, 메모리,...)에 
    따른 상대적인 값이므로, 동일 수준의 장비와 비교를 위한 수치만으로 고려해야 한다.
  • 매번 테스트 시나리오를 변경할 때에는, MySQL 서버를 재 시작시키는 것이 가장 좋으며,
    재시작시에는
        mysql> set global innodb_fast_shutdown=0;
        shell$> mysqladmin -uroot -p shutdown
    와 같이 Clean shutdown을 해주는 것이 테스트 간의 영향도를 최소화시킬 수 있는 방법이다.



## 참고 사항 (oltp-test-mode 의 설정값에 따른 테스트 케이스의 SQL 내용)
simple
  • ==> 단순히 아래 형태의 SELECT 쿼리만 실행
  • [필수] SELECT c FROM sbtest WHERE id=N;

complex (advanced transactional)
  • ==> 아래의 쿼리들중에서 M개를 선별하여 쿼리 실행
  • [필수] BEGIN;
  • [옵션] SELECT c FROM sbtest WHERE id=N;
  • [옵션] SELECT c FROM sbtest WHERE id BETWEEN N AND M;
  • [옵션] SELECT SUM(K) FROM sbtest WHERE id BETWEEN N and M;
  • [옵션] SELECT c FROM sbtest WHERE id between N and M ORDER BY c;
  • [옵션] SELECT DISTINCT c FROM sbtest WHERE id BETWEEN N and M ORDER BY c;
  • [옵션] UPDATE sbtest SET k=k+1 WHERE id=N;
  • [옵션] UPDATE sbtest SET c=N WHERE id=M;
  • [옵션] DELETE FROM sbtest WHERE id=N;
  • [옵션] INSERT INTO sbtest VALUES (...);
  • [필수] COMMIT;


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

io_capacity와 checkpoint age <MySQL 5.6>  (0) 2014.11.27
MySQL 5.6 Parallel Replication (slave_parallel_workers)  (0) 2014.11.25
MySQL innodb_flush_method 튜닝 포인트  (0) 2014.11.19
innodb 처음 사용시 고려  (0) 2014.11.19
nmon  (0) 2014.11.18
반응형

MySQL InnoDB 스토리지 엔진을 사용하면 매개 변수 innodb_flush_method가 있는데 이 설정 값의 의미와 테스트를 통해 튜닝 포인트를 검토해 보고자 한다.

innodb_flush_method 매개 변수는?

MySQL InnoDB innodb_flush_method 매개 변수는 Unix/Linux에서 데이터 파일, 로그 파일을 읽고 쓰는 방법을 지정하는 것으로 "13.6.3. InnoDB Startup Options and System Variables"에 따르면 다음과 같은 세가지 설정이 가능하다.

  • fdatasync : 디폴트 설정. 데이터나 로그 파일을 열고 쓸 때 fsync()를 사용한다.
  • O_DSYNC : 로그 파일을 읽고 쓸 때는 O_SYNC를 사용하고 데이터 파일을 읽고 쓸 때는 fsync()를 사용한다.
  • O_DIRECT : 데이터 파일을 열 때는 O_DIRECT(솔라리스는 directio())를 사용하고 데이터 파일과 로그 파일을 쓸 때는 fsync()를 사용한다.


Direct I/O란?

O_DIRECT 플래그를 사용하여 파일을 열면 OS가 가지고 있는 Direct I/O기능을 이용할 수 있다. 즉, 이것은 OS의 캐시 메커니즘을 무시하는 기능이며, RDBMS는 자기 부담으로 데이터를 캐시 하니까 OS의 캐시 메커니즘은 필요 없어도 된다는 의미이다.



일반적으로 디스크의 파일에 액세스하는 경우 파일 캐시를 통과하게 되어 있는데 이 파일 캐싱 덕분에, 캐시 히트했을 경우에는 데이터 읽기 속도가 빨라진다. 또한, 파일 캐시를 이용한 지연된 쓰기 기능은 프로세스에 대한 쓰기 작업 성능이 향상된다.
Direct I/O를 사용하면 디스크상의 파일(데이터)에 액세스하기 위해 파일 캐시를 통과하지 않고 데이터는 응용 프로그램과 같은 프로세스와 디스크에 직접 전달된다.
RDBMS는 내부에 파일 캐시와 같은 도구를 갖추고 있다. 따라서 파일 캐시를 통하게 되면 캐시 처리가 2중으로 되어 불필요한 지연이 발생하여 Direct I/O와 같이 파일 캐시를 경유하지 않고 직접 디스크에 엑세스 하는 방안이 필요한 것이다.

테스트를 통한 고찰

1) 테스트 환경
- 서버 자원

CPUIntel Xeon Quad-Core X3440(2.53GHz)
OSCentos 5.7 x86_64
RAMDDR3 PC3-10600 (1,333MHz) 2GB x 2
HDDSATA2 500GB (7200.ES)
RDBMSMySQL 5.5.23


- MySQL 설정 패턴

innodb_buffer_pool_size16MB, 32MB, 64MB, 128MB, 256MB
innodb_flush_method미지정(fdatasync), O_DIRECT
Write 데이터 스케일500M 정도


- 테스트 테이블

CREATE TABLE user(
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`last_name` varchar(256) DEFAULT NULL,
`first_name` varchar(256) DEFAULT NULL,
`duty` varchar(256) DEFAULT NULL,
`cellphone` varchar(256) DEFAULT NULL,
`housephone` varchar(256) DEFAULT NULL,
`telephone` varchar(256) DEFAULT NULL,
`office_fax` varchar(256) DEFAULT NULL,
`home_address` varchar(256) DEFAULT NULL,
`office_address` varchar(256) DEFAULT NULL,
`remark` text, 
PRIMARY KEY (`id`),
KEY `NAME_INDEX` (`first_name`,`last_name`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

2) 테스트 결과.



buffer_pool이 128M 이전은 fdatasync 방식이 성능이 더 높고 128M이후부터는 O_DIRECT 방식이 더 높은 성능 결과를 보여주고 있다.
앞쪽으로 fdatasync 방식이 더 성능이 높은 것은 InnoDB 버퍼 풀에 없는 데이터가 OS 파일 캐시에 있을 수 있어 디스크 I/O를 줄일 수 있기 때문에 성능 효과를 본 것 같다. 즉, OS 파일 캐시가 InnoDB 버퍼 풀에 대한 보조 캐시 역할을 한 것이라고 볼 수 있다.

요약해 보면

O_DIRECT가 fdatasync에 비해 동등한 성능 이상을 발휘하기 위해서는 

  • 모든 데이터가 InnoDB 버퍼 풀에 들어가거나
  • 물리 메모리의 절반 정도를 InnoDB 버퍼 풀에 할당하는 경우

중 하나의 조건을 충족해야 좋은 성능을 발취할 것으로 보인다.
그러나 데이터 베이스 이외에 기능들에서 File I/O가 많이 일어난다면, 트랜젝션의 양, 트랜젝션의 중량감 등도 고려되어야 하고 무조건 버퍼풀 많이 잡는 것도 문제니 꼭, 테스트를 많이 해서 시스템에 환경에 맞는 매개변수를 취사 선택해야 한다. 또한 이런 습관은 더 중요하다. 이론적 예측보다는, 그냥 좋다고 덥석 설정 값을 고정하기보다는 테스트를 해서 증명하는 것이 더 좋은 방법이다.

"추측하지 말라, 데이터를 보고 계산된 예측을 하라"

[참조 사이트]


반응형

'연구개발 > MYSQL' 카테고리의 다른 글

MySQL 5.6 Parallel Replication (slave_parallel_workers)  (0) 2014.11.25
sysbench 설치 및 실행  (0) 2014.11.25
innodb 처음 사용시 고려  (0) 2014.11.19
nmon  (0) 2014.11.18
mysql 쿼리 결과 파일 저장  (0) 2014.11.17
반응형

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


innodb 처음 사용시 고려
(1) Linux 에서는 write-back cache 를 disable 시킬것.
(2) innodb_autoextend_increment 수치를 조정하여 tablespace 가 full 일경우
    default 로 8MB씩 증가하는것을 변경할수 있다.
(3) autoextend attribute and those following can be used only for the last
    datafile in the innodb_data_file_path line.
(4) set key_buffer to 5 ~ 10% of your RAM on how much you use myisam tables,
    but keep key_buffer_size + Innodb buffer pool size < 80 % of your RAM.
(5) set buffer pool size to 50 ~ 80% of RAM.
(6) Per-Table Tablespace 사용시 해당 테이블에 대한 복구나 이동이 쉽다.
    [mysqld]
    innodb_file_per_table
   : table 생성시에만 관여. 기존 테이블의 Access 에는 무관.
(7) skip-innodb-checksums : pull and plug 테스트 해보고 괜찮으면 써도 됨.
                            부하 별로 없으면 쓰지 말자.. 혹시나.


(8) innodb_commit_concurrency : 동시에 commit 을 날릴수 있는 Thread 의 수.
(9) innodb_concurrency_tickets 
(10) innodb_fast_shutdown : (0, 1, 2)
     0: Oracle의 Normal shutdown 과 같음.
     1: Oracle의 shutdown immediate 과 같음.
     2: Oracle의 shutdown abort 와 같음.
(11) innodb_doublewrite : write double write buffer first, and then actual 
                          data file.(vs. --skip_innodb_doublewrite)
(12) innodb_file_io_threads : On Unix, increasing the number has no effect.
                              Innodb always uses the default value.
                              (즉, 변경해도 소용없다.)
(13) innodb_flush_log_at_trx_commit : 일단 0로 해서 사용하자.
     0 : log buffer 에 있는것을 일초마다 log file 로 flush 한다.
     1 : 트랜잭션마다 log file 로 flush 한다.
     2 : 트랜잭션마다 log file 로 내리지만 disk flush 는 발생하지 않는다.
(14) innodb_flush_method : fdatasync 가 기본(변경할 필요가 있을까?)
     O_DSYNC, O_DIRECT 등의 옵션이 있다.
(15) 안전한 replication 환경을 위해서는
     innodb_flush_log_at_trx_commit = 1, sync_binlog=1 로 세팅하시오.
(16) innodb_locks_unsafe_for_binlog : default 0
     next key locking 을 안쓰려면 enable(1) 을 하면 되는데 당연히 disable 추천.
(17) innodb_log_arch_dir, innodb_log_archieve : archieve log 할시에만 사용.
     히스토리컬 이유에서만 사용. 복구는 자체의 log 파일로 복구 하기 땜시 
     별필요 없긴 한데 그래도 한번 고민 해볼 필요 있슴.
(18) innodb_log_buffer_size : 1-8 MB 가 적당. io 에 의한 부하가 있을 경우 이값을
     적당히 늘여주면서 모니터링(20MB 는 넘지 말자.)
(19) innodb_log_file_size : 로그 그룹내의 각 로그파일의 크기.
     기본값은 5MB이며 1MB 에서 1/Nth of buffer Pool 로 값을 조정. 
     N 은 그룹내의 로그파일의 수. 당연히 크면 좋지만 너무 크면 복구 할때
     오래걸린다. log_file_size 의 합이 4기가를 넘을수는 없다.
(20) innodb_log_files_in_group : 로그그룹내의 로그파일의 수. 권장값과 기본값은
     2 이지만 우린 좀 키워 볼까나?(InnoDB writes to the files in a circular fashion).
(21) innodb_log_group_home_dir : innodb_log_arch_dir 과 같아야 하며 InnoDB 로그 변수와 관련되어 아무것도 지정하지 않을 경우 5MB 의 ib_logfile0, ib_logfile1 두개의 파일이 data 디렉토리에 생성된다.
(22) innodb_max_dirty_pages_pct : 0-100 사이의 값. 기본값 90.
     buffer pool 에 있는 dirty page(not yet written)의 비율을 넘지 않도록 innodb 는 buffer pool 에서 pages 를 쓰려고 한다.
(23) innodb_mirrored_log_groups : 로그 그룹의 동일한 복제본의 수. 현재는 이 값은     1 로 세팅되어져야 한다.
(24) innodb_open_files : innoDB 에서 multiple tablespace 를 사용할경우에만 의미가  있는 값.
     InnoDB 가 한번에 열수 있는 .ibd 의 최대 수. 최소 10. 기본값 300.
     Table cache 값과는 상관 없고 --open-files-limit 옵션과도 관계없슴.
(21) innodb_support_xa : 기본값 1 또는 ON.(분산 트랜잭션 지원이란다.)
     ON 시킬경우 분산 트랜잭션 환경에서 two-phase commit 을 지원.
     transaction preparation 에 의한 disk flush 가 증가하기때문에 거시기 함.
     그래도 일단 enable.
(22) innodb_safe_binlog : innodb 테이블의 내용과 바이너리 로그의 일치성으로 보장하기 위해서 사용.
     xa transacion support 로 의미 없어짐.
(23) innodb_sync_spin_loops : thread 가 suspend 되기전 InnoDB 의 mutex 가 free 되도록
     기다리는 시간.(뭔소리여. 써야 되나? 모르니 default)
(24) innodb_table_locks : 기본값 1. LOCK TABLE 이 InnoDB 에게 내부적으로 테이블에 Lock 을 
     걸어라고 요구함.  
     autocommit = 0, innodb_table_lock = 1 로 
     해야만 innodb layer 에서 mysql 에서 table lock 을 걸었는지를 알수 있고
     그래야만 deadlock detection 이 된다.
(25) innodb_thread_concurrency : 기본값 20. 성능상의 문제나 show innodb status 결과 
     많은 스레드들이 세마포어를 기다리고 있으면 이 값을 증가 시키거나 감소 시킴.
     추천값은 CPU 숫자 + 디스크 숫자임. 20일경우 concurrency 체킹을 안함.
     일단 우리는 16으로 하지 뭐.
(26) innodb_thread_sleep_delay : innodb thread 가 innodb queue 에 joining 하기전에 
     기다리는 시간. 기본값 10,000 (ms 단위)
     일단은 기본값으로 가자.
(27) sync_binlog : syncronize its binary log to disk. 무조건 1로 하자.
2. myisam 에서 innodb 로 데이터 이관
: 당연히 mysql 시스템 테이블을 innodb 로 변경하겠다는 황당한 생각은 하지 말것.
 
테이블 생성시 default 로 innodb 로 하고 싶다면 my.cnf 에서
default-storage-engine=innodb 로 할것.
alter table imsi engine=INNODB ; 로 마이그레이션 강추.
또는 table 생성하고 insert into imsi select * from 어시기; 도 괜찮다.
만약에 unique constraint 가 secondary keys 에 걸려 있을경우
set unique_checks = 0;
.. import operation ..
set unique_checks = 1;
이렇게 하는것이 io 를 감소 시키기 땜시로 빠르다.
큰테이블 넘길때는 innodb buffer pool 사이즈를 80%까지 늘여서 작업하면 IO 가 줄어서 빠르다.
이때는 당연히 logfiles 의 크기를 늘여야 한다.
3. InnoDB data 및 Log file 추가/삭제
: 단순히 mysql shutdown 하고 innodb_data_file_path 에 추가 시키면 된다.
만약 autoextend 로 설정을 하였다면 그파일의 사이즈를 mb 단위로 환산하는 루틴이 필요하다.
(ex) innodb_data_file_path=/ibdata/ibdata1:10M:autoextend
 -->  ibdata1의 크기가 988MB 일경우
     innodb_data_file_path=/ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend 
  데이터 파일 삭제시
  : 테이블 스페이스를 줄이는 방법은 현재로서는 없단다.
    따라서 다음과 같은 절차가 필요하다.
    (1) mysqldump 로 모든 innodb 테이블을 덤프.
    (2) stop server
    (3) 모든 테이블 스페이스 파일 삭제
    (4) 새로운 테이블 스페이스 설정
    (5) Restart 서버
    (6) Import dump files
   이 이외에도 개인적으로는 innodb -> myisam 변경 -> shutdown -> 테이블스페이스설정 -> innodb 로 변경
    <Log file 숫자 변경하기>
    (1) stop mysql server (make sure it shuts down with out errors)
    (2) copy old log files into a safe place.
    (3) delete old log files from the log file directory.
    (4) edit my.cnf to change log file configuration.
    (5) start server
4. InnoDB Backup and Recovering
   : innodb hot backup 을 쓰는게 가장 좋긴 하지만 없으면 바이너리 백업을 한다.
    (1) shutdown server without errors 
    (2) copy all data files(ibdata files and .ibd files) into a safe place.
    (3) copy all ib_logfile to a safe place.
    (4) copy my.cnf to a safe place.
    (5) copy all .frm files to a safe place.
    이 이외에도 정기적으로 mysqldump 를 통한 백업을 시행해라.
    또한 mysqldump는 --single-transaction 이 있어서 다른 클라이언트에 Locking 을 거는 일 없이 백업이 가능.
    바이너리 로그를 통한 현재타임 복구는 binary 로그를 이용하여 실시.
    즉 mysqlbinlog hostname-bin.123 | mysql
    시스템 크래시로 인한 복구가 아니라면 그냥 mysql 을 리스타트 하는것으로 복구가 진행됨.
5. InnoDB 강제 복구
  : 데이터베이스 페이지가 손상되었을때에도 select into outfile 을 통해
    백업할수가 있다.
    corruption 이 select * from tbl_name 또는 InnoDB 의 roll forward recovery나
    백그라운드 작업들이 crash 되더라도 백그라운드 작업들이 돌지 않도록 막으면서 
    innodb storage engine 을 시작시킬수 있다. 따라서 테이블들을  dump 할수가
    있는 것이다. 
    [예]
    [mysqld]
    innodb_force_recovery = 4
    이렇게 세팅한후 mysql 을 리스타트 하면 스타트가 가능하다.
    여기에서 세팅 가능한 값들을 살펴보면
    1 : 손상된 페이지가 감지되더라도 mysql을 시작한다.
    2 : main thread 가 동작하는것을 차단한다.
        corruption 을 깨끗하게 하는 작업중에 crash 가 발생했었다면 이 값을
        세팅하면 mysql 이 시작 가능하다.
    3 : 스타트업 된후에 트랜잭션의 rollback 을 진행하지 않는다.
    4 : insert buffer merge operation(??) 을 차단한다. 또한
        테이블의 statistics 를 계산하지 않는다.
    5 : database 를 시작할때 undo logs 를 찾지 않는다. 또한 incomplete trasactions를 
        commit 된것으로 처리한다.
    6 : log roll-forward(check 포인트까지의 재실행)을 실행하지 않는다.
    보면 알겠지만 낮은 숫자에서 startup 이 될수록 복구할수 있는 데이터가 많다.
    forced recovery 가 사용되었지만 dump 를 위한 select와 drop, create tables
    등을 실행할수가 있다. 만약 특정테이블이 롤백과정중 crash 를 발생시켰는것을
    안다면 drop 시킬수가 있는것이다.
    어쨋거나 이값이 0보다 클경우 user 들은 암것도 못한다.(당근..)
    
6. iosolation level 확인
   : select @@global_tx_isolation;
     select @@tx_isolation;
7. DeadLock 대처법
   (1) show engine innodb status 로 최근의 deadlock 발생을 알수가 있다.
   (2) 만약에 locking reads(select .. for update 또는 lock in share mode)를
       사용한다면 READ COMMITED 같은 낮은 isolation level 을 써라
8. Transaction serialize
    : semaphore table 생성.
    각각의 transaction 에서 먼저 1 row  짜리의 semaphore 테이블을 업데이트 하고
    그리고 난뒤 다른 테이블을 억세스 한다.
9. Innodb Performance Tuning Tip
    (1) 긴 primary 키를 쓰지말고 auto_increment 칼럼을 만들어서 그넘을 
        primary key 로 잡아라.(its value must be stored with every secondary
        index record)
    (2) 70% 이하의 CPU 로드를 유지하고 Buffer Pool 은 80% 이내에서
        적당히 크게 잡아라.
    (3) 여러개의 변경을 하나의 transaction 으로 묶어라.
        innodb 는 반드시 각 commit 마다 로그를 disk 로 flush 해야 하기땜시로.
    (4) 로그파일의 크기를 크게 가져가라(심지어 buffer pool 크기만큼도 가능하다)
    (5) log buffer 의 크기도 크게 가져라(8MB 의 배수로)
    (6) innodb 로 데이터를 import 할겨우 autocommit mode 가 off 인지 확인하라.
    (7) multiple row insert 를 써라.
        insert into imsi values (1,2), (2,3), ...
    (7) big table import 시
        set unique_checks = 0;
        set foreign_key_checks = 0;
        ....
        set unique_checks = 1;
        set foreign_key_checks = 1;
    (8) query cache 를 써라. 
10. InnoDB 모니터링
    : (1) show engine innodb status G 를 이용한 모니터링
      (2) InnoDB Monitor 를 이용하는 방법.
          Create Table innodb_monitor (a INT) ENGINE=INNODB; 로 활성화.
          drop table innodb_monitor 로 비활성화.
          이와 유사한 방법으로 innodb_lock_monitor, innodb_tablespace_monitor,
          innodb_table_monitor 등이 있다.
         (ex) innodb_monitor 의 분석
          - TRANSACTIONS sectin : 만약에 이부분이 lock waits 값이 있다면, 어플리케이션이
            lock contention 을 가지고 있을 것이다. 또한 transaction 의 deadlock 에 대하여
            trace 할수 있도록 도움이 될것이다.
          - SEMAPHORES section : 세마포어를 기다리는 쓰레드와 얼마나 오래 spin, mutex wait, 
            rw-lock 세마포어를 기다렸는지에 대한 통계 정보.
            세마포어를 기다리는 쓰레드의 수가 많은것은 disk I/O, InnoDB 내의 Contention 이
            원인이다. Contention 은 많은 수의 쿼리또는 OS 의 쓰레드 스케줄링에 문제가 있어서
            발생했을 수가 있다. 이때 innodb_thread_concurrency 값을 낮게 해주는것이 도움이 된다.   
          - BUFFER POOL AND MEMORY section : 얼마나 많은 data file I/O 가 발행했는지 알수 있다.
          - ROW OPERATIONS section : 메인 쓰레드가 뭘하고 있는지 보여준다.
        
     (3) show engine innodb status 정보는 15초마다 innodb_status.pid 파일로 innodb 의 상태를 
         기록한다.(innodb_status_file = 1 로 세팅되어져 있을경우). mysql 의 정상적인 종료시
         해당 파일을 삭제하지만 비정상적인 종료시에는 수동으로 삭제 하여야 하며 당연히 
         비정상적인 종료일경우 문제를 해결할수 있는 정보가 여기에 기록되어 있을수가 있겠지.
11. Defragmenting Table
     (1) null alter table : alter table imsi engine=innodb ;
     (2) mysqldump -> drop -> create -> insert
12. Troubleshooting InnoDB Data Dictionay.
    : create table 하는 중간에 깨졋을 경우
         (1) .frm 파일은 없고 tablespace 에는 있는 경우인데 에러메세지가 지시하는 대로 
           (다른 데이터 베이스에서 같은 이름의 테이블을 생성하고 그때 생성된 .frm 파일을
            현재 데이터베이스로 이동. 그리고 drop)
            drop table 해보고 안되면 mysql client 를 --skip-auto-rehash 로 다시 시작해서 
            drop 시키면 된다.
         (2) .frm 파일은 있고 tablespace 에는 없는 경우 : 그냥 frm 파일만 삭제하면 된다.
      (중요) alter table 중에 crash 발생했거나 중지 했을 경우.
         : tablespace 에서 임시테이블로 생성이 되어 있슴. innodb_table_monitor를 이용하여
           테이블 이름이 #sql-.... 것을 drop 시키면 됨.(이때 테이블이름을 backtick 으로 감싸야 함).

반응형

'연구개발 > MYSQL' 카테고리의 다른 글

sysbench 설치 및 실행  (0) 2014.11.25
MySQL innodb_flush_method 튜닝 포인트  (0) 2014.11.19
nmon  (0) 2014.11.18
mysql 쿼리 결과 파일 저장  (0) 2014.11.17
MySQL filesort 알고리즘  (0) 2014.11.06
반응형

요즘 고객사에서 성능 이슈를 많이 제기하면서 튜닝 작업이 많아 졌는데

튜닝 작업전에 왜 성능이 떨어지게 되는 원인을 찾을 때 많이 쓰는 Tool 인

Nmon에 대해 포스팅 해보겠습니다.

아래 Nmon은 AIX에서 사용했을 때 입니다.

아무런 옵션 값 없이

- nmon을 입력하면 아래와 같은 화면을 볼 수 있습니다. 

현재 시스템의 간략한 정보가 보여지네요 cpu개수, processor 종류 현재 운영체제 이름 등 참고할 만한 정보가 나옵니다.



 

위의 화면에서 각각 C, M, D를 입력하면

 C는 cpu 사용률, M은 memory 사용률, D는 disk 사용률을 보여주며 다시 입력하면 해당 정보들이 사라집니다.

보통 현재 업무의 부하를 볼때 사용됩니다.

이렇게 바로 프롬프트 창에 nmon이라 치면 성능 모니터링이 가능합니다.



 위와는 다르게 nmon에 이제 옵션을 주게 되면

nmon은 이제 더 이상 모니터링이 아니라 성능 분석이 용이하게 위의 값들을 파일로 만들어 줍니다.

 



 

위의 오타들은 무시해주세요 ㅎ

nmon이라는 디렉토리를 만들어 crontab에 걸기 위한 sh을 만드는 과정입니다.

 



 위의 그림에서 보듯이 nmon -tdf -s 1 -c 60 -m /nmon 이 가장 많이 쓰이는 기본적인 형태 입니다.

(값이 일반적이지는 않습니다.)

각각 옵션을 살펴 보면 -t 옵션은 top process의 정보도 수집하여 시스템에 가장 많은 부하를 주는 process를 알 수 있습니다. -d 옵션은 disk 정보도 수집하게 하는 옵션이며 -f 는 nmon이 수집하는 정보를 파일의 형태로 저장하게 하는 것 입니다.

-s 는 정보 수집의 간격을 나타냅니다. 단위는  단위 입니다.

-c 는 수집 횟수를 나타냅니다.

즉 s의 값과 c의 값을 곱하여 nmon을 수행하는 시간을 정할 수 있습니다.

예를 들어 1분간격으로 60번의 정보를 수집한다고 하면

-s 60 -c 60 두값을 곱하면 3600 이고 이 뒤에  를 붙이게 되면 3600초로 1시간 동안 nmon이 정보를 수집하게 됩니다.

-m 은 nmon 파일이 저장되는 위치 입니다. 만약 값을 주지 않으면 최상위인 root에 파일이 저장 되게 됩니다.

예에서는 -m /nmon을 하였으니 /nmon 밑에 파일이 저장되게 되겠지요



 

밑은 crontab 에 등록하여 특정시간에 자동으로 nmon이 돌게 하는 절차 입니다.

위에 vi로 만든 sh에 실행 권한을 추가한 후



 

crontab -l 로 crontab에 무엇이 등록되어있는지 볼 수 있습니다.

(crotab에 대해서는 후일 포스팅 하겠습니다.)



crontab -e 를 명령어 프롬프트에 치시고 vi 환경으로 아래 처럼 편집 해주시면 됩니다.

crontab 의 * * * * * * 에서

첫 번째 * 은 분을

두 번째 * 은 시간을

세 번째 * 은 일을

네 번째 * 은 월을

다섯 번째 * 은 요일을

여섯 번째 * 에는 명령어나 실행 시킬 sh 을 집어 넣으면 됩니다.

그럼 아래 그림은  매월 매일 22시 마다 nmon.sh 를 수행 하겠다는 crontab 이네요





반응형

'연구개발 > MYSQL' 카테고리의 다른 글

MySQL innodb_flush_method 튜닝 포인트  (0) 2014.11.19
innodb 처음 사용시 고려  (0) 2014.11.19
mysql 쿼리 결과 파일 저장  (0) 2014.11.17
MySQL filesort 알고리즘  (0) 2014.11.06
replication 재설정  (0) 2014.10.16

+ Recent posts

반응형