EKS + Fluent bit + OpenSearch 구성을 통한 로그 수집 TECH by Sangmi Park 2024년 02월 08일 1-a. EFK (ElasticSearch + Fluented + Kibana)란? EFK란 ElasitcSearch + Fluentd bit + Kibana의 조합을 일컬음보통 지속적으로 유입되는 로그 데이터를 수신하고 이 데이터를 차트와 그래프로 시각화 하거나 분석할때 사용하는 솔루션2021년 9월, Elastic의 라이선스 변경으로 인해 AWS에서는 ElasticSearch에 대한 업데이트 제공을 중단함. 기존 ElasticSearch를 포크(Fork)하여 OpenSearch라는 오픈 소스 서비스를 개시하고,Elastic에서 함께 지원하던 시각화 도구인 Kibana는 OpenSearch Dashboard 라는 서비스로 지원 1-b. OpenSearch + Fluent bit + OpenSearch Dashboard Fluent bit : 데이터(로그)를 수집해서 Opensearch로 전달OpenSearch : Fluentd로부터 받은 데이터를 검색 및 집계하여 필요한 정보 획득OpenSearch Dashboard: Opensearch의 빠른 검색능력을 통해 데이터 시각화 및 모니터링 1-c. Fluentd / Fluent bit / LogStash 장단점 장점단점Fluentd– 다양한 데이터 소스에서 로그를 수집하고 대용량 데이터 처리를 지원하는 포괄적인 로그 수집기– 풍부한 플러그인과 커뮤니티 지원이 제공됨– 일부 환경에서 성능이 떨어질 수 있으며, 메모리 사용량이 크고 설정이 상대적으로 복잡함Fluent bit– 경량화 되어 자원 소모가 적고, 빠른 처리 속도 제공– 컨테이너 환경에 적합하고 메모리 효율성이 뛰어남– 로그 처리 파이프라인이 다른 컴포넌트와 비교했을 때,일부 기능이 제한적일 수 있음LogStash– 다양한 데이터 입력과 출력 플러그인 지원– ElasticSearch와의 연동이 강력하며, 데이터 처리 파이프라인 구축이 상대적으로 용이– 자원 소모가 크고, 처리량이 많은 시나리오에서성능에 제약이 있을 수 있음 2-a. 사전 준비사항 1) 로그를 생성할 애플리케이션 생성git clone https://github.com/GoogleCloudPlatform/microservices-demo.git cd microservice-demo 2) 애플리케이션 yaml 파일 클러스터에 적용kubectl apply -f ./microservice-demo/release/kubernetes-manifests.yaml 3) 배포 확인kubectl get pod -A -n logging 2-b. Elasticsearch(Amazon OpenSearch Service) 생성 https://docs.aws.amazon.com/ko_kr/opensearch-service/latest/developerguide/createupdatedomains.html 를 참고하여 Elasticsearch 생성 2-c. AWS IRSA (IAM Role for Service Account) 설정 Kubernetes Service Account와 AWS IAM 역할을 연결하여 AWS 리소스에 대한 접근 권한을 부여하는 접근제어 방식1) EKS OIDC Identity Providers 생성 IAM > Access Management > Identity Providers > Add Provider → 공급자 유형 : OpenID Connect → 공급자 URL EKS > Clusters > 클러스터 선택 > Overview > OpenID Connect provider URL → 대상 : sts.amazonaws.com 2) IAM Policy 생성 IAM > Access Management > Policies > Create policy{ "Version": "2012-10-17", "Statement": [ { "Action": [ "es:ESHttp*" ], "Resource": "${OPENSEARCH_ARN}", "Effect": "Allow" } ]}→ ${OPENSEARCH_ARN} : 생성한 OpenSearch의 ARN 정보로 교체 3) IAM Role 생성 IAM > Access Management > Policies > Create role→ 신뢰할 수 있는 엔터티 유형 : 사용자 지정 신뢰 정책{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "${IDENTITY_PROVIDER_ARN}" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "${IDENTITY_PROVIDER}:aud": "sts.amazonaws.com", "${IDENTITY_PROVIDER}:sub": "${SERVICE_ACCOUNT_NAME}", } } } ] } → ${IDENTITY_PROVIDER_ARN} : 위에서 확인한 EKS OpenID Connect provider ARN 값→ ${IDENTITY_PROVIDER}:aud : 위에서 확인한 EKS OpenID Connect provider→ ${IDENTITY_PROVIDER}:sub : 생성할 Service Account 이름 2-d. RBAC (Role-Based Access Control) 설정 Kubernetes Service Account에게 클러스터 수준의 리소스 접근을 제어할 권한 부여1) Service Account 생성apiVersion: v1 kind: ServiceAccount metadata: name: fluent-bit annotations: eks.amazonaws.com/role-arn: ${IAM_ROLE_ARN} namespace: logging 2) Cluster Role 생성apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: fluent-bit-read rules: - apiGroups: - "" resources: - namespaces - pods verbs: - get - list - watch 3) Cluster Role Binding 생성apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: fluent-bit-read roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: fluent-bit-read subjects: - kind: ServiceAccount name: fluent-bit namespace: logging 2-e. Fluent-bit ConfigMap 생성 apiVersion: v1 kind: ConfigMap metadata: labels: k8s-app: fluent-bit name: fluent-bit-config namespace: logging data: fluent-bit.conf: | [SERVICE] Flush 1 Log_Level info Daemon off Parsers_File parsers.conf HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 @INCLUDE input-kubernetes.conf @INCLUDE filter-kubernetes.conf @INCLUDE output-opensearch.conf input-kubernetes.conf: | [INPUT] Name tail Tag kube.* Path /var/log/containers/*.log Parser docker DB /var/log/flb_kube.db Mem_Buf_Limit 5MB Skip_Long_Lines On Refresh_Interval 10 filter-kubernetes.conf: | [FILTER] Name kubernetes Match kube.* Kube_URL https://kubernetes.default.svc:443 Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token Kube_Tag_Prefix kube.var.log.containers. Merge_Log On Merge_Log_Key log_processed K8S-Logging.Parser On K8S-Logging.Exclude On output-opensearch.conf: | [OUTPUT] Name es Match * Host ${OPENSEARCH_ENDPOINT} Port 443 TLS On AWS_Auth On AWS_Region ${AWS_REGION} Index ${INDEX_NAME} Replace_Dots On Suppress_Type_Name On parsers.conf: | [PARSER] Name docker Format json Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L Time_Keep On→ [INPUT] Path /var/log/containers/*.log : 수집할 로그가 위치한 경로→ [OUTPUT] Host ${OPENSEARCH_ENDPOINT} AWS_Region ${AWS_REGION} Index ${INDEX_NAME} : Daemonset 컨테이너의 환경 변수에서 설정데몬셋(DaemonSet)과 ${OPENSEARCH_ENDPOINT} 변수를 사용하여 각 노드가 자체의OpenSearch 인스턴스로 로그 데이터를 전송하도록 구성하면, 각 노드가 독립적으로 로그 데이터를 처리하므로써 장애상황이 발생하여도 다른 노드는 정상적으로 로그 데이터를 전송하고 처리할 수 있습니다. 이로 인해 단일 포인트 오브 실패를 피할 수 있으며, 클러스터의 안정성과 로그 데이터의 신뢰성을 향상시킬 수 있음 2-f. Fluent-bit Daemonset 생성 apiVersion: apps/v1 kind: DaemonSet metadata: labels: k8s-app: fluent-bit-logging kubernetes.io/cluster-service: "true" version: v1 name: fluent-bit namespace: logging spec: selector: matchLabels: k8s-app: fluent-bit-logging template: metadata: annotations: prometheus.io/path: /api/v1/metrics/prometheus prometheus.io/port: "2020" prometheus.io/scrape: "true" labels: k8s-app: fluent-bit-logging kubernetes.io/cluster-service: "true" version: v1 spec: containers: - env: - name: OPENSEARCH_ENDPOINT value: ${OPENSEARCH_ENDPOINT} - name: AWS_REGION value: ${AWS_REGION} - name: INDEX_NAME value: ${INDEX_NAME} name: fluent-bit image: amazon/aws-for-fluent-bit:2.28.0 imagePullPolicy: Always ports: - containerPort: 2020 volumeMounts: - mountPath: /var/log name: varlog - mountPath: /var/lib/docker/containers name: varlibdockercontainers readOnly: true - mountPath: /fluent-bit/etc/ name: fluent-bit-config serviceAccountName: fluent-bit terminationGracePeriodSeconds: 10 tolerations: - effect: NoSchedule key: node-role.kubernetes.io/master operator: Exists - effect: NoExecute operator: Exists - effect: NoSchedule operator: Exists volumes: - hostPath: path: /var/log name: varlog - hostPath: path: /var/lib/docker/containers name: varlibdockercontainers - configMap: name: fluent-bit-config name: fluent-bit-config→ ${OPENSEARCH_ENDPOINT} : OpenSearch endpoint url (https:// 포함 X)→ ${AWS_REGION}→ ${INDEX_NAME} : 수집된 로그 데이터를 OpenSearch로 전송하기 전 어떤 인덱스 이름에 해당 로그를 저장할 지 정의→ image: amazon/aws-for-fluent-bit:2.28.0→ serviceAccountName: fluent-bit : 위에서 생성한 IAM Role에 설정값으로 지정 3. OpenSearch 동작 확인 1) OpenSearch 접속 2) 인덱스 패턴 생성메뉴 > Management > Stack Management > Index Patterns > Create index patternStep 1 of 2 위에서 설정한 Index Name (eks-log)를 검색하면 일치하는 소스가 조회됨 로그데이터에 time이라는 필드에 이벤트 시간 정보가 포함되어있다면 OpenSearch에서 @timestamp 필드에 매핑하게 되어정확한 시간 순서로 이벤트를 확인할 수 있음 3) 로그 적재 확인 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2024년 02월 08일
구글OTP PC/모바일 동시에 사용하는 방법 ARTICLE by Sangmi Park 2023년 11월 21일 안녕하세요~ 베스핀글로벌 D&A실 김경진님이 작성해 주신 ‘구글 OTP PC/모바일 동시에 사용하는 방법’에 대해 알아보겠습니다. 목적 AWS 콘솔 접속 보안에 PC/모바일에서 자유롭게 사용하게 위해크롬 브라우저에 확장 프로그램(extention)으로 설치되므로 좀 더 빠르고, 편하게 콘솔 로그인 가능하다.핸드폰 분실, 교체 등의 사유로 구글OTP 사용이 불가한 경우에 대비가 가능하다. 방법 다음의 스텝으로 진행하면 된다.크롬 확장 프로그램 인증 도구 (Authenticator) 를 설치하고 등록한다.AWS IAM에서 MFA 디바이스에서 QR코드 또는 Secret Key를 백업한다.모바일 구글OTP에 QR코드 또는 Secret key를 이용하여 등록한다.완료되면 PC/모바일 중 사용하기 편한 OTP 번호를 입력하여 콘솔 로그인한다.(제약 사항) 크롬 브라우저면 가능하다. 3. 크롬에 인증 도구 (Authenticator) 설치 1) 크롬 브라우저에서 다음의 링크에서 크롬 확장 프로그램 인증 도구 (authenticator)를 Chrome에 추가한다.https://chrome.google.com/webstore/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai 2) 확장 프로그램 추가를 선택한다. 3) 크롬 우상단의 확장프로그램을 선택하여 인증 도구를 고정시킨다. 4) 고정되면 크롬 우상단에 아래와 같은 인증 도구 아이콘이 생긴다. (설치 완료) 4. AWS 콘솔에서 IAM MFA 디바이스 관리 1) AWS 콘솔 로긴하여 IAM > Users 에서 적용할 사용자를 확인하여 Security credentials 탭으로 이동한 후, Assigned MFA deivce / Manage 를 선택한다. 2) Virtual MFA device 선택 후, 다음을 클릭한다. 3) Show QR Code 를 눌러 QR 코드를 표시한다. 4) QR코드를 모바일 카메라 등으로 사진 찍어 두거나 또는 캡쳐하여 PC에 보관한다. (백업용)※ QR코드 대신 다음의 secret key 를 이용해도 무방하다. 5) 설치한 인증도구의 QR 코드 스캔을 클릭하여 계정을 추가한다. 6) 기존 AWS IAM 의 QR 코드를 아래와 같이 선택한다. 7) 등록이 정상적으로 완료되면 아래와 같이 OTP 코드가 확인된다. 8) AWS IAM MFA 디바이스 세팅에서 위에 OTP 코드를 순차적으로 입력한다. 9) 등록이 잘되었는지 확인하고, 콘솔 로그인 해본다. ※ QR코드 추가에 문제 발생시 대신 다음의 secret key 를 이용해도 무방하다. 5. 모바일 구글OTP에 추가 모바일 Google OTP 앱을 실행하여,아래 + 메뉴을 선택한다.사진 찍어 둔 QR 코드를 모바일 구글OTP로 스캔하거나, 설정키를 입력하여 등록한다.정상 등록확인 후, 콘솔 로그인해 본다.<끝> 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 11월 21일
Slack Bolt를 활용한 Python Chatbot 가이드 TECH by Sangmi Park 2023년 11월 15일 Slack Bolt 란? Bolt는 Slack 고유의 SDK로서 여러 최신 API들을 담고 있는 라이브러리를 제공합니다.왜 Slack bolt를 사용하는지?Slack bolt는 기존에 사용하던 slack_sdk를 기반으로 만들어진 SDK로 slack_sdk의 기능을 모두 사용할 수 있고, 기존에 코드로 구현하기 복잡했던event 트래깅 혹은 websocket mode들을 간단하게 구현 할 수 있다는 장점이 있습니다. 또한 Slack에서 직접 개발 업데이트를 제공해주어 신규 API에 대한 빠른 대응을 준비할 수 있습니다. 1. Slack App 생성 Slack Bolt를 활용하여 Python Chatbot을 개발하기에 앞서 Slack에 메세지를 보내거나 읽어오는 역할을 수행할 Slack App을 생성해야 합니다. 1-1. Slack Workspace 로그인 Chatbot을 연동하려고 하는 Slack WorkSpace에 로그인 한 후 Slack API 페이지로 이동합니다.https://api.slack.com/apps/ 1-2. Slack App 생성 Slack Api 페이지에서 신규 Slack App을 생성합니다.‘Create New App’을 클릭Create an app 팝업이 뜨면 ‘From scratch’ 선택App Name에 chatbot으로 사용할 App명을 지정Chatbot을 활용하려고 하는 Workspace를 선택Create App을 클릭하여 신규 Slack App을 생성 1-3. App/Bot Token 생성 Python에서 신규 생성한 Bot을 사용하기 위해서는 인가된 접근임을 증명할 Token이 필요합니다.Token은 신규 생성한 Bot Page에서 생성 할 수 있습니다. Token을 신규 생성한 후 유출되지 않도록 주의 해야합니다. 1-3-1. App Token 생성 Slack API 페이지에서 신규 생성한 App을 선택합니다. Setting > Basic Information > App-Level-Tokens 에서 App Token을 생성합니다.생성하려는 App Token의 Scope는 ‘connections:write’를 선택합니다. 3. 생성된 Token을 안전한 곳에 저장합니다. 1-3-2. Bot Token 생성 Features > OAuth & Permissions > Scopes > Bot Token Scopes에서 ‘chat:write’ 권한을 추가해 줍니다. 추가한 Scopes를 Workspace에 적용시키려면 Install이 필요합니다.Features > OAuth & Permissions > OAuth Tokens for Your Workspace 에서 ‘Install to Workspace’ 버튼을 클릭, 권한을 허가 해줍니다. 권한을 허용하면 Features > OAuth & Permissions > OAuth Tokens for Your Workspace 에서 신규 생성된 Bot Token을 확인 할 수 있습니다.해당 토큰을 안전한 곳에 저장합니다. 1-4. Slack App Socket mode 활성화 Slack에서 보내는 메시지를 신규로 만든 Slack App이 실시간으로 체크해서 반응 할 수 있도록 구성하기 위해서는 여러 방법이 있지만 이 가이드에서는 SocketMode를 사용합니다.Settings > Socket Mode > Connect using Socket Mode 에서 Enable Socket Mode 버튼을 활성화 합니다. 2. Python Slack Chatbot 작성 2-1. Python 환경 구성 Python3와 pip가 설치 되어 있다는 가정하에 설명 하겠습니다.만약 설치가 되어 있지 않다면 OS 환경에 맞춰서 python3 최신버전과 그와 연동되는 pip를 설치해주세요. 2-1-1. slack_bolt SDK 설치 pip를 사용하여 slack chatbot을 구성할 서버에 slack_bolt 라이브러리를 설치하여 줍니다.(문서작성 기준 최신버전 사용 slack_bolt v1.18.0) 2-1-2. Chatbot python 파일 작성 app.py 파일을 생성합니다.아래의 테스트 코드를 작성합니다.SLACK_BOT_TOKEN 과 SLACK_APP_TOKEN 에 위에서 저장했던 Token 값을 넣어줍니다. 3. python3 로 app.py를 실행합니다. 4. Bolt App이 실행되고 있다는 문구가 뜨면 성공적으로 연동 된 것 입니다. 3. Slack Chatbot 테스트 이제 생성한 Slack App과 Python Chatbot을 활용하여 여러 Event를 처리할 수 있습니다.Slack API에는 많은 Event들이 존재하는데, 다양한 Event에 대한 정보는 Slack 공식 Document를 참고하여 주세요. https://api.slack.com/apis/connections/events-api 3-1. Chatbot Event Subscriptions 등록 Slack App에서 Event에 대한 정보를 Python Chatbot으로 Route 하기 위해서는, 어떤 Event를 Route 할 것인지에 대한 설정이 필요합니다.Slack에서 Event에 대한 구독을 등록함으로써 Python으로 작성한 Chatbot에 Event가 Route 되게 됩니다.Slack API 페이지에서 생성한 Slack App을 선택합니다. 2. Features > Event Subscriptions 에서 Enable Event를 활성화 합니다. 3. Subscribe to bot events에 Add Bot User Event를 선택하여 아래의 event들을 구독합니다. message.channels : 해당 App 이 추가된 public channel의 메시지를 Listen 합니다.message.groups : 해당 App 이 추가된 private channel의 메시지를 Listen 합니다.message.im : 해당 App 이 추가된 DM의 메시지를 Listen 합니다.message.mpim : 해당 App 이 추가된 Multi-person DM의 메시지를 Listen 합니다.4. 변경사항 저장을 위해 Save Change를 클릭합니다. 변경한 내용을 WorkSpace에 반영하기 위해서 Basic Information > Building Apps for Slack > Install your app 에서‘Reinstall to Workspace’를 클릭해 Reinstall 작업을 진행합니다. 3-2. Python Chatbot Event Handler 작성 Event 구독을 완료 하였기 때문에 이제 Python으로 작성한 Chatbot의 Websocket을 실행 시키게되면 Event 발생 시 지정한 Handler가 호출 되게 됩니다. Chatbot을 활용할 채널에 추가하고 메시지를 보내 작성한 Chatbot이 동작하도록 코드를 작성하겠습니다. 3-2-1. Message Event Route Handler Message Event는 Chatbot이 속한 Channel에서 누군가 메시지를 보냈을 때 발생하는 이벤트 입니다.테스트에서는 해당 이벤트를 Route하여 Chatbot이 응답하는 처리를 진행해 보겠습니다. Slack App을 만든 Workspace에서 임의의 채널에 Chatbot App을 초대 합니다. 2. Python Chatbot Code를 아래와 같이 수정합니다. python3로 app.py를 실행합니다. Chatbot을 초대한 채널에 ‘hello’ 메시지를 보냅니다.정상적으로 Chatbot이 응답하는지 확인합니다. 방금 읽은 인사이트를 실무에 직접 적용하고 싶으시다면?지금 바로 베스핀글로벌에 문의하세요. 베스핀글로벌 문의하기 2023년 11월 15일
[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일
사우디아라비아 vs. 아랍에미리트, 두 나라 사이 불꽃이 튀는 이유 ‘전격 공개’! BESPICK by Sangmi Park 2023년 06월 28일 안녕하세요, 베스픽 구독자 여러분. 오늘은 멀지만 몇 년 새 우리에게 친숙한 이름이 되어버린 ‘중동’, 그중에서도 지역을 대표하는 두 나라 ‘사우디아라비아’와 ‘아랍에미리트(UAE)’의 긴장 관계에 대해 뒷얘기를 풀어보고자 합니다.사실 두 나라 사이의 긴장 관계는 하루 이틀 사이에 생겨난 것은 아닙니다. 우리나라만 봐도 국경을 맞대고 있는 나라의 사이가 아주 좋기란 쉽지 않죠. 사우디아라비아와 아랍에미리트도 ‘중동의 형제’라 불리며, 깊은 교류와 문화적 공통점을 바탕으로 긴밀한 동맹을 유지하고 있지만(!) 그 속내는 다르다는데요. 그게 클라우드 혹은 디지털 기술과 무슨 상관이냐고요? 끝까지 다 읽으시면 알게 됩니다! ‘아부다비’·‘두바이’ 알지만… 들어는 봤니, ‘리야드’?👂 혹시 사우디아라비아의 수도가 어디인지 알고 계셨나요? 아랍에미리트의 아부다비와 두바이가 세계적으로 유명한 것에 비해, 사우디아라비아는 알아도 그 수도 리야드는 모르는 사람들이 많습니다. 세계에서 두 번째로 많은 석유 생산량을 앞세워 경제와 국력의 덩치를 키운 사우디아라비아가 중동 지역의 맹주인 건 확실합니다. 아랍 국가 중 유일한 G20 국가이기도 하고요. 하지만 중동 지역에 출장을 간다면, 또는 관광을 하러 간다면 그 도착지는 리야드가 아닌 아랍에미리트의 두 도시, 아부다비와 두바이 중 하나일 확률이 매우 높습니다. Abu Dhabi, Source: traveler.marriott.com/ 아랍에미리트의 수도 아부다비는 현재 도시 내에 5개의 경제 자유 구역을 갖추고 있습니다. 아부다비 투자 진흥청(Abu Dhabi Investment Authority)은 세계 최대 펀드 중 하나고요. 잘 알려진 것처럼 두바이엔 세계에서 가장 고급스러운 호텔과 세계에서 가장 높은 건물이 있죠. 아부다비는 2022년 글로벌 도시 성장 전망(GCO) Top 10 중 9위에 뽑혔고요. 두바이는 같은 지수에서는 11위였습니다. 전 세계 150개 도시를 대상으로 분석한 이 보고서에서 아부다비와 두바이는 중동 지역의 도시 중 가장 높은 순위를 차지했으며, 리야드는 30위권 내에 없었습니다. 아랍에미리트가 가장 글로벌한 중동 국가임을 입증하는 것이죠. 2020년 기준 사우디아라비아의 국내총생산(GDP)은 약 7000억 달러로, 아랍에미리트의 2배나 되고 인구로 비교해도 사우디아라비아가 아랍에미리트의 3배가 넘습니다. 하지만 1인당 구매력 평가 지수(PPP) 기준으로 아랍에미리트는 세계에서 가장 부유한 국가 8위, 중동에서는 카타르에 이은 2위입니다. 그에 비해 사우디아라비아는 아랍에미리트는 물론, 쿠웨이트에도 밀려 중동 지역 내 4위를 기록하고 있죠. 아무리 사우디아라비아가 경제 규모나 영토가 더 크고 인구도 많다지만 글로벌에서 평가하는 국가와 도시의 브랜드, 또 실질적 삶의 질에 있어서는 아랍에미리트에 밀리고 있는 형국인데요. 아랍에미리트나 사우디아라비아나 자국의 석유 매장량이 언젠가는 고갈될지도 모른다는 불안감에 휩싸여 있는 것은 마찬가지입니다. 그 때문에 아랍에미리트나 사우디아라비아나 석유 이후의 경제, 즉 ‘포스트 오일(Post-Oil) 시대’를 준비할 수밖에 없는 것이죠. 석유 없는 미래를 대비해야 하는 중동 국가들에 대해 더 자세히 알고 싶다면, 저번주 베스픽을 확인해 주세요! 👉 최대 산유지 중동, 이제는 ‘클세권’ 노린다? 포스트 오일 시대를 대비하라, 자금·인력·파트너 쟁탈전사우디아라비아와 아랍에미리트 두 나라 모두가 석유 다음의 자원으로 주목한 것이 바로 ‘디지털 경제’입니다. 디지털 경제란 모든 경제 활동을 디지털화시켜 그 발전 속도를 크게 증대시키는 것을 의미하는데요. 세계은행에 따르면 디지털 경제가 중동 및 북아프리카(MENA) 지역에서 많은 일자리를 창출할 수 있을 뿐 아니라, 각국의 국내총생산(GDP)을 총합 1조 6000억 달러까지 증가시킬 수 있다고 하는데요. MENA 지역의 디지털 경제 시장 규모는 현재 400억 달러가 안되지만 2030년까지 박차를 가하면 4000억 달러에 이를 수도 있다는(!) 분석이 나오기도 했습니다. 디지털 경제를 위해서는 무엇이 필요할까요? 자금과 함께 고급 인력, 그리고 전문성을 갖춘 파트너겠죠. 바로 이를 확보하기 위한 경쟁이 사우디아라비아와 아랍에미리트 사이에 벌어지기 시작했습니다. 기회와 자원은 한정적이고, 석유 고갈에 대한 두려움은 큰 만큼 그 경쟁이 더욱 치열한데요. 아랍에미리트는 오랫동안 외국계 자본을 유치하기 위한 전략을 적극적으로 추진해왔습니다. 팬데믹이 시작되면서 전 세계적으로 외국인 직접 투자(FDI)가 42% 감소했지만 아랍에미리트는 달랐습니다. 2020년에도 전년대비 20억 달러가 늘어 199억 달러를 기록했고 2021년에는 사상 최고치인 207억 달러를 달성했죠. 배경에는 아랍에미리트 정부 차원의 노력이 있었습니다. 이미 예전부터 중동 지역에서 가장 개방적인 정책을 펴왔던 아랍에미리트는 2019년 자국에서 사업 혹은 투자를 하길 원하거나 AI·빅데이터·SW 등 전문 기술을 보유한 외국인에게 골든 비자를 주어 10년간 장기 체류를 가능하게 했고요. 2020년에는 허가된 장소에서의 음주와 결혼하지 않은 커플의 동거를 허락했습니다. 글로벌 스탠다드에 맞춰 토요일과 일요일을 휴일로 바꾸기도 했죠. 그런데 이 흐름에 사우디아라비아도 동참하면서 두 나라 사이 경쟁이 본격화됩니다. 아랍에미리트가 중동 지역의 비즈니스 허브이니, 글로벌 기업의 중동 본사들은 당연히 두바이나 아부다비에 위치해 있었는데요. 2021년 2월 사우디아라비아가 2024년까지 다국적 기업의 본사를 리야드로 옮기지 않으면 비즈니스를 금지하겠다며 엄포를 놓은 거죠. 글로벌 기업의 중동 지역 주요 비즈니스 파트너 자리를 놓고 아랍에미리트에 도전한 것입니다. 이 조치에 힘입어 리야드는 2021년 말 기준으로 44개나 되는 글로벌 기업의 지역 본사를 유치했습니다. 그해 1월에 20개뿐이었던 걸 감안하면 1년도 안되어서 2배 넘게 증가했죠. 아랍에미리트는 이에 맞불을 놓듯 최근 외국인의 기업 지분 100% 소유를 허용했습니다. 말하자면 사우디아라비아는 강경한 태도로 아랍에미리트에 도전하고 있고, 아랍에미리트는 당근을 주는 유화책을 어필하며 각자의 목표를 위해 열심히 뛰고 있는 셈입니다. ‘비전 2030’ vs ‘Projects of the 50’, 승자는 어부지리?🎣 사우디아라비아의 경제 다각화를 주도적으로 이끄는 사람이 바로 최근 한국을 방문했던 빈 살만 왕세자, ‘미스터 에브리씽’입니다. 국내에서도 화제가 됐던 네옴시티로 대표되는 ‘비전 2030’을 내세워 사우디아라비아의 디지털 전환을 강력하게 추진하고 있는데요. 사우디아라비아는 G20 국가들 중 ‘Top Digital Riser’로 선정될 만큼 디지털 전환을 위한 포괄적인 정부 지원을 발표했죠. 또한 사우디아라비아는 최근 의료, 제조 그리고 클라우드를 포함한 산업 분야에 투자할 경우 인센티브를 제공하는 특별 경제 구역을 만들겠다고 밝혔습니다. 사우디아라비아는 이런 특별 경제구역을 4~5개는 만들 계획이라고 하는데요. 자연스럽게 이미 여러 경제 구역을 갖추고 있는 아랍에미리트와의 경쟁은 피할 수 없겠죠. 아랍에미리트도 마찬가지입니다. 건국 50주년과 함께 ‘미래 50년을 위한 국가 전략(Projects of the 50)’이라는 이름으로 향후 50년간의 야심찬 성장 계획을 발표했는데요. 기술과 혁신을 성장의 핵심 동인으로 삼아 향후 10년 동안 국가의 경제 규모를 2배로 늘리는 것을 목표로 하고 있습니다. 이에 따라 핀테크, 블록체인, AI, 클라우드, 모빌리티 등 미래 핵심 기술 기업들의 설립과 운영을 지원하고 있죠. 잠재력이 높은 기술 기업들에 문을 열어 석유 자원이 아닌 미래 자원을 개발하기 위함입니다. 글로벌 빅테크들은 이를 틈타 중동에 활발하게 진출하고 있는데요. 특히 디지털 경제의 가장 기본적인 토대가 되는 주요 인프라, 클라우드를 공급하는 CSP 기업들의 기세가 무섭습니다. 실제로 해당 지역의 클라우드 컴퓨팅 시장은 2026년까지 314억 달러로 급증할 것으로 여겨지고 있는데요. 2020년 오라클은 사우디아라비아 제다(Jeddah)에 클라우드 리전을 설립하더니, 같은 해 두바이와 아부다비에 차례로 리전을 여는 공격적 행보를 보였습니다. 구글도 아람코와 합작 투자의 일환으로 담맘(Dammam)에 리전을 개설했고요. 아랍에미리트에도 이미 마이크로소프트를 선두로 알리바바, IBM 등 내로라하는 클라우드 기업들이 대거 진출해 있습니다. 양국 외에 바레인과 카타르에도 클라우드 리전이 설립되어 중동 지역의 클라우드 전환 기회를 호시탐탐 노리고 있습니다. 이렇게 치열한 경쟁 속에서 과연 승자는 누가 될까요? 사우디아라비아? 아랍에미리트? 그 틈새에서 두 나라로부터 가장 적극적이고 최적화된 지원을 얻어낼 기업이 바로 승자일 확률이 가장 높지 않을까 싶은데요. 중동 지역에서 디지털 경제 개발을 저해하는 가장 큰 요인으로 꼽히는 것이 바로 기술 격차입니다. 클라우드를 비롯한 전문 기술에 대한 현지 수요와 공급 사이에 어마어마한 격차가 자리 잡고 있기 때문에 기술을 서로 교류하고 전문성을 보유한 파트너가 절실한 것이죠. 바로 이 가려운 부분을 딱 긁어주면서, 신뢰를 바탕으로 비즈니스를 추진할 수 있는 기업이라면 이 치열한 싸움에서 피 흘리지 않고 승자가 될 수 있지 않을까요? 베스핀글로벌은 2019년 중동과 북아프리카 지역에 첫 진출한 이후, 해당 지역의 디지털 전환을 돕고 있습니다. 올해 아부다비 최초 클라우드 운영센터와 교육 아카데미를 설립하여 클라우드 인재를 한데 모아 교육하고 양성하고 채용함으로써 해당 지역의 클라우드 생태계를 조성했는데요. 향후 중동에서 펼쳐질 포스트 오일의 시대, 디지털 전환은 어디까지 펼쳐질까요? 그리고 베스핀글로벌은 어떠한 역할을 맡게 될까요? 베스핀글로벌이 앞장서고 있는 중동의 미래에 대해 주목해 주시기 바랍니다. 오늘은 이것으로 마무리하겠습니다. 다음주에 만나요 베스픽 질문&피드백 남기기 📰 안보면 클나우 “ICT 수출전략, 하드웨어에서 소프트웨어 중심으로 전환해야” 더보기오늘(20일) ICT 수출 활성화를 위한 민·관 합동 간담회가 열렸습니다. 수출 현황과 전망, 중동 등 새로운 시장 진출과 그 성공 사례를 공유하는 시간이었는데요. 이 자리에서 베스핀글로벌의 이한주 대표는 수출 전략을 하드웨어 중심에서 소프트웨어, 특히 클라우드 형태의 디지털 전략으로 대전환해야 한다고 강조했습니다.AI 챗봇 챗GPT ‘돌풍’…개발사 “2024년 매출 10억 달러 목표” 더보기공개 이후 일주일 이내에 100만 명 이상이 사용한 것으로 알려진 ‘챗GPT’에 관심이 집중되고 있습니다. 인간과 상당히 비슷한 대화는 물론, 프로그래밍도 가능하다고 하는데요. 개발사 측은 2024년 10억 달러 규모의 매출을 목표로 하고 있다고 합니다.오라클, FYQ2(9~11월) 호실적 발표… 클라우드 서비스 매출 성장세 더보기오라클이 전망을 웃도는 실적을 발표했습니다. 특히 매출의 65%를 차지하는 클라우드&온프레미스 서비스 매출 성장세가 두각을 나타냈는데요. 클라우드 관련 매출액이 전년 대비 40%나 증가했다고 합니다. ☁️ 안쓰면 클나우 2023 IT 키워드는 핀옵스(FinOps)? 2023 IT 트렌트를 보다보면 ‘핀옵스(FinOps)’라는 말을 자주 접하실 듯 합니다. 멀티 클라우드와 하이브리드 클라우드 사용이 증가하면서 클라우드 비용과 자원에 대한 전문적인 관리가 필요해진 것인데요. 핀옵스의 핵심은 다음 3가지입니다. 클라우드 비용 관리 전담 조직(인력)가시화 도구 사용클라우드 거버넌스 우리 회사의 핀옵스 역량이 궁금하신가요? 어떻게 핀옵스를 시작하면 좋을지 고민이신가요? 그런 분들을 위해 옵스나우 핀옵스 컨설팅 서비스를 소개합니다. 클라우드 관리 솔루션 OpsNow CMP(옵스나우 CMP)를 활용해 클라우드 비용 최적화를 위한 다양한 방안을 제시해 드립니다. 클라우드 비용 최적화를 위한 핀옵스 컨설팅 바로가기 클라우드 관리 솔루션 ‘옵스나우’ 자세히 보기 클라우드 도입 사례, 관리와 비용 절감을 위한 팁은 물론 국내외 IT 업계 소식까지당신의 클라우드 원픽 뉴스레터 베스픽에서 만나보세요.뉴스레터를 구독하시면 매주 화요일, 가장 먼저 베스픽을 받아볼 수 있습니다 🙂 방금 읽은 이 콘텐츠가 마음에 드셨다면?지금 바로 베스핀글로벌의 뉴스레터 ‘베스픽’을 구독하고, 매주 인사이트를 가장 빠르게 받아보세요. 베스핀글로벌 문의하기 뉴스레터 구독하기 2023년 06월 28일
[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일