[MySQL] Online DDL 별 적용 가능한 알고리즘 (8.0 이상) TECH by Sangmi Park 2023년 08월 03일 ALTER TABLE 명령을 실행하면 MySQL 서버는 다음과 같은 순서로 스키마 변경 알고리즘을 찾음. ALGORITHM=INSTANT로 스키마 변경이 가능한지 확인 후, 가능하다면 선택ALGORITHM=INPLACE로 스키마 변경이 가능한지 확인 후, 가능하다면 선택ALGORITHM=COPY 알고리즘 선택 알고리즘의 우선순위가 낮을수록 MySQL 서버는 스키마 변경을 위해 더 큰 잠금과 많은 작업을 필요로 하고, 서버의 부하도 많이 발생시킴. INSTANT : 테이블의 데이터는 전혀 변경하지 않고, 메타데이터만 변경하고 작업을 완료함. 테이블이 가진 레코드 건수와 무관하게 작업 시간은 매우 짧음. 스키마 변경 도중 테이블의 읽고 쓰기는 대기하게 되지만 스키마 변경 시간이 매우 짧기 때문에 다른 커넥션의 쿼리 처리에는 크게 영향을 미치지 않음.INPLACE : 임시 테이블로 데이터를 복사하지 않고 스키마 변경을 실행. 하지만 내부적으로는 테이블의 리빌드를 실행할 수도 있음. 레코드의 복사 작업은 없지만 테이블의 모든 레코드를 리빌드해야 하기 때문에 테이블의 크기에 따라 많은 시간이 소요될 수 있음. 하지만 스키마 변경 중에도 테이블의 읽기와 쓰기 모두 가능. INPLACE 알고리즘으로 스키마가 변경되는 경우에도 최초 시작 시점과 마지막 종료 시점에는 테이블의 읽고 쓰기가 불가함. 하지만 이 시간은 매우 짧기 때문에 다른 커넥션의 쿼리 처리에 대한 영향도는 높지 않음.COPY : 변경된 스키마를 적용한 임시 테이블을 생성하고, 테이블의 레코드를 모두 임시 테이블로 복사한 후 최종적으로 임시 테이블을 RENAME해서 스키마 변경을 완료. 이 방법은 테이블 읽기만 가능하고 DML은 실행할 수 없음. 서비스 영향을 최소화하면서 가능한 알고리즘을 확인해 보는 방법 ALGORITHM=INSTANT 옵션으로 스키마 변경을 시도실패하면 ALGORITHM=INPLACE, LOCK=NONE 옵션으로 스키마 변경을 시도실패하면 ALGORITHM=INPLACE, LOCK=SHARED 옵션으로 스키마 변경을 시도실패하면 ALGORITHM=COPY, LOCK=SHARED 옵션으로 스키마 변경을 시도실패하면 ALGORITHM=COPY, LOCK=EXCLUSIVE 옵션으로 스키마 변경을 시도>> 1, 2번으로 되지 않는다면 DML을 멈춘 다음 스키마 변경을 해야 하는 작업임. 스키마 변경 작업의 진행 상황은 performance_schema.events_stages_current 테이블을 통해 확인 mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATEDFROM performance_schema.events_stages_current;>> WORK_COMPLETED / WORK_ESTIMATED * 100 : 진행률 Online DDL 별 적용 가능한 알고리즘 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 08월 03일
[MySQL] Partition add & drop 자동화 테스트 TECH by Sangmi Park 2023년 07월 14일 1. Partition Drop 월 별 혹은 년도 별 Partition Table을 관리할 때, 과거 파티션을 삭제하는 과정을 크게 두 가지의 방법으로 테스트해 보았습니다. 해당 테스트를 진행한 이유는 두 가지 방법에 대해 효용성을 체크하기 위함이며, alter drop partition 보다 exchange partition이 수행 속도가 빠르다면 Partition Table에 걸리는 Lock을 최소화하여 서비스를 원활하게 할 수 있지 않을까라는 기대를 예상했습니다.첫 번째는 별도의 일반 테이블(0건)을 만들고, Drop할 파티션과 Exchange를 한 후 일반 테이블을 삭제하는 방법입니다. 이 경우 일반 테이블에 과거 테이블을 이력으로도 남길 수 있다는 장점이 있습니다. 두 번째는 대상 Partition Table에 ALTER DROP PARTITION 을 수행하여 바로 DDL을 날리는 과정이며, online DDL을 수행하는 과정에서 DML을 따로 받을 수 있습니다. 1-1. TEST 환경구성 항목설 명DatabaseRDS MySQL 8.0.23Sysbench[ec2-user@ip-10-0-130-172 ~]$ sysbench –versionsysbench 1.0.20Test Table1. Descriptionmysql> CREATE TABLE `sbtest1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `k` int(11) NOT NULL DEFAULT ‘0’, `c` char(120) NOT NULL DEFAULT ”, `pad` char(60) NOT NULL DEFAULT ”, PRIMARY KEY (`id`), KEY `k_1` (`k`)) ENGINE=InnoDB AUTO_INCREMENT=100000001 DEFAULT CHARSET=utf8PARTITION BY RANGE (id)(PARTITION p1 VALUES LESS THAN (30000000) ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN (60000000) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (90000000) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (120000000) ENGINE = InnoDB);2. Data 적재Sysbench를 이용해 sbtest1 테이블에 1억건 적재sysbench –db-driver=mysql –mysql-host=bjh-test-partition.cnaj6ucovzx2.ap-northeast-2.rds.amazonaws.com –mysql-user=admin –mysql-password=qkswlgus –mysql-db=sysbench –table-size=100000000 –tables=1 /usr/share/sysbench/oltp_read_only.lua prepare 1-2. Exchange Partition Test 시나리오설 명1) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+——————+———————–+————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_METHOD | PARTITION_DESCRIPTION | TABLE_ROWS |+————–+————+—————-+—————————-+——————+———————–+————+| sysbench | sbtest1 | p2 | 1 | RANGE | 60000000 | 29592144 || sysbench | sbtest1 | p3 | 2 | RANGE | 90000000 | 29592576 || sysbench | sbtest1 | p4 | 3 | RANGE | 120000000 | 9863928 |+————–+————+—————-+—————————-+——————+———————–+————+2) 원본 테이블 Row확인mysql> select table_schema, table_name, partition_name, table_rows from information_schema.PARTITIONS where TABLE_NAME=’sbtest1′;+————–+————+—————-+————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |+————–+————+—————-+————+| sysbench | sbtest1 | p2 | 29592144 || sysbench | sbtest1 | p3 | 29592576 || sysbench | sbtest1 | p4 | 9863928 |+————–+————+—————-+————+4 rows in set (0.01 sec) 3) Drop Partition 수행mysql> alter table sbtest1 drop partition p2;MySQL [sysbench]> alter table sbtest1 drop partition p2;Query OK, 0 rows affected (0.16 sec)Records: 0 Duplicates: 0 Warnings: 0 1-3. ALTER DROP Partition 시나리오설 명1) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+——————+———————–+————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_METHOD | PARTITION_DESCRIPTION | TABLE_ROWS |+————–+————+—————-+—————————-+——————+———————–+————+| sysbench | sbtest1 | p2 | 1 | RANGE | 60000000 | 29592144 || sysbench | sbtest1 | p3 | 2 | RANGE | 90000000 | 29592576 || sysbench | sbtest1 | p4 | 3 | RANGE | 120000000 | 9863928 |+————–+————+—————-+—————————-+——————+———————–+————+2) 원본 테이블 Row확인mysql> select table_schema, table_name, partition_name, table_rows from information_schema.PARTITIONS where TABLE_NAME=’sbtest1′;+————–+————+—————-+————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | TABLE_ROWS |+————–+————+—————-+————+| sysbench | sbtest1 | p2 | 29592144 || sysbench | sbtest1 | p3 | 29592576 || sysbench | sbtest1 | p4 | 9863928 |+————–+————+—————-+————+4 rows in set (0.01 sec) 3) Drop Partition 수행mysql> alter table sbtest1 drop partition p2;MySQL [sysbench]> alter table sbtest1 drop partition p2;Query OK, 0 rows affected (0.16 sec)Records: 0 Duplicates: 0 Warnings: 0 2. Partition Add 파티션 테이블에 maxvalue 파티션을 가지고 있을 경우와 없는 경우 add partition 을 할 수 있는 방법또한 달라집니다. maxvalue 파티션이 없을 경우에는 단순히 add partition이 가능하지만 있을 경우에는 add partition을 진행할 경우 Error Code : 1481이 발생하게 됩니다. 2-1. Maxvalue 파티션이 없을 경우 시나리오설 명1) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+———————–+————+————–+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_DESCRIPTION | TABLE_ROWS | INDEX_LENGTH |+————–+————+—————-+—————————-+———————–+————+————–+| sysbench | sbtest1 | p3 | 1 | 90000000 | 29592576 | 624902144 || sysbench | sbtest1 | p4 | 2 | 120000000 | 9863928 | 248266752 || sysbench | sbtest1 | p5 | 3 | 150000000 | 0 | 16384 |+————–+————+—————-+—————————-+———————–+————+————–+ 2) 파티션 추가mysql> alter table sbtest1 add partition (partition p6 values less than (180000000));MySQL [sysbench]> alter table sbtest1 add partition (partition p6 values less than (180000000));Query OK, 0 rows affected (0.12 sec)Records: 0 Duplicates: 0 Warnings: 03) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+———————–+————+————–+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_DESCRIPTION | TABLE_ROWS | INDEX_LENGTH |+————–+————+—————-+—————————-+———————–+————+————–+| sysbench | sbtest1 | p3 | 1 | 90000000 | 29592576 | 624902144 || sysbench | sbtest1 | p4 | 2 | 120000000 | 9863928 | 248266752 || sysbench | sbtest1 | p5 | 3 | 150000000 | 0 | 16384 || sysbench | sbtest1 | p6 | 4 | 180000000 | 0 | 16384 |+————–+————+—————-+—————————-+———————–+————+————–+ 2-2. Maxvalue 파티션이 있을 경우 시나리오설 명1) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+———————–+————+————–+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_DESCRIPTION | TABLE_ROWS | INDEX_LENGTH |+————–+————+—————-+—————————-+———————–+————+————–+| sysbench | sbtest1 | p3 | 1 | 90000000 | 29592576 | 624902144 || sysbench | sbtest1 | p4 | 2 | 120000000 | 9863928 | 248266752 || sysbench | sbtest1 | p5 | 3 | 150000000 | 0 | 16384 || sysbench | sbtest1 | p6 | 4 | 180000000 | 0 | 16384 || sysbench | sbtest1 | p7 | 5 | MAXVALUE | 0 | 16384 |+————–+————+—————-+—————————-+———————–+————+————–+ 2) 파티션 추가 (에러발생)mysql> alter table sbtest1 add partition (partition p6 values less than (200000000));MySQL [sysbench]> alter table sbtest1 add partition (partition p6 values less than (200000000));ERROR 1481 (HY000): MAXVALUE can only be used in last partition definition3) REORGANIZE 파티션mysql> select * from information_schema.partitions where table_schema=’sysbench’;MySQL [sysbench]> ALTER TABLE sbtest1 -> REORGANIZE PARTITION p7 into ( -> partition p7 values less than (200000000) engine=innodb, -> PARTITION p8 VALUES LESS THAN (MAXVALUE) ENGINE = InnoDB -> );Query OK, 0 rows affected (0.12 sec)Records: 0 Duplicates: 0 Warnings: 04) 파티션테이블 상태 조회mysql> select * from information_schema.partitions where table_schema=’sysbench’;+————–+————+—————-+—————————-+———————–+————+————-+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_ORDINAL_POSITION | PARTITION_DESCRIPTION | TABLE_ROWS | DATA_LENGTH |+————–+————+—————-+—————————-+———————–+————+————-+| sysbench | sbtest1 | p3 | 1 | 90000000 | 29592576 | 6740246528 || sysbench | sbtest1 | p4 | 2 | 120000000 | 9863928 | 2248146944 || sysbench | sbtest1 | p5 | 3 | 150000000 | 0 | 16384 || sysbench | sbtest1 | p6 | 4 | 180000000 | 0 | 16384 || sysbench | sbtest1 | p7 | 5 | 200000000 | 0 | 16384 || sysbench | sbtest1 | p8 | 6 | MAXVALUE | 0 | 16384 | 3. Partition 관리 자동화 신규 파티션 추가와 삭제를 매번 수작업으로 진행할 수는 없으므로 이를 자동으로 관리하기 위한 프로시저 및 이벤트를 생성하는 과정을 진행하였습니다. 파티션 관리 요건 중 가장 중요한 것은 다음의 세가지입니다.1. 어떠한 이유에서든지 프로시저가 동작하지 않은 경우라도 데이터 Insert 실패가 발생하지 않도록 할 것.2. 프로시저가 일정기간 동작하지 않고, 다시 재기동 되는 경우에 프로시저가 주기적으로 동작했던 것과 동일한 파티션 구조를 생성할 것.3. 파티션 삭제시 Table Lock으로 인한 영향을 최소화할 것.처음 이 파티션 테스트를 진행하기 전에는 파티션의 MAXVALUE가 테이블의 관리나 성능적인 측면에서 필요 없다고 생각하였으나, 1번의 내용과 같이 파티션 관리 프로시저가 며칠 동안 동작하지 않을 경우 서비스 자체가 운영되지 않을 수 있기 때문에 반드시 존재해야 한다고 제 개인적인 생각을 바꾸게 되었습니다. 또한, 앞서 테스트한 경우와 마찬가지로 파티션 drop은 단순한 alter문이 아닌 partition exchange로 진행하여 3번에 해당하는 Table Lock 최소화도 고려하였습니다. 3-1. Partition Create Procedure Create Partition Procedure 문 (Terminal 수행을 위해 DELIMITER 변경 후 진행)DELIMITER $$CREATE PROCEDURE create_partition(p_dbname varchar(255), p_tbname varchar(255), p_future INT, p_interval INT)SQL SECURITY INVOKERBEGIN DECLARE x, max_pdesc, new_pdesc INT; DECLARE pname VARCHAR(64); DECLARE alter_cmd VARCHAR(1024); — 현재 테이블의 파티션의 가장 마지막 파티션의 HIGH VALUE 값을 구함 SELECT MAX(PARTITION_DESCRIPTION) – TO_DAYS(current_date()) INTO x FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION != ‘MAXVALUE’ ; — 파티션 미리 생성할 기한까지 지정한 interval에 맞도록 파티션 추가 — 파티션 추가는 ADD PARTITION이 아닌 MAXVALUE 파티션의 REORGANIZE로 처리됨 WHILE x <= p_future DO SELECT CONCAT(‘p’, DATE_FORMAT(current_date() + interval MAX(PARTITION_DESCRIPTION) – TO_DAYS(current_date()) day, ‘%Y%m%d’)), MAX(PARTITION_DESCRIPTION), MAX(PARTITION_DESCRIPTION) + p_interval INTO pname, max_pdesc, new_pdesc FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION!=’MAXVALUE’; IF max_pdesc < new_pdesc THEN SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘.’, p_tbname, ‘ REORGANIZE PARTITION pMAXVALUE INTO (‘, ‘PARTITION ‘, pname, ‘ VALUES LESS THAN (‘, new_pdesc, ‘), PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE)’ ); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; END IF; SET x = x + p_interval; END WHILE; — 파티션 정보 출력 (옵션) SELECT current_date() + interval MAX(PARTITION_DESCRIPTION) – TO_DAYS(current_date()) – 1 day AS Last_Date, COUNT(*) AS Partitions_For_Future FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION != ‘MAXVALUE’ AND PARTITION_DESCRIPTION > TO_DAYS(current_date()) + 1;END $$DELIMITER ; 3-1-1. Partition Create Procedure 시나리오설 명1) 파티션테이블 생성Range Partition Create 구문 (Maxvalue 파티션 필요)CREATE TABLE partitiontest ( id int NOT NULL AUTO_INCREMENT, some_data varchar(100), createdAt datetime(6) NOT NULL, modifiedAt datetime(6) DEFAULT NULL, PRIMARY KEY (id,createdAt)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8partition by range (to_days(createdAt))(partition p20221201 values less than (to_days(‘2022-12-02’)) ENGINE = InnoDB,partition p20221202 values less than (to_days(‘2022-12-03’)) ENGINE = InnoDB,partition p20221203 values less than (to_days(‘2022-12-04’)) ENGINE = InnoDB,partition p20221204 values less than (to_days(‘2022-12-05’)) ENGINE = InnoDB,partition p20221205 values less than (to_days(‘2022-12-06’)) ENGINE = InnoDB,partition p20221206 values less than (to_days(‘2022-12-07’)) ENGINE = InnoDB,partition p20221207 values less than (to_days(‘2022-12-08’)) ENGINE = InnoDB,partition p20221208 values less than (to_days(‘2022-12-09’)) ENGINE = InnoDB,partition p20221209 values less than (to_days(‘2022-12-10’)) ENGINE = InnoDB,partition p20221210 values less than (to_days(‘2022-12-11’)) ENGINE = InnoDB,partition p20221211 values less than (to_days(‘2022-12-12’)) ENGINE = InnoDB,partition p20221212 values less than (to_days(‘2022-12-13’)) ENGINE = InnoDB,partition p20221213 values less than (to_days(‘2022-12-14’)) ENGINE = InnoDB,partition p20221214 values less than (to_days(‘2022-12-15’)) ENGINE = InnoDB,partition p20221215 values less than (to_days(‘2022-12-16’)) ENGINE = InnoDB,partition p20221216 values less than (to_days(‘2022-12-17’)) ENGINE = InnoDB,partition p20221217 values less than (to_days(‘2022-12-18’)) ENGINE = InnoDB,partition p20221218 values less than (to_days(‘2022-12-19’)) ENGINE = InnoDB,partition p20221219 values less than (to_days(‘2022-12-20’)) ENGINE = InnoDB,partition pMAXVALUE values less than (maxvalue) ENGINE = InnoDB);2) 파티션 조회MySQL [bjh]> select * from information_schema.partitions where table_schema=’bjh’ and table_name=’partitiontest’;+————–+—————+—————-+—————–+———————-+———————–+———————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME |PARTITION_METHOD | PARTITION_EXPRESSION | PARTITION_DESCRIPTION | CREATE_TIME |+————–+—————+—————-+—————–+———————-+———————–+———————+| bjh | partitiontest | p20221201 |RANGE | to_days(`createdAt`) | 738856 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221202 |RANGE | to_days(`createdAt`) | 738857 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221203 |RANGE | to_days(`createdAt`) | 738858 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221204 |RANGE | to_days(`createdAt`) | 738859 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221205 |RANGE | to_days(`createdAt`) | 738860 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221206 |RANGE | to_days(`createdAt`) | 738861 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221207 |RANGE | to_days(`createdAt`) | 738862 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221208 |RANGE | to_days(`createdAt`) | 738863 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221209 |RANGE | to_days(`createdAt`) | 738864 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221210 |RANGE | to_days(`createdAt`) | 738865 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221211 |RANGE | to_days(`createdAt`) | 738866 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221212 |RANGE | to_days(`createdAt`) | 738867 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221213 |RANGE | to_days(`createdAt`) | 738868 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221214 |RANGE | to_days(`createdAt`) | 738869 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221215 |RANGE | to_days(`createdAt`) | 738870 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221216 |RANGE | to_days(`createdAt`) | 738871 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221217 |RANGE | to_days(`createdAt`) | 738872 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221218 |RANGE | to_days(`createdAt`) | 738873 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221219 |RANGE | to_days(`createdAt`) | 738874 | 2022-12-19 04:47:35 || bjh | partitiontest | pMAXVALUE |RANGE | to_days(`createdAt`) | MAXVALUE | 2022-12-19 04:47:35 |+————–+—————+—————-+—————–+———————-+———————–+———————+3) 프로시저 수행MySQL [mysql]> call create_partition(‘bjh’, ‘partitiontest’, 1, 1);프로시저 해석 : bjh.partitiontest 테이블을 금일 날짜(테스트 날짜 :2022-12-19) 기준으로 1일 후까지 1일 간격으로 파티션을 생성.+————+———————–+| Last_Date | Partitions_For_Future |+————+———————–+| 2022-12-20 | 1 |+————+———————–+1 row in set (0.25 sec)Query OK, 0 rows affected (0.25 sec)3-1) 파티션 결과 조회MySQL [mysql]> select * from information_schema.partitions where table_schema=’bjh’ and table_name=’partitiontest’;+————–+—————+—————-+—————–+———————+———————–+———————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME |PARTITION_METHOD |PARTITION_EXPRESSION | PARTITION_DESCRIPTION | CREATE_TIME |+————–+—————+—————-+—————–+———————+———————–+———————+| bjh | partitiontest | p20221201 |RANGE |to_days(`createdAt`) | 738856 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221202 |RANGE |to_days(`createdAt`) | 738857 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221203 |RANGE |to_days(`createdAt`) | 738858 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221204 |RANGE |to_days(`createdAt`) | 738859 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221205 |RANGE |to_days(`createdAt`) | 738860 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221206 |RANGE |to_days(`createdAt`) | 738861 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221207 |RANGE |to_days(`createdAt`) | 738862 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221208 |RANGE |to_days(`createdAt`) | 738863 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221209 |RANGE |to_days(`createdAt`) | 738864 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221210 |RANGE |to_days(`createdAt`) | 738865 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221211 |RANGE |to_days(`createdAt`) | 738866 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221212 |RANGE |to_days(`createdAt`) | 738867 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221213 |RANGE |to_days(`createdAt`) | 738868 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221214 |RANGE |to_days(`createdAt`) | 738869 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221215 |RANGE |to_days(`createdAt`) | 738870 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221216 |RANGE |to_days(`createdAt`) | 738871 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221217 |RANGE |to_days(`createdAt`) | 738872 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221218 |RANGE |to_days(`createdAt`) | 738873 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221219 |RANGE |to_days(`createdAt`) | 738874 | 2022-12-19 05:09:59 || bjh | partitiontest | p20221220 |RANGE |to_days(`createdAt`) | 738875 | 2022-12-19 05:09:59 || bjh | partitiontest | pMAXVALUE |RANGE |to_days(`createdAt`) | MAXVALUE | 2022-12-19 05:09:59 |+————–+—————+—————-+—————–+———————+———————–+———————+4) 프로시저 수행MySQL [mysql]> call create_partition(‘bjh’, ‘partitiontest’, 7, 1);프로시저 해석 : bjh.partitiontest 테이블을 금일 날짜(테스트 날짜 :2022-12-19) 기준으로 7일 후까지 1일 간격으로 파티션을 생성.+————+———————–+| Last_Date | Partitions_For_Future |+————+———————–+| 2022-12-26 | 7 |+————+———————–+1 row in set (1.52 sec)Query OK, 0 rows affected (1.52 sec)4-1) 파티션 결과 조회MySQL [mysql]> select * from information_schema.partitions where table_schema=’bjh’ and table_name=’partitiontest’;+————–+—————+—————-+—————–+———————-+———————–+———————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME |PARTITION_METHOD | PARTITION_EXPRESSION | PARTITION_DESCRIPTION | CREATE_TIME |+————–+—————+—————-+—————–+———————-+———————–+———————+| bjh | partitiontest | p20221201 |RANGE | to_days(`createdAt`) | 738856 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221202 |RANGE | to_days(`createdAt`) | 738857 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221203 |RANGE | to_days(`createdAt`) | 738858 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221204 |RANGE | to_days(`createdAt`) | 738859 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221205 |RANGE | to_days(`createdAt`) | 738860 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221206 |RANGE | to_days(`createdAt`) | 738861 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221207 |RANGE | to_days(`createdAt`) | 738862 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221208 |RANGE | to_days(`createdAt`) | 738863 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221209 |RANGE | to_days(`createdAt`) | 738864 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221210 |RANGE | to_days(`createdAt`) | 738865 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221211 |RANGE | to_days(`createdAt`) | 738866 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221212 |RANGE | to_days(`createdAt`) | 738867 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221213 |RANGE | to_days(`createdAt`) | 738868 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221214 |RANGE | to_days(`createdAt`) | 738869 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221215 |RANGE | to_days(`createdAt`) | 738870 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221216 |RANGE | to_days(`createdAt`) | 738871 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221217 |RANGE | to_days(`createdAt`) | 738872 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221218 |RANGE | to_days(`createdAt`) | 738873 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221219 |RANGE | to_days(`createdAt`) | 738874 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221220 |RANGE | to_days(`createdAt`) | 738875 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221221 |RANGE | to_days(`createdAt`) | 738876 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221222 |RANGE | to_days(`createdAt`) | 738877 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221223 |RANGE | to_days(`createdAt`) | 738878 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221224 |RANGE | to_days(`createdAt`) | 738879 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221225 |RANGE | to_days(`createdAt`) | 738880 | 2022-12-19 05:11:32 || bjh | partitiontest | p20221226 |RANGE | to_days(`createdAt`) | 738881 | 2022-12-19 05:11:32 || bjh | partitiontest | pMAXVALUE |RANGE | to_days(`createdAt`) | MAXVALUE | 2022-12-19 05:11:32 |+————–+—————+—————-+—————–+———————-+———————–+———————+ 3-1-2. 알게된 점 해당 프로시저를 수행할 때, 파티션에 중복 (시나리오3), 4)번 과정에서는2022-12-20의 파티션이 중복 수행됨.)이 있다고 하더라도 오류없이 파티션이 정상적으로 추가가 되었습니다. 또한, information_schema.partitions 테이블의 create_time 컬럼을 조회할 때 추가된 컬럼에 한해서만 갱신이 되는 것이 아니라, 파티션 전체에 대해 파티션을 추가한 시간으로 동일하게 갱신되어 있었습니다. 3-2. Partition Drop Procedure Drop Partition Procedure 문 (Terminal 수행을 위해 DELIMITER 변경 후 진행)DELIMITER $$CREATE PROCEDURE delete_partition(p_dbname varchar(255), p_tbname varchar(255), p_del_date INT)SQL SECURITY INVOKERBEGIN DECLARE done INT; DECLARE pname VARCHAR(64); DECLARE alter_cmd VARCHAR(1024); DECLARE deleted_partition VARCHAR(1024); — 삭제할 파티션 목록 취합 DECLARE cur CURSOR FOR SELECT PARTITION_NAME FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION!=’MAXVALUE’ AND PARTITION_DESCRIPTION<=TO_DAYS(current_date()) – p_del_date ; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET done = 0; — 삭제 대상 파티션 목록 확인 및 작업 완료 후 출력 (옵션) SELECT GROUP_CONCAT(PARTITION_NAME) INTO deleted_partition FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION!=’MAXVALUE’ AND PARTITION_DESCRIPTION<=TO_DAYS(current_date()) – p_del_date ; OPEN cur; FETCH cur INTO pname; WHILE done = 0 DO — MySQL 5.6 버전 이상인 경우 동일 스키마로 빈 테이블을 만들어서 PARTITION EXCHANGE 처리 후 DROP PARTITION — 파티션 삭제 처리 시간 지연으로 인한 Table Lock 영향을 최소화하기 위함 IF left(version(),3) >= ‘5.6’ THEN — make empty table for exchange SET @alter_sql := CONCAT(‘CREATE TABLE ‘, p_dbname, ‘._exchange_’, p_tbname,’_’,pname, ‘ LIKE ‘, p_dbname, ‘.’ , p_tbname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘._exchange_’, p_tbname,’_’,pname, ‘ REMOVE PARTITIONING’); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; — exchange SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘.’, p_tbname, ‘ EXCHANGE PARTITION ‘, pname, ‘ WITH TABLE ‘, p_dbname, ‘._exchange_’, p_tbname, ‘_’, pname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; — drop tmp table — SET @alter_sql := CONCAT(‘DROP TABLE ‘, p_dbname, ‘._exchange_’, p_tbname); — PREPARE alter_cmd FROM @alter_sql; — EXECUTE alter_cmd; — DEALLOCATE PREPARE alter_cmd; END IF; — 파티션 삭제 SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘.’, p_tbname, ‘ DROP PARTITION ‘, pname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; FETCH cur INTO pname; END WHILE; CLOSE cur; — 삭제 처리한 파티션 목록 출력 (옵션) SELECT deleted_partition AS Deleted_Partitions ;END $$DELIMITER ; Switching한 Temp Table을Drop하는 부분은 현재 진행중인 프로젝트에서 History보관주기가 변경될 수 있어 일단 주석으로 처리한 후 테스트를 진행하였습니다. 3-2-1. Partition Drop Procedure (임시테이블 유지) 시나리오설 명1) 파티션테이블 생성Range Partition Create 구문CREATE TABLE partitiontest ( id int NOT NULL AUTO_INCREMENT, some_data varchar(100), createdAt datetime(6) NOT NULL, modifiedAt datetime(6) DEFAULT NULL, PRIMARY KEY (id,createdAt)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8partition by range (to_days(createdAt))(partition p20221201 values less than (to_days(‘2022-12-02’)) ENGINE = InnoDB,partition p20221202 values less than (to_days(‘2022-12-03’)) ENGINE = InnoDB,partition p20221203 values less than (to_days(‘2022-12-04’)) ENGINE = InnoDB,partition p20221204 values less than (to_days(‘2022-12-05’)) ENGINE = InnoDB,partition p20221205 values less than (to_days(‘2022-12-06’)) ENGINE = InnoDB,partition p20221206 values less than (to_days(‘2022-12-07’)) ENGINE = InnoDB,partition p20221207 values less than (to_days(‘2022-12-08’)) ENGINE = InnoDB,partition p20221208 values less than (to_days(‘2022-12-09’)) ENGINE = InnoDB,partition p20221209 values less than (to_days(‘2022-12-10’)) ENGINE = InnoDB,partition p20221210 values less than (to_days(‘2022-12-11’)) ENGINE = InnoDB,partition p20221211 values less than (to_days(‘2022-12-12’)) ENGINE = InnoDB,partition p20221212 values less than (to_days(‘2022-12-13’)) ENGINE = InnoDB,partition p20221213 values less than (to_days(‘2022-12-14’)) ENGINE = InnoDB,partition p20221214 values less than (to_days(‘2022-12-15’)) ENGINE = InnoDB,partition p20221215 values less than (to_days(‘2022-12-16’)) ENGINE = InnoDB,partition p20221216 values less than (to_days(‘2022-12-17’)) ENGINE = InnoDB,partition p20221217 values less than (to_days(‘2022-12-18’)) ENGINE = InnoDB,partition p20221218 values less than (to_days(‘2022-12-19’)) ENGINE = InnoDB,partition p20221219 values less than (to_days(‘2022-12-20’)) ENGINE = InnoDB,partition pMAXVALUE values less than (maxvalue) ENGINE = InnoDB);2) 파티션 조회MySQL [bjh]> select * from information_schema.partitions where table_schema=’bjh’ and table_name=’partitiontest’;+————–+—————+—————-+—————–+———————-+———————–+———————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME |PARTITION_METHOD | PARTITION_EXPRESSION | PARTITION_DESCRIPTION | CREATE_TIME |+————–+—————+—————-+—————–+———————-+———————–+———————+| bjh | partitiontest | p20221201 |RANGE | to_days(`createdAt`) | 738856 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221202 |RANGE | to_days(`createdAt`) | 738857 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221203 |RANGE | to_days(`createdAt`) | 738858 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221204 |RANGE | to_days(`createdAt`) | 738859 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221205 |RANGE | to_days(`createdAt`) | 738860 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221206 |RANGE | to_days(`createdAt`) | 738861 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221207 |RANGE | to_days(`createdAt`) | 738862 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221208 |RANGE | to_days(`createdAt`) | 738863 | 2022-12-19 04:47:35 | … 중략 …| bjh | partitiontest | p20221214 |RANGE | to_days(`createdAt`) | 738869 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221215 |RANGE | to_days(`createdAt`) | 738870 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221216 |RANGE | to_days(`createdAt`) | 738871 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221217 |RANGE | to_days(`createdAt`) | 738872 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221218 |RANGE | to_days(`createdAt`) | 738873 | 2022-12-19 04:47:35 || bjh | partitiontest | p20221219 |RANGE | to_days(`createdAt`) | 738874 | 2022-12-19 04:47:35 || bjh | partitiontest | pMAXVALUE |RANGE | to_days(`createdAt`) | MAXVALUE | 2022-12-19 04:47:35 |+————–+—————+—————-+—————–+———————-+———————–+———————+3) 프로시저 수행MySQL [mysql]> call mysql.delete_partition(‘bjh’, ‘partitiontest’, 16);프로시저 해석 : bjh.partitiontest 테이블을 금일 날짜(테스트 날짜 :2022-12-19) 기준으로 16일이 경과한 파티션을 삭제.+———————+| Deleted_Partitions |+———————+| p20221201,p20221202 |+———————+1 row in set (5.46 sec)Query OK, 0 rows affected (5.46 sec)3-1) 파티션 결과 조회MySQL [mysql]> select * from information_schema.partitions where table_schema=’bjh’ and table_name=’partitiontest’;+————–+—————+—————-+——————+———————-+———————–+———————+| TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | PARTITION_METHOD | PARTITION_EXPRESSION | PARTITION_DESCRIPTION | CREATE_TIME |+————–+—————+—————-+——————+———————-+———————–+———————+| bjh | partitiontest | p20221203 | RANGE | to_days(`createdAt`) | 738858 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221204 | RANGE | to_days(`createdAt`) | 738859 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221205 | RANGE | to_days(`createdAt`) | 738860 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221206 | RANGE | to_days(`createdAt`) | 738861 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221207 | RANGE | to_days(`createdAt`) | 738862 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221208 | RANGE | to_days(`createdAt`) | 738863 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221209 | RANGE | to_days(`createdAt`) | 738864 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221210 | RANGE | to_days(`createdAt`) | 738865 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221211 | RANGE | to_days(`createdAt`) | 738866 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221212 | RANGE | to_days(`createdAt`) | 738867 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221213 | RANGE | to_days(`createdAt`) | 738868 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221214 | RANGE | to_days(`createdAt`) | 738869 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221215 | RANGE | to_days(`createdAt`) | 738870 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221216 | RANGE | to_days(`createdAt`) | 738871 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221217 | RANGE | to_days(`createdAt`) | 738872 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221218 | RANGE | to_days(`createdAt`) | 738873 | 2022-12-19 06:32:45 || bjh | partitiontest | p20221219 | RANGE | to_days(`createdAt`) | 738874 | 2022-12-19 06:32:45 || bjh | partitiontest | pMAXVALUE | RANGE | to_days(`createdAt`) | MAXVALUE | 2022-12-19 06:32:45 |+————–+—————+—————-+——————+———————-+———————–+———————+4) 임시테이블 존재 확인MySQL [bjh]> show tables;+———————————–+| Tables_in_bjh |+———————————–+| _exchange_partitiontest_p20221201 || _exchange_partitiontest_p20221202 || partitiontest |+———————————–+3 rows in set (0.00 sec)4-1) 임시테이블 존재 확인MySQL [bjh]> describe _exchange_partitiontest_p20221202;MySQL [bjh]> describe _exchange_partitiontest_p20221202;+————+————–+——+—–+———+—————-+| Field | Type | Null | Key | Default | Extra |+————+————–+——+—–+———+—————-+| id | int | NO | PRI | NULL | auto_increment || some_data | varchar(100) | YES | | NULL | || createdAt | datetime(6) | NO | PRI | NULL | || modifiedAt | datetime(6) | YES | | NULL | |+————+————–+——+—–+———+—————-+4 rows in set (0.00 sec) 3-2-2. Partition Drop Procedure (임시테이블 삭제) 앞서 테스트 한 프로시저는Exchange된 일반 테이블을 drop하지 않고 그대로 남겨 이력을 가져가고자 할 때 사용할 수 있는 프로시저입니다.일반 테이블이 필요 없을 때에는 아래의 프로시저를 사용하여 즉시 Drop 할 수 있습니다. (앞의 프로시저와 내용이 조금씩 다르므로 구문 전체 복사가 필요합니다.)Drop Partition Procedure 문 (Terminal 수행을 위해 DELIMITER 변경 후 진행)DELIMITER $$CREATE PROCEDURE delete_partition(p_dbname varchar(255), p_tbname varchar(255), p_del_date INT)SQL SECURITY INVOKERBEGIN DECLARE done INT; DECLARE pname VARCHAR(64); DECLARE alter_cmd VARCHAR(1024); DECLARE deleted_partition VARCHAR(1024); — 삭제할 파티션 목록 취합 DECLARE cur CURSOR FOR SELECT PARTITION_NAME FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION!=’MAXVALUE’ AND PARTITION_DESCRIPTION<=TO_DAYS(current_date()) – p_del_date ; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET done = 0; — 삭제 대상 파티션 목록 확인 및 작업 완료 후 출력 (옵션) SELECT GROUP_CONCAT(PARTITION_NAME) INTO deleted_partition FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = p_dbname AND TABLE_NAME = p_tbname AND PARTITION_DESCRIPTION!=’MAXVALUE’ AND PARTITION_DESCRIPTION<=TO_DAYS(current_date()) – p_del_date ; OPEN cur; FETCH cur INTO pname; WHILE done = 0 DO — MySQL 5.6 버전 이상인 경우 동일 스키마로 빈 테이블을 만들어서 PARTITION EXCHANGE 처리 후 DROP PARTITION — 파티션 삭제 처리 시간 지연으로 인한 Table Lock 영향을 최소화하기 위함 IF left(version(),3) >= ‘5.6’ THEN — make empty table for exchange SET @alter_sql := CONCAT(‘CREATE TABLE ‘, p_dbname, ‘._exchange_’, p_tbname, ‘ LIKE ‘, p_dbname, ‘.’ , p_tbname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘._exchange_’, p_tbname, ‘ REMOVE PARTITIONING’); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; — exchange SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘.’, p_tbname, ‘ EXCHANGE PARTITION ‘, pname, ‘ WITH TABLE ‘, p_dbname, ‘._exchange_’, p_tbname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; — drop tmp table SET @alter_sql := CONCAT(‘DROP TABLE ‘, p_dbname, ‘._exchange_’, p_tbname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; END IF; — 파티션 삭제 SET @alter_sql := CONCAT(‘ALTER TABLE ‘, p_dbname, ‘.’, p_tbname, ‘ DROP PARTITION ‘, pname); PREPARE alter_cmd FROM @alter_sql; EXECUTE alter_cmd; DEALLOCATE PREPARE alter_cmd; FETCH cur INTO pname; END WHILE; CLOSE cur; — 삭제 처리한 파티션 목록 출력 (옵션) SELECT deleted_partition AS Deleted_Partitions ;END $$DELIMITER ; 3-3. Procedure Event 등록 앞의 Drop & Add 파티션 프로시저를 가지고 이벤트 스케줄러러나 crontab(이벤트 스케줄러 미지원 버전의 경우)에 등록합니다.이벤트 스케줄러 사용 시, event_scheduler 파라미터 ON 여부도 확인해야 합니다.사전 준비사항SET GLOBAL activate_all_roles_on_login=ON; — 해당 파라미터 ON 확인— 이벤트 생성 및 실행에 필요한 권한 부여MySQL [mysql]> grant event on *.* to `admin`@`%`;MySQL [mysql]> grant execute on procedure mysql.delete_partition to `admin`@`%`;MySQL [mysql]> grant execute on procedure mysql.create_partition to `admin`@`%`;MySQL [mysql]> flush privileges;Drop & Add Partition Event Scheduler (Terminal 수행을 위해 DELIMITER 변경 후 진행)DELIMITER $$drop event if exists evt_partition_management $$CREATE DEFINER=`admin`@`%` EVENT evt_partition_managementON SCHEDULE EVERY ‘1’ DAY STARTS ‘2022-12-20 01:00:00’ — 스케쥴러 시작 시점은 반드시 현재 날짜 기준으로 미래 시점이어야 함DOBEGIN call mysql.delete_partition(‘bjh’, ‘partitiontest’, 10); call mysql.create_partition(‘bjh’, ‘partitiontest’, 3, 1);END $$DELIMITER ;Event 등록 확인MySQL [mysql]> show events;+——-+—————————+——————–+—————-+—————-+———————+——+———-+| Db | Name | Definer | Interval value | Interval field | Starts | Ends | Status |+——-+—————————+——————–+—————-+—————-+———————+——+———-+| mysql | evt_partition_management | admin@% | 1 | DAY | 2022-12-20 01:00:00 | NULL | ENABLED || mysql | ev_rds_gsh_collector | rdsadmin@localhost | 5 | MINUTE | 2022-12-19 04:19:42 | NULL | DISABLED || mysql | ev_rds_gsh_table_rotation | rdsadmin@localhost | 7 | DAY | 2022-12-26 04:19:42 | NULL | DISABLED |+——-+—————————+——————–+—————-+—————-+———————+——+———-+ 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 07월 14일
[Linux] Out Of Memory 발생 시 메모리 확인 방법 TECH by Sangmi Park 2023년 06월 30일 리눅스 서버를 운영하면서 일반적으로 CPU / MEM / DISK 등의 상태에 대해 모니터링을 하게 됩니다.모니터링을 하는 방법이야 유료/무료 툴을 사용하든 직접 명령어로 확인하든 다양한 방법이 있을 것이고, 본문에서는 다루지 않을 생각입니다.서버를 모니터링할 때 가장 무서운 장애는 OOM(Out Of Memory)입니다.특정 프로세스에서 메모리를 많이 사용하게 되어 OOM 이 발생하게 되면 해당 프로세스(App 등)가 멈출 뿐 아니라 서버의 메모리 자원이 부족하여 아예 동작을 하지 못하는 상황이 발생하게 됩니다.따라서 OOM 상황을 방지하고자 프로세스들을 확인하고 메모리를 확보하는 작업을 하게 됩니다. 1. 메모리 확인 $ free -h위 명령으로 전체 메모리 / 사용 메모리 / 캐시 메모리 / 스왑 메모리 등을 확인할 수 있습니다. $ top이 명령으로 CPU / MEM 를 동시에 확인할 수 있으며, 어떤 프로세스의 사용률이 높은지 확인할 수 있습니다. 일반적으로 top 명령으로 위처럼 확인할 수 있고, 만약 특정 앱의 프로세스가 메모리 사용률이 높다면, 그 앱을 사용하는 담당자에게 문의해 죽일 수 있습니다. 2. 캐시 메모리의 사용비율이 높은 상황 `$ free -h` 명령으로 확인했을 때 메모리 사용률은 낮은데 이상하게 캐시 메모리의 사용이 높은 경우가 있습니다.이 경우에는 캐시 메모리를 비워주어 해결할 수 있습니다.캐시 메모리를 사용한다면 자주 사용되고 있는 프로그램들의 값들을 캐시에 저장하여 사용하기에 메모리 접근 속도를 높일 수 있지만, 다른 프로그램에서 메모리 사용률을 확보하지 못하는 문제가 발생할 수 있습니다.따라서 주기적으로 캐시 메모리를 비워 메모리를 확보해 주는 것이 좋을 것 같습니다.$ sync && echo 3 > /proc/sys/vm/drop_caches이 명령어를 사용하면 캐시 메모리를 비울 수 있고, 메모리 여유 공간을 확보할 수 있습니다. 위 명령에 대해 좀 더 자세히 확인해보자면, 아래와 같습니다.pagecache 해제$ echo 1 > /proc/sys/vm/drop_caches dentries, inodes 해제$ echo 2 > /proc/sys/vm/drop_caches pagecache, dentries, inodes 모두 해제$ echo 3 > /proc/sys/vm/drop_caches 플러싱하기$ sync 3. 정리 메모리가 부족한 상황은 일반적으로 특정 프로세스에서 과도하게 사용하거나 캐시 메모리에서 많이 사용하고 있는 경우입니다.이 외의 경우는 아직 경험해 보지 못하였으나, 시스템 로그 / 메모리 확인 / 앱의 상태 확인 등의 방법을 통해 차근차근 접근한다면 충분히 해결할 수 있을 것입니다. 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 06월 30일
[My SQL] DB / Table 용량확인(data, index) TECH by Sangmi Park 2023년 06월 07일 아래의 쿼리를 참고하여 원하는 형태로 쿼리를 수정하여 사용량을 확인 할 수 있다. 1. 특정 DB 테이블별 용량을 확인할 때 SELECT table_schema AS ‘DatabaseName’, TABLE_NAME, ROUND(SUM(data_length + index_length)/ 1024 / 1024 , 2) AS ‘total_Size(MB)’, ROUND(SUM(data_length)/ 1024 / 1024, 2) AS ‘data_Size(MB)’, ROUND(SUM(index_length)/ 1024 / 1024, 2) AS ‘index_Size(MB)’FROM information_schema.tablesWHERE table_schema = {DB명}GROUP BY table_schema, TABLE_NAME;용량이 커서 GB 기준으로 보고 싶다면 아래 같이 쿼리를 변경하면 된다.ROUND(SUM(data_length + index_length)/ 1024 / 1024 , 2) AS ‘total_Size(MB)’,=> ROUND(SUM(data_length + index_length)/ 1024 / 1024 /1024 , 2) AS ‘total_Size(GB)’, 2. 특정 DB 전체 용량을 확인할 때 SELECT table_schema AS ‘DatabaseName’, TABLE_NAME, ROUND(SUM(data_length + index_length)/ 1024 / 1024 , 2) AS ‘total_Size(MB)’, ROUND(SUM(data_length)/ 1024 / 1024, 2) AS ‘data_Size(MB)’, ROUND(SUM(index_length)/ 1024 / 1024, 2) AS ‘index_Size(MB)’FROM information_schema.tablesWHERE table_schema = {DB명}GROUP BY table_schema; 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 06월 07일
AWS VPC S3 endpoint gateway vs interface 차이 TECH by Sangmi Park 2022년 06월 28일 1. AWS VPC endpoint 란? VPC 엔드포인트를 통해 인터넷 게이트웨이, NAT 디바이스, VPN 연결 또는 AWS Direct Connect 연결이 필요 없이 Virtual Private Cloud(VPC)와 지원 서비스 간에 연결을 설정할 수 있습니다. 따라서 VPC에서 연결할 수 있는 특정 API 엔드포인트, 사이트 및 서비스를 제어합니다. 2. S3 에서 지원 가능한 VPC endpoint 유형 Gateway endpoint 와 Interface endpoint 라는 두 가지 유형의 VPC 엔드포인트를 사용하여 Amazon S3에 접근할 수 있습니다. Gateway endpoint 는 AWS 네트워크를 통해 VPC에서 Amazon S3에 접근하기 위해 route table 에 지정하는 Gateway 입니다. Interface endpoint 는 Private IP 주소를 사용하여 VPC 피어링 또는 AWS Transit Gateway를 사용하여 VPC 내, 온프레미스 또는 다른 AWS 리전의 VPC에서 Amazon S3로 요청을 라우팅함으로써 게이트웨이 엔드포인트의 기능 확장할 수 있습니다. 2.1 interface vs gateway 차이 ※ Interface Endpoint 사용 시 PirvateLink 에 대한 요금이 발생합니다. https://aws.amazon.com/ko/privatelink/pricing/#Interface_Endpoint_pricing 2.2 Gateway Endpoint Gateway Endpoint 는 S3 리전별로 지정된 IP 접두사 목록을 기반으로 라우팅 테이블의 경로 대상에 적용하여 사용합니다. Gateway Endpoint 속성 및 제한엔드포인트에는 Amazon S3 리소스에 액세스하기 위한 엔드포인트 사용을 제어하는 정책이 있습니다. 기본 정책은 VPC 내의 모든 사용자 또는 서비스가 자격 증명을 사용하여 아무 AWS 계정에서 아무 Amazon S3 리소스에 액세스할 수 있도록 허용합니다. VPC가 연결된 계정이 아닌 다른 AWS 계정에 대한 Amazon S3 리소스도 마찬가지입니다.Amazon S3가 수신한 해당 서브넷에 있는 인스턴스의 원본 IPv4 주소는 VPC의 퍼블릭 IPv4 주소에서 프라이빗 IPv4 주소로 변경됩니다. 엔드포인트는 네트워크 라우팅을 스위칭하고 열린 TCP 연결을 끊습니다. 퍼블릭 IPv4 주소를 사용한 이전 연결이 다시 시작되지 않습니다. 따라서 엔드포인트를 만들거나 수정할 때는 중요한 작업을 실행하지 않는 것이 좋으며 연결이 끊어진 후에는 소프트웨어가 자동으로 Amazon S3에 다시 연결할 수 있는지 테스트해야 합니다.IAM 정책 또는 버킷 정책을 사용하여 VPC IPv4 CIDR 범위(프라이빗 IPv4 주소 범위)로부터의 액세스를 허용할 수 없습니다. VPC CIDR 블록이 중첩되거나 동일할 수 있고 이로 인해 예기치 않은 결과가 발생할 수 있습니다. 따라서 VPC 엔드포인트를 통해 Amazon S3에 요청할 때는 IAM 정책에 aws:SourceIp 조건을 사용할 수 없습니다. 사용자 및 역할의 IAM 정책과 모든 버킷 정책에도 같은 사항이 적용됩니다. 문에 aws:SourceIp 조건이 포함되어 있는 경우, 값이 제공된 IP 주소 또는 범위와 일치하지 않습니다. 대신에 다음 작업을 할 수 있습니다.라우팅 테이블을 사용하여 엔드포인트를 통해 Amazon S3의 리소스에 액세스할 수 있는 인스턴스를 제어할 수 있습니다.버킷 정책의 경우 특정 엔드포인트 또는 특정 VPC에 대한 액세스를 제한할 수 있습니다.엔드포인트는 교차 리전 요청을 지원하지 않습니다. 엔드포인트는 현재 IPv4 트래픽에 대해서만 지원됩니다. 2.3 Interface Endpoint Interface Endpoint 는 서브넷의 IP 주소 범위에서 프라이빗 IP 주소를 사용하는 탄력적 네트워크 인터페이스이며, AWS가 소유하거나 AWS 고객 또는 파트너가 소유한 서비스로 전달되는 트래픽에 대한 진입점 역할을 합니다.Interface Endpoint 속성 및 제한각 인터페이스 엔드포인트에서 가용 영역당 1개의 서브넷만 선택할 수 있습니다.인터페이스 엔드포인트를 생성할 때 계정에 매핑된 가용 영역에 엔드포인트가 생성됩니다. 이 가용 영역은 다른 계정과는 별도입니다.서비스 공급자와 소비자의 계정이 서로 다르며 여러 가용 영역을 사용하고 소비자가 VPC 엔드포인트 서비스 정보를 보는 경우 응답에는 공통 가용 영역만 포함됩니다. 예를 들어 서비스 공급자 계정에서 us-east-1a 및 us-east-1c를 사용하고 소비자가 us-east-1a 및 us-east-1b를 사용하는 경우 응답에는 공통 가용 영역 us-east-1a의 VPC 엔드포인트 서비스가 포함됩니다.기본적으로 각 인터페이스 엔드포인트는 가용 영역당 최대 10Gbps의 대역폭을 지원하고 최대 40Gbps까지 자동으로 조정되며, 변경을 위해 AWS Support 를 서브넷에 대한 네트워크 ACL이 트래픽을 제한하는 경우 엔드포인트 네트워크 인터페이스를 통해 트래픽을 보내지 못할 수 있습니다. 서브넷의 CIDR 블록에서 주고 받는 트래픽을 허용하는 적절한 규칙을 추가해야 합니다.엔드포인트 네트워크 인터페이스와 연결된 보안 그룹이 서비스와 통신하는 VPC의 리소스와 엔드포인트 네트워크 인터페이스 간의 통신을 허용하는지 확인합니다. AWS CLI 같은 명령줄 도구가 HTTPS를 통해 VPC의 리소스에서 AWS 서비스로 요청하려면 보안 그룹에서 인바운드 HTTPS(포트 443) 트래픽을 허용해야 합니다.인터페이스 엔드포인트는 TCP 트래픽만을 지원합니다.엔드포인트를 만들 경우, 연결하려는 서비스에 대한 액세스를 제어하는 엔드포인트에 엔드포인트 정책을 연결할 수 있습니다.참가자는 자신이 소유하지 않은 VPC에서 Amazon Route53 Resolver 엔드포인트를 생성할 수 없습니다. VPC 소유자만 인바운드 엔드포인트와 같은 VPC 수준 리소스를 생성할 수 있습니다.엔드포인트는 동일한 리전에서만 지원됩니다. VPC와 다른 리전의 서비스 간에 엔드포인트를 생성할 수 없습니다.엔드포인트는 IPv4 트래픽만 지원합니다.VPC 간에 또는 서비스 간에 엔드포인트를 전송할 수 없습니다.VPC당 생성할 수 있는 엔드포인트에 대한 할당량이 존재합니다. 3. VPC Peering 구성을 통한 내부 통신 Gateway Endpoint 는 Route table 끝점에 지역별 S3 Prefix List 를 지정하여 통신하는 반면에Interface Endpoint 로 구성하면 Region 또는 VPC Peering 구성을 통해 내부 통신으로 타 VPC (리전) S3 에 접근할 수 있습니다.[ A(Seoul) Region 의 Route table ] NAT / IGW 를 사용하지 않고 VPC Peering CIDR 대역만 허용합니다. [ B (Virginia) Region 의 Route table ]Endpoint 를 허용하는 B Region 도 NAT / IGW 를 사용하지 않고 VPC Peering CIDR 만 허합니다. [ B (Virginia Region) 의 S3 Endpoint ] [ Virginia Region 의 S3 ] [ 외부 통신 없이 s3 를 통해 Seoul region 에서 upload ] AWS CLI TEST 4. 결론 두 가지 S3 VPC Endpoint 연결 방식에 대해 알아보았습니다.단일 VPC 환경의 경우 AWS S3 Gateway endpoint 방식의 구성이 적합하며, 다중 VPC 환경/계정/리전의 경우 접근 용도에 따라 Interface endpoint 구성이 적합합니다. 고객의 아키텍처 및 요구 사항에 따라 특성을 확인 하시어, 구성을 하시길 바랍니다. 참고 자료https://docs.aws.amazon.com/ko_kr/vpc/latest/privatelink/vpc-endpoints.html 가상 환경을 종료 할때는 exit 명령을 수행 하여 빠져 나갈 수 있으며, 다시 다른 가상 환경을 사용하기 위해 접속해도 문제가 없이 실행 됩니다. 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2022년 06월 28일
K8S 개념 및 Cluster 구축 실습 TECH by Sangmi Park 2022년 06월 27일 쿠버네티스(kubernetes)란 마이크로 서비스 아키텍처(MSA)가 발전하고, 데브옵스(DevOps)에 대한 개념이 명확해지면서 컨테이너 기반의 환경이 주목받기 시작했다.대규모의 서비스에서 하드웨어와 VM 의 수가 많아지고 컨테이너의 수가 많아지면 이 컨테이너를 어디에 배포해야 하는지 결정해야 한다. 주어진 자원을 최적으로 사용하기 위해 적절한 위치에 배포해야 한다. 특성에 따라 물리서버에 배포하거나, 가용성을 위해 다른 서버에 배포하기도 한다. 이러한 개념을 스케줄링이라고 한다. 스케줄링을 포함하여 재기동, 모니터링, 삭제 관리 등 종합적으로 관리해주는 환경을 컨테이너 운영환경이라고 한다.현재 컨테이너 운영환경 중 가장 널리 사용하는 솔루션이 쿠버네티스(kubernetes, K8S)이다. 컨테이너화된 워크로드와 서비스를 관리하기 위한 이식성이 있고, 확장 가능한 오픈소스 플랫폼이다.개념 이해를 위해 쿠버네티스의 구성요소(Componenet) 및 기본 구성단위인 오브젝트(Object)에 대해 살펴보자. 그리고 쿠버네티스 클러스터를 실제 구축하며 실습을 통해 익혀보자. kubernetes Component (1) 1. Master Node 주요 컨트롤 유닛으로서 Worker Nodes를 관리하는 주체클러스터에 관한 전반적인 결정 및 이벤트를 감지, 반응하는 역할 a. ETCD : 설정관리, 서비스 디스커버리, 스케줄링 등을 위한 데이터를 저장하는 저장소 모든 상태와 데이터를 저장분산 시스템으로 구성하여 안정성 높임 (고가용성)가볍고 빠르면서 정확하게 설계 (일관성)Key-Value 형태로 데이터 저장TTL, watch 같은 부가 기능 제공클러스터의 모든 정보가 etcd에 저장이 되므로 항상 백업etcd 스냅샷을 S3 로 저장 가능 b. kubectl관리자가 쿠버네티스에 명령 및 관리하기 위해 사용하는 CLI 명령줄 도구API Server 로 요청c. API Server모든 조회나 요청을 담당REST API를 통해 etcd 정보 조회 및 업데이트하고 명령을 실행권한을 체크하여 적절한 권한 없을 경우 차단관리자 요청 뿐 아니라 다양한 내부 모듈과 통신 d. Controllers논리적으로 다양한 컨트롤러가 존재(복제, 노드, 엔드포인트…)지속적으로 상태를 체크하고 원하는 상태를 유지 (Desired State)논리적으로 다양하게 쪼개져 있지만, 실제로는 복잡성을 낮추기 위해 하나의 프로세스로 진행e. Scheduler새로 생성된 Pod 를 감지하고 실행할 노드를 선택Pod 생성을 위해 요청한 리소스, 우선순위 및 기타 제약조건에 따라서 노드에 바인드 역할ex) 특정 라벨의 노드에 부여 kubernetes Component (2) 2. Worker Node 할당된 task를 요청대로 수행하는 시스템컨테이너들 간의 네트워크 등 서비스에 필요한 전반적인 일들을 마스터 노드와 통신하며 수행 a. kubelet각 노드에서 실행되는 일종의 에이전트Pod 를 실행/중지하고 상태를 체크 후에 API Server 에 보고도커 API 를 이용하여 도커 데몬과 통신을 통해 컨테이너 실행CRI (Container Runtime) – Docker, Containerd, CRI-O, …… b. kube-proxy각 노드에서 실행되는 네트워크 프록시로 내/외부 통신 설정지속적으로 서비스와 Pod, iptables 의 변경 사항 확인(상태 체크) Pod간 통신(overlay network), 노드간의 통신 가능(Service)성능상의 이유로 별도의 프록시 프로그램 대신 iptables 또는 IPVS 를 사용 (설정만 관리)로드밸런싱 기능 제공 c. pod가장 작은 배포 단위단일 노드에 배포된 하나 이상의 컨테이너 그룹전체 클러스터에서 고유한 IP 할당포드에 있는 모든 컨테이너는 IP 주소, IPC, 호스트 이름, 기타 리소스를 공유네트워크와 스토리지를 추상화 kubernetes Object 1. Volume DB와 같이 영구적으로 파일을 저장해야 하는 경우, 컨테이너 restart와 관련없이 파일을 영구적으로 저장해야 하는데, 이러한 Storage 형태를 뜻함Pod를 가동할 때 디폴트로, 컨테이너마다 로컬 디스크를 생성하여 가동되는데, 이 로컬 디스크는 영구적이지 않기 때문. 즉, 컨테이너가 restart 되거나 새로 deploy 될 때마다 로컬 디스크는 Pod의 설정에 따라 새롭게 정의되어 배포되기 때문Volume은 Pod 내의 컨테이너 간의 공유 가능 2. Service Pod를 Service로 제공할 때, 일반적으로 하나의 Pod로 Service 하는 경우는 드물고, 여러 개의 Pod로 Service하면서 이를 LB를 이용해서 하나의 IP와 Port로 묶어서 Service 제공Pod는 동적으로 생성되고, 장애가 생기면 자동으로 restart되면서 IP가 바뀌기 때문에, LB에서 Pod의 목록을 지정할 때 IP주소를 이용하는 것은 어렵다. 또한 Auto Scaling으로 인하여 Pod가 동적으로 추가 또는 삭제되기 때문에, 이렇게 추가/삭제된 Pod 목록을 LB가 유연하게 선택해주어야 한다. 이 때 사용하는 것이 라벨(label)과 라벨 셀렉터(label selector)라는 개념이다. Service를 정의할 때, 어떤 Pod를 서비스로 묶을 것인지 정의하는데, 이를 label selector라고 한다. 각 Pod를 생성할 때, metadata 정보 부분에 label을 정의Service는 특정 label을 가지고 있는 Pod간에만 Load Balancing을 통하여 외부로 서비스 제공한다. 3. Namespace Namespace는 쿠버네티스 클러스터 내의 논리적인 분리 단위즉, 하나의 클러스터 내에 개발/운영/테스트 환경이 있을 때, 클러스터를 개발/운영/테스트 3개의 Namespace로 나눠서 운영사용자별로 각 Namespace 의 접근 권한을 다르게 운영 가능Namespace 별로 Pod, Service 등을 나눠 관리 가능Namespace 별로 리소스의 할당량을 지정할 수 있다. 개발계의 CPU 100개, 운영계의 CPU 400개과 GPU 100개, 이런 식으로 사용 가능한 리소스의 수를 지정 가능주의할 점은 Namespace는 논리적인 분리 단위이고, 물리적으로 환경을 분리(isolation)한 것은 아니다. 다른 Namespace간의 Pod라도 통신은 가능 K8S Cluster 구축 Manual 1. 기본 설치 (Mater&Worker 공통) 1. sudo su (관리자 권한)2. 도커 설치$ apt update $ apt install -y docker.io3. Installing kubeadm, kubelet and kubectlhttps://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/$sudo apt-get update $sudo apt-get install -y apt-transport-https ca-certificates curl $sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg <https://packages.cloud.google.com/apt/doc/apt-key.gpg> $echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] <https://apt.kubernetes.io/> kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list $sudo apt-get update $sudo apt-get install -y kubelet kubeadm kubectl $sudo apt-mark hold kubelet kubeadm kubectl4. 자동실행 설정 – 시스템 재부팅 시 자동실행되도록 설정$ systemctl enable docker kubelet 2. Mater 설정 1. 클러스터 생성https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/$ kubeadm init --pod-network-cidr=192.168.0.0/16 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config kubeadm join 192.168.104.189:6443 --token duixm1.q32ni39stuifik95 \ --discovery-token-ca-cert-hash sha256:052dcc589796d5737cb66c215ced1c3fa997f3cb7b384fe6c16ed4b0f405a14a 2. kubectl (권한) 설정 – 루트가 아닌 사용자를 위해 kubctl이 작동하도록 하려면 kubeadm init 출력의 일부이기도 한 다음 명령을 실행하시오.$mkdir -p $HOME/.kube $sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $sudo chown $(id -u):$(id -g) $HOME/.kube/config(kubectl get all —all-namespaces 한 번 쳐보기) kubectl get nodes (아직 NotReady) 3. cluster에 network 배포 (Calico Pod Network)#calico 설치 $ kubectl apply -f https:*//docs.projectcalico.org/v3.11/manifests/calico.yaml*#설치 확인 $ kubectl get pods -n kube-system4. taint 설정 제거 (taint 설정이 된 경우 pod의 스케줄링이 일어나지 않음)마스터 노드에도 pod를 배포하려면 다음과 같이 실행$ kubectl taint nodes --all node-role.kubernetes.io/master- node/ip-192-168-104-189 untainted node/<your-hostname> untainted5. 클러스터 노드 확인 (마스터 노드 동작 확인) > STATUS=Ready인지 확인$ kubectl get nodes -o wide 3. Worker 설정 1. 공통 (도커 및 쿠버네티스) 설치 후6443 port 열어주기 (마스터, 워커 노드 인스턴스 각각에서. 일단 같은 securitygroup 쓰기 때문에 그 인스턴스에서 port 열어줌. 다른걸 쓴다면 서로의 ip로 6443 포트 열어주면 됨)kubectl get pod -n kube-systemkubectl ~~ 명령어 입력하면The connection to ther server localhost:8080 was refused 발생Master Node에서는 kubectl 권한 설정 해주면 됨.Worker Node에서는 (Master에서)kubeadm init 했을 때 나왔던, join 해주면 됨2. Join : Worker Node 추가 (Master에서 kubeadm init 했을 때 나온 token을 join)일반적으로 토큰은 24시간 유효$ kubeadm join 192.168.104.189:6443 --token duixm1.q32ni39stuifik95 \\ --discovery-token-ca-cert-hash sha256:052dcc589796d5737cb66c215ced1c3fa997f3cb7b384fe6c16ed4b0f405a14a [preflight] Running pre-flight checks [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at <https://kubernetes.io/docs/setup/cri/> [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.마스터노드에서 kubectl get nodes 하면 워커노드 조인되고, STATUS: ready인 것 확인 가능.일반적으로 여기까지하면 cluster 구축 완료.+) 1번의 token을 잃어버린 경우 재확인$ kubeadm token list+) token이 만료된 경우 재생성해 사용 (기본 24시간 후 삭제)$ kubeadm token create 마치며 이 글을 통해 쿠버네티스에 대한 개념적인 이해와 실전에서 활용할 수 있는 클러스터 구축에 대한 팁까지 얻을 수 있었기를 기대한다. 쿠버네티스의 컨테이너 환경은 퍼블릭/프라이빗 클라우드 혼용 환경 및 온프레미스 환경에서도 동일하게 적용 가능하기 때문에 하이브리드 클라우드 솔루션으로 각광받고 있다. 다양한 환경에서 활용이 용이한 쿠버네티스에 대한 이해의 시작점을 이 글로 삼아 다양한 서비스에 적용해도록 하자. 참조https://heekim0719.tistory.com/414?category=817909https://bcho.tistory.com/1256?category=731548 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2022년 06월 27일
[python] 패키지 관리를 위한 poetry(가상환경까지) TECH by Sangmi Park 2022년 06월 17일 poetry소개 poetry는 python 개발시 패키지의 의존성을 관리하는 라이브러리 이며, 자바의 maven이나 gradle 비슷한 툴이라고 볼 수 있씁니다. 또한 virtualenv와 같이 가상환경 설정을 지원하여, 보다 포괄적인 의미의 기능도 있으며, build/publish 같은 배포까지도 가능한 범용적인 tool로도 사용할 수 있습니다.(본 문서는 poetry를 이용한 기본 설치 및 사용법과 실제 chatops를 개발 하기 위해 적용한 사례의 예시 기반으로 작성 되었습니다.) 설치 Linux 에서 설치(ubuntu 20.04)curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 설치 후 poetry 명령어를 수행하면 “command not found” 에러가 발생하는데, 설치 시 출력되는 설명처럼 $PATH에 $HOME/.protry/bin을 추가하거나 `source $HOME/.poetry/env`를 직접 입력하면 poetry 명령어를 수행 할 수 있습니다. 프로젝트 생성 첫번째, chatops의 server 프로젝트를 생성poetry new chatops-server --src두번째, chatops의 agent 프로젝트를 생성poetry new chatops-agent --src`–src` 옵션을 주면 생성된 프로젝트명 하위의 `src` 디렉토리에 소스가 위치하게되며, 생략시 프로젝트 명 하위에 소스가 위치하게 된다. 위와 같이 명령어를 실행 했을 경우 아래와 같은 디렉토리 구조가 됩니다. 패키지 추가 이제 poetry를 사용하는 근본적 이유 이면서, 굉장히 막강한 기능인 패키지 추가 삭제를 해보겠습니다.아래의 명령으로 패키지를 추가할 수 있다. 실제 chatops에서 cache를 위해 사용될 ExpiringDict 모듈을 설치해 볼 것입니다. 해당 명령어는 pyproject.toml 이 존재하는 디렉토리에서 실행 해야 합니다.poetry add expiringdict 위의 패키지 추가 완료 화면에서 보이는 문구중에 “Writing Lock File” 이 바로 poetry.lock 파일에 쓰기를 한다는 내용이며, 이 poetry.lock 파일이 있으면 지금 현재 프로젝트의 의존성과 완전히 동일한 의존성을 가지도록 구성할 수 있어, 해당 파일이 개발 환경 가이드라인의 배포 시에 같이 배포 될 수 있도록 하는 부분이 필요합니다. 예를 들면, git에 poetry.lock파일을 업로드 하여 개발 팀원들이 공유 받아서 사용하도록 할 수 있습니다.또한 pyproject.toml의 내용을 보면 방금 설치한 ExpiringDict 패키지의 의존성이 추가되어 있음을 확인 할 수 있습니다. 위의 의존성 추가 부분에서 “^” 이런 마크의 정확한 내용은 아래의 링크에서 확인 할 수 있는데, 위의 expiringdict를 예로 설명 들면 “>=1.2.1<2.0.0”을 의미합니다. 아래 링크를 참조 바랍니다.https://python-poetry.org/docs/dependency-specification/ 프로젝트 빌드 poetry는 build를 지원하여 배포가 가능한 파일도 생성 할 수 있습니다.poetry build 위 그림 처럼 build를 수행 하면, dist 디렉토리 하위에 배포가 가능한 파일들이 생성 되며, 이를 이용해 운영환경에 배포할 수 있습니다. 물론 setup.py를 이용하여 잘 정리된 build 파일로 만들어 질 수 있습니다. Virtual Environments poetry는 virtuanlenv와 동일한 가상환경(virtualenv)를 자체적으로 관리 할 수 있습니다. 가상환경 생성 그러면 가상환경을 실행하기 위해 아래의 명령어를 수행해 보도록 하겠습니다. poetry env use $PYTHON_HOME/bin/python3 가상환경 접속 생성한 가상환경을 사용하기 위해서는 다음의 shell 옵션을 추가해서 실행하면 됩니다. poetry shell shell 접속을 하면 프롬프트에 접두어(위의 경우 `chatops-server-vywmTEbm-py3.8`)가 붙게 되며 해당 값은 아래의 명령어로 확인 할 수 있습니다. poetry env info 위의 그림에서 보듯이 `poetry env use` 명령으로 생성된 python은 $HOME/.cache/pypoetry/viertualenvs/ 하위 디렉토리에 위치하게 되며 가상환경의 shell로 접속하여 수행되는 poetry add 패키지는 해당 디렉토리에 설치가 됩니다. 가상환경 접속종료 가상 환경을 종료 할때는 exit 명령을 수행 하여 빠져 나갈 수 있으며, 다시 다른 가상 환경을 사용하기 위해 접속해도 문제가 없이 실행 됩니다. 가상환경 삭제하기 가상환경을 삭제하기 위해서는 다음 명령어를 수행해야 합니다. virtualenv처럼 디렉토리 자체를 삭제하면 문제가 발생 할 수 있습니다. poetry env remove $PYTHON_HOME/bin/python3 requirements.txt 추출하기 poetry도 requirements.txt 파일을 추출 할 수 있으며, poetry export 명령어로 다음과 같이 수행하여 설치된 모듈만 배포할 수 있습니다. (pyproject.toml파일에 설치된 모듈의 목록이 잘 정리 되어 있어 poetry build를 이용하여 생성된 파일로 배포를 수행할 수도 있습니다.) poetry export -f requirements.txt > requirements.txt Conclusion 오랜기간 java개발 만을 해왔고 최근에서야 python 개발을 본격적으로 시작하게 되어 python의 일반적인 개발 환경 설정부분이 궁금하여 virtualenv, pyenv등의 python 환경 설정 관련 패키지들을 공부하다가 poetry를 알게 되면서, 이제 개발 환경 설정 관련 부분은 poetry만 있으면 충분히 개발 할 수 있을 거라고 생각하게 되어 위의 문서를 작성 하게 되었습니다. 현재 poetry를 이용한 chatops개발을 진행 할 예정이며 향후에 개발이 완료 되었을 때 다시 한번 poetry의 실제 적용사례 및 배포관련된 부분의 내용을 작성 하도록 하겠습니다. python 기반의 프로젝트를 처음 시작하는 분들께 도움이 되었으면 좋겠습니다. 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2022년 06월 17일