로컬 Docker에서 이미 업그레이드했으면 3-3 절차까지 생략

실행1 - MariaDB 생성(10.11.3 사용: https://hub.docker.com/_/mariadb)

cd ./AKS-migrate-v10113

 

docker pull mariadb:10.11.3 (현재 최신버전: 10.11.3)

 

실행2 - DB 스키마 호환성 체크

기존 DB volume: mysql 폴더를 mount 시켜 실행해 봄 - 성공 시 바로 사용하면 됨

 

실행3 - DB 스키마 호환성 체크 실패 시

새 DB volume: mysql 폴더 생성

 

3-1. mariadb:10.11.3 이미지를 그대로 컨테이너로 실행한 다음 원격 쉘에서 아래 명령으로 vim, spider 엔진 설치

mysql# apt-get update -yqq
mysql# apt install vim -yqq
mysql# apt install mariadb-plugin-spider -yqq
mysql# apt-get clean
mysql# rm -rf /var/lib/apt/lists/*

 

3-2. 임시 컨테이너 생성

docker pull hello-world

 

3-3. mariadb 컨테이너 종료/재시작한 다음 mysql 폴더 백업

10.4와 10.11은 스키마가 호환되지 않음
docker cp mariadb:/var/lib/mysql ./db/data_backup-v10113/

 

실행4 - MariaDB:10.11.3 spider 엔진 설치

docker build -t mariadb:spider-10.11.3 -f Dockerfile.mariadb_spider-v10113 .

또는 (Docker Hub에서 다운로드 - 사전 생성된 이미지 사용)

docker pull rodimreht/mariadb:spider-10.11.3
docker tag rodimreht/mariadb:spider-10.11.3 mariadb:spider-10.11.3
docker rmi rodimreht/mariadb:spider-10.11.3

 

실행5 - Kubernetes로 올리기

az acr login --name rodimreht
az acr show --name rodimreht
az acr list --resource-group rodimreht --query "[].{acrLoginServer:loginServer}" --output table
> rodimreht.azurecr.io

docker images
docker tag mariadb:spider-10.11.3 rodimreht.azurecr.io/mariadb:spider-10.11.3
docker push rodimreht.azurecr.io/mariadb:spider-10.11.3
az acr repository show-tags --name rodimreht --repository mariadb --output table

 

실행6 - DB 업데이트용 Pod 생성 [dummypod2.yml]

mariadb 저장소는 ReadWriteMany Volume은 사용 불가, ReadWriteOnce로만 사용 가능(설명은 맨 아래에)
kubectl apply -f dummypod2.yml
---
apiVersion: v1
kind: Pod
metadata:
  name: dummypod2
spec:
  containers:
  - image: mcr.microsoft.com/oss/nginx/nginx:1.15.5-alpine
    name: dummy2
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 250m
        memory: 256Mi
    volumeMounts:
      - name: webdata
        mountPath: /var/lib/mysql
        subPath: mariadb/mysql
      - name: webdata
        mountPath: /etc/mysql/conf.d
        subPath: mariadb/config
  volumes:
    - name: webdata
      persistentVolumeClaim:
        claimName: webshare-pvc

 

실행7 - MariaDB 초기 데이터 업로드

kubectl delete pod/dummypod2
kubectl apply -f dummypod2.yml
kubectl describe pod/dummypod2 -n default

 

7-1. Pod ls 명령 실행

kubectl exec pod/dummypod2 -- ls /mnt/mariadb

 

7-2. Pod rm 명령 실행

필요 시 삭제 전 기존 파일/폴더 별도 백업할 것
kubectl exec pod/dummypod2 -- rm -fr /mnt/mariadb/*

 

7-3. Pod로 DB 파일 복사

kubectl cp ./db/data_backup-v10113/mysql dummypod2:/mnt/mariadb/
kubectl cp ./db/config dummypod2:/mnt/mariadb/

 

실행8 - IP주소 기록 및 .\db\rdrt_spider_create_aks_db.sql 생성

kubectl get svc (mariadb CLUSTER-IP 확인: 10.0.xxx.xxx로 업데이트)

 

실행9 - MariaDB 백업, 중지

kubectl exec deploy/mariadb -- mysqldump --routines --triggers -uroot -p******** spider_db > .\db\spider_db.sql
kubectl exec deploy/mariadb -- mysqldump --routines --triggers -uroot -p******** backend_db1 > .\db\backend_db1.sql
kubectl exec deploy/mariadb -- mysqldump --routines --triggers -uroot -p******** backend_db2 > .\db\backend_db2.sql
kubectl delete deployment mariadb
kubectl delete deployment rdrt-web
kubectl delete deployment rdrt-mobile
kubectl delete deployment rdrt-admin
kubectl delete deployment rdrt-kiosk
kubectl delete deployment rdrt-scim
kubectl delete deployment rdrt-service
kubectl delete deployment rdrt-roomviewer

 

실행10 - 신규 DB 배포 생성

cd /d D:\Docker\update\AKS
kubectl delete pod/dummypod2
kubectl apply -f mariadb-spider-v10113-deployment.yaml
cd /d C:\Temp\AKS-migrate-v10113
kubectl exec -i deploy/mariadb -- mysql -uroot -p******** < .\db\rdrt_spider_create_aks_db.sql
kubectl exec -i deploy/mariadb -- mysql -uroot -p******** backend_db1 < .\db\backend_db1.sql
kubectl exec -i deploy/mariadb -- mysql -uroot -p******** backend_db2 < .\db\backend_db2.sql
kubectl exec -i deploy/mariadb -- mysql -uroot -p******** spider_db < .\db\spider_db.sql

 

실행11 - 관련 서비스 재시작

cd /d D:\Docker\update\AKS
kubectl apply -f rdrt-admin-deployment.yaml
kubectl apply -f rdrt-roomviewer-deployment.yaml
kubectl apply -f rdrt-service-deployment.yaml
kubectl apply -f rdrt-mobile-deployment.yaml
kubectl apply -f rdrt-scim-deployment.yaml
kubectl apply -f rdrt-kiosk-deployment.yaml
kubectl apply -f rdrt-web-deployment.yaml

 

추가. 마이그레이션 중 주의사항

1. MariaDB에는 ReadWriteMany Volume 사용 불가

MariaDB는 기동 시 /etc/mysql/conf.d/my.cnf 파일 및 /var/lib/mysql 하위 저장소 파일들을 읽는데,
해당 파일들이 mysql 계정 권한 소유로, 644(rw-r-r)로 설정된 경우에만 정상 로드되도록 되어 있다.
그런데, AKS 저장소를 ReadWriteMany로 마운트시키면 모든 폴더/파일 권한이 1000(공유계정) 권한으로 설정되어 바꿀 수 없기 때문에 MariaDB가 시작하다 실패하게 된다.
AKS 저장소를 ReadWriteOnce로 마운트시켜야 연결된 Pod OS의 권한을 상속받아 폴더/파일 소유권 및 권한을 바꿀 수 있다.
(이런 세부적인 내용은 인터넷에 나와있지 않아 사전에 미리 알기는 어려움. ㄷㄷ)

2. MariaDB 신규 설치 및 Bulk insert 작업 후 일정 시간 대기 필요

위 백업/복원 명령어를 통해 Bulk insert로 Database를 새로 구성한 경우, 테이블 및 인덱스 구성이 완료되기까지 시간이 좀 더 걸릴 수 있다.
(경험적으로 약 1~2시간 이상이 지나야 안정적으로 동작하는 듯 하다.)
그 전에는 빠르던 쿼리가 엄청 느린 등등의 이상한(?) 경험을 할 수 있으니 주의해야 한다.
좀 이상하다고 테이블/인덱스를 새로 생성한다거나 할 필요 없다... 일단 좀 기다려 보는 것이 좋다.

3. Spider DB 한정: 다중 Public Key가 있는 테이블 각 필드 Index 확인/추가

MariaDB 10.11 버전에서는 Spider 엔진을 사용 중인 데이터베이스에서는 다중 Public Key가 있는 테이블의 PK 필드 각각 Index 생성이 필요하다(Spider, InnoDB 모두).
그렇지 않은 경우 PK임에도 불구하고 index를 타지 못해서 엄청나게 느리거나 이해할 수 없는 이상한 오류가 나는 경험을 하게 된다(버그로 추정).

예를 들어 COM_ID, USER_ID가 다중 PK로 잡혀있고 DISPLAY_YN 필드는 index 걸려 있는 경우,

SELECT * FROM tb_user WHERE `USER_ID` = 'PNP.E01234' AND DISPLAY_YN <> 'N';

이 명령은 잘 실행되는데

SELECT COUNT(*) FROM tb_user WHERE `USER_ID` = 'PNP.E01234' AND DISPLAY_YN <> 'N';

이 명령을 실행하면 DISPLAY_YN이 order by 절에 없다는(?!) 희한한 오류가 발생하고 실행이 되지 않는다.
해결 방법은 의외로 PK 필드인 COM_ID, USER_ID 각각에 대해 index를 생성해주는 것이다! ㄷㄷ

ALTER TABLE `tb_user`
    ADD INDEX `ix_user_COM_ID` (`COM_ID`),
    ADD INDEX `ix_user_USER_ID` (`USER_ID`);

 

4. Sub Query의 WHERE절에 IS NULL이 있는지 확인하고 수정 필요

MariaDB 10.11 버전에서는 Sub Query에 IS NULL 조건이 있으면 index를 타지 않는다(버그로 추정).
필드 IS NULL 쿼리를 ISNULL(필드, '') = '' 쿼리로 바꾸면 정상 동작한다.

예를 들어

SELECT COUNT(*) FROM tb_room_reservation
WHERE (APPROVAL_STATE IS NULL OR APPROVAL_STATE <> '30303')
    AND CANCEL_DT IS NULL AND USER_ID = 'PNP.E01234';

이런 멀쩡하고 빠르게 실행 잘 되는 쿼리가 다음과 같이 Sub Query로 들어가 있으면

SELECT
    tb_room.*,
    (
        SELECT COUNT(*) FROM tb_room_reservation
        WHERE (APPROVAL_STATE IS NULL OR APPROVAL_STATE <> '30303')
            AND ROOM_ID = tb_room.ROOM_ID
            AND CANCEL_DT IS NULL AND USER_ID = 'PNP.E01234'
    ) AS R_COUNT
FROM tb_room
    INNER JOIN tb_area ON tb_area.AREA_ID = tb_room.AREA_ID
    INNER JOIN tb_floor ON tb_floor.FLOOR_ID = tb_area.FLOOR_ID
    INNER JOIN tb_building ON tb_building.BLDG_ID = tb_floor.BLDG_ID
WHERE tb_room.RESV_YN='Y'
    AND tb_room.USE_YN='Y'
    AND tb_floor.USE_YN='Y'
    AND tb_building.ROOM_RESV_YN='Y'
    AND tb_floor.BLDG_ID=150000000000
    AND ROOM_TYPE='30101'
    AND fn_is_accessible_area(tb_room.AREA_ID, 'PNP.E01234') = TRUE;

매우 오랜 시간이 걸려서 겨우 결과가 리턴된다. IS NULL 때문이다!
이 쿼리를 아래와 같이 바꾸면 다시 정상 동작한다.

SELECT
    tb_room.*,
    (
        SELECT COUNT(*) FROM tb_room_reservation
        WHERE (IFNULL(APPROVAL_STATE, '') = '' OR APPROVAL_STATE <> '30303')
            AND ROOM_ID = tb_room.ROOM_ID
            AND IFNULL(CANCEL_DT, '') = '' AND USER_ID = 'PNP.E01234'
    ) AS R_COUNT
FROM tb_room
    INNER JOIN tb_area ON tb_area.AREA_ID = tb_room.AREA_ID
    INNER JOIN tb_floor ON tb_floor.FLOOR_ID = tb_area.FLOOR_ID
    INNER JOIN tb_building ON tb_building.BLDG_ID = tb_floor.BLDG_ID
WHERE tb_room.RESV_YN='Y'
    AND tb_room.USE_YN='Y'
    AND tb_floor.USE_YN='Y'
    AND tb_building.ROOM_RESV_YN='Y'
    AND tb_floor.BLDG_ID=150000000000
    AND ROOM_TYPE='30101'
    AND fn_is_accessible_area(tb_room.AREA_ID, 'PNP.E01234') = TRUE;

이런 말도 안되는 버그를 만들어 내다니... MariaDB 최신 안정화 버전이라고 너무 믿으면 안되겠다.
상황에 따라 IFNULL 문으로도 안되는 경우가 있는데, 그럴 때는 아예 IF ...IS NULL THEN ... ELSE 문으로 쿼리를 나눠야 하는 경우도 있으니 참고.

5. Database/Procedure Collation(문자열 정렬) 확인/수정

늘 그렇듯, Bulk insert로 DB/테이블/프로시저 등을 생성하면 쿼리 또는 프로시저 실행 시 아래와 같은 오류를 만나게 되는 경우가 많다.

  Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '='

상세한 설명은 복잡하니 됐고, 간단히 다음의 3단계로 처리하면 된다(C# ASP.NET Core 기준).

  1. 접속하는 데이터베이스는 utf8mb4_general_ci로 맞춘다(Spider 엔진 사용 시 백엔드 DB는 utf8mb4_unicode_ci로 설정).
    ALTER DATABASE spider_db DEFAULT CHARACTER SET utf8mb4 COLLATE = utf8mb4_general_ci;
    ALTER DATABASE backend_db1 DEFAULT CHARACTER SET utf8mb4 COLLATE = utf8mb4_unicode_ci;
    ALTER DATABASE backend_db2 DEFAULT CHARACTER SET utf8mb4 COLLATE = utf8mb4_unicode_ci;
  2. 각 테이블 기본 정렬 및 각 문자열 필드의 정렬도 모두 utf8mb4_general_ci로 맞춘다.
    ALTER TABLE `ex_user`
     COLLATE='utf8mb4_general_ci',
     CHANGE COLUMN `USER_ID` `USER_ID` VARCHAR(40) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci' FIRST,
     CHANGE COLUMN `PASSWORD` `PASSWORD` VARCHAR(40) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci' AFTER `USER_ID`,
     CHANGE COLUMN `IP_ADDRESS` `IP_ADDRESS` VARCHAR(30) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci' AFTER `PASSWORD`;
  3. 오류가 발생하는 프로시저는 삭제 후 재생성한다.
    DROP PROCEDURE IF EXISTS `up_select_stats`;
    DELIMITER //
    CREATE PROCEDURE `up_select_stats`(
     IN `V_COM_ID` VARCHAR(40),
     IN `V_USER_ID` VARCHAR(50)
    )
    BEGIN
     ...
    END//
    DELIMITER ;

이렇게 하면 깔끔하게 잘 실행된다.

추가로, MariaDB 업그레이드에 따른 영향을 고려하여, 지속적으로 쿼리/프로시저 실행 성능을 측정하고 튜닝한다.




- End Of Document -



Posted by 떼르미
,


자바스크립트를 허용해주세요!
Please Enable JavaScript![ Enable JavaScript ]