반응형

서로 다른 계정 간 S3 To S3 복사작업 하는 방법 with php laravel

다른 언어도 동일하게 copyObject API를 사용하면 가능하다.

사전 데이터

aws-sdk-php
A 계정으로 만든 버킷
B 계정으로 만든 버킷
A,B 버킷에 접근할 iam 계정

사전 작업

AWS 콘솔에서 iam 계정 번호를 준비해, 사용할 버킷 A, B에 아래와 같이 your_iam_ID 위치에 권한을, your_bucket에 버킷 이름을 넣는다.

  • ListBucket : 디렉토리 복사코드를 준비하기 위한 리스트 조회 권한
  • GetObject : 파일을 다운로드할 수 있는 조회 권한
  • PutObject : 파일을 업로드 할 수 있는 권한

해당 위치 접근 방법은 Amazon S3 > 버킷 > 권한 > 버킷 정책

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowAccountyour_iam_IDAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::your_iam_ID:root"
            },
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::your_bucket",
                "arn:aws:s3:::your_bucket/*"
            ]
        }
    ]
}

CopyObject API 구현

CopyObject API는 파일 단위로 A에서 B로 옮기는 작업이다. 따라서 단일 건에 대해서는 권한만 잘 오픈해준다면, 어렵지 않은 작업이다.

단일 파일 복사 작업

use Aws\\S3\\S3Client;

class S3ToS3Transfer{

    public function fileCopy(){
        $targetS3Client = new S3Client([
            'credentials' => [
                'key' => iam_key,
                'secret' => iam_secret_Key,
            ],
            'region' => 'ap-northeast-2',
            'version' => 'latest',
        ]);

        //source 위치에 있는 파일을 key 위치로 복사
        $targetS3Client->copyObject([
            'Bucket'     => 'target_bucket',
            'Key'        => 'target_path',
            'CopySource' => urlencode('source_bucket/' . $sourcePath),
        ]);

    }

CopySource의 버킷을 명시해줘야 정상 동작 가능

디렉토리 복사 작업

디렉토리 복사는 파일의 목록을 읽어오는 ListBucket API를 활용해야 한다.

흐름은 대략 이렇다

  1. Source S3 스토리지 리스트 불러오기(ListObjectsV2 API)
  2. 불러온 리스트에서 size가 0인 디렉토리 제외하고 모두 배열에 저장(1000개 이상일 경우 페이지네이션 처리)
  3. foreach로 각 object를 돌며 단일 copyObject API 요청
    public function directoryCopy(array $data){
        $sourceS3Client = new S3Client([
            'credentials' => [
                'key' => iam_key,
                'secret' => iam_secret_key,
            ],
            'region' => 'ap-northeast-2',
            'version' => 'latest',
        ]);

        $targetS3Client = new S3Client([
            'credentials' => [
                'key' => iam_key,
                'secret' => iam_secret_key,
            ],
            'region' => 'ap-northeast-2',
            'version' => 'latest',
        ]);

        // source S3 디렉토리 탐색 시작(1000개 단위 페이징 되어있음)
        $requestParams = [
                'Bucket' => $sourceStorageInfo->virtual_path,
                'Prefix' => $sourcePath, // 조회할 디렉토리 지정
            ];

        do{
            $objects = $sourceS3Client->listObjectsV2($requestParams);

            // 다음 페이지 존재확인 IsTruncated : 1 or 0
            if ($objects['IsTruncated']){
                $requestParams = [
                    'Bucket' => $sourceStorageInfo->virtual_path,
                    'Prefix' => $sourcePath, // 조회할 디렉토리 지정
                    'ContinuationToken' => $objects['NextContinuationToken'] // 다음 페이지 토큰
                ];

                $objectsNextPageFlag = true;

            } else {
                $objectsNextPageFlag = false;
            }

            //오브젝트 리스트 파싱
            if (isset($objects['Contents'])) {
                foreach ($objects['Contents'] as $object) {
                    // 디렉토리 오브젝트 제외
                    if ($object['Size'] == 0) {
                        continue;
                    }

                    $notIncludeDirectoryObjects[] = $object;
                }
            }
            
        } while($objectsNextPageFlag); // 페이징 끝날 때까지 반복

        //배열 전체 탐색해 target S3에 파일 복사
        foreach ($notIncludeDirectoryObjects as $object) {
            $objectKey = $object['Key']; // 버킷 제외 파일 경로
            $fileNameWithExt = basename($objectKey); // 파일명 추출

            //source 위치에 있는 파일을 key 위치로 복사
            $targetS3Client->copyObject([
                'Bucket'     => 'target_bucket',
                'Key'        => 'target_path',
                'CopySource' => urlencode('source_bucket/' . $sourcePath), // 버킷 + 소스 위치
            ]);
        }
    }

리스트 조회한 데이터를 그대로 복사요청 진행하면 되는 로직

반응형

'공부 > Laravel' 카테고리의 다른 글

Laravel 5.8 TestCode  (0) 2024.06.21
Pusher를 활용한 Laravel5.8 + Javascript 소켓통신  (0) 2024.06.20
반응형

HLS(HTTP Live Streaming)는 Apple이 개발한 비디오 스트리밍 프로토콜로, 주로 인터넷을 통해 오디오 및 비디오 콘텐츠를 실시간 또는 주문형(on-demand)으로 전달하는 데 사용


핵심 개념

  • HTTP 기반
  • 콘텐츠를 일반 HTTP 서버를 통해 전송하므로 방화벽, CDN, 캐시 서버와 잘 호환
  • Segment(조각) 방식 전송
  • 전체 비디오를 작게 분할(보통 2~10초)한 .ts 파일로 쪼개어 순차적으로 전송
  • M3U8 플레이리스트 사용
  • .m3u8 형식의 플레이리스트 파일을 사용해 어떤 세그먼트를 재생할지 정의
  • 적응형 비트레이트 스트리밍(ABR)
  • 네트워크 상태에 따라 자동으로 품질(해상도/비트레이트)을 조정해 버퍼링을 최소화

HLS 구성 요소

  1. Master Playlist (m3u8)
  2. 여러 해상도/비트레이트 버전을 링크한 상위 목록
  3. Media Playlist (m3u8)
  4. 특정 품질의 세그먼트 목록 (ex: segment1.ts, segment2.ts...)
  5. Media Segments (.ts)
  6. 실제 오디오/비디오 데이터가 들어 있는 짧은 MPEG-TS 파일들

작동 방식 요약

  1. 클라이언트가 .m3u8 플레이리스트 요청
  2. 플레이리스트에 있는 세그먼트(.ts) 파일들을 순차 다운로드
  3. 다운로드한 세그먼트를 재생
  4. 네트워크 상태 따라 다른 품질의 플레이리스트로 전환 가능

어디에 사용되나?

  • YouTube, Twitch, Netflix 등 OTT 서비스
  • 모바일/웹 브라우저 기반 스트리밍
  • 라이브 방송 시스템 (뉴스, 스포츠 등)

장점

  • 범용성: 브라우저와 모바일 기기에서 바로 재생 가능
  • HTTP 사용: 별도 스트리밍 서버 필요 없음
  • 적응형 스트리밍: 다양한 네트워크 환경에서 안정적 재생

M3U8

m3u8은 HLS(HTTP Live Streaming)에서 사용되는 플레이리스트 파일 형식으로, UTF-8 인코딩된 M3U 파일. 쉽게 말해, 재생할 미디어 파일(.ts 세그먼트 등)의 목록과 스트리밍 정보를 담고 있는 텍스트 파일


m3u8 파일이 하는 역할

  • 스트리밍할 미디어 세그먼트(.ts) 들의 경로를 나열
  • 각 세그먼트의 길이, 순서 정보를 포함
  • 경우에 따라 해상도별 스트림 목록(Master Playlist) 역할도 함

m3u8의 두 종류

  1. Master Playlist
    #EXTM3U
    #EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
    low.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=1280x720
    mid.m3u8
    #EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1920x1080
    high.m3u8
    
    
    사용자의 네트워크 상황에 따라 적절한 화질의 Media Playlist를 선택
  2. 여러 화질 버전의 Media Playlist를 포함한 상위 목록
  3. Media Playlist
    #EXTM3U
    #EXT-X-TARGETDURATION:10
    #EXT-X-VERSION:3
    #EXTINF:9.0,
    segment1.ts
    #EXTINF:10.0,
    segment2.ts
    #EXTINF:8.5,
    segment3.ts
    #EXT-X-ENDLIST
    
    
    위 순서대로 .ts 파일을 다운로드하고 재생
  4. 실제 비디오 세그먼트 목록을 나열

주요 태그 설명

#EXTM3U m3u8 파일의 시작을 알림
#EXTINF:<duration> 각 세그먼트의 재생 길이(초)
#EXT-X-STREAM-INF 마스터 재생 목록에서 각 해상도 스트림 정의
#EXT-X-ENDLIST 리스트가 종료되었음을 의미 (VOD에서 사용)
#EXT-X-TARGETDURATION 세그먼트의 최대 길이

m3u8 파일은 어떻게 쓰이나?

  • 웹 플레이어에서 .m3u8 주소를 불러와 스트리밍 시작
  • 라이브 방송은 .m3u8이 실시간으로 업데이트됨
  • 동영상 다운로드 도구에서 .m3u8을 분석해 전체 영상 다운로드 가능

.HLS에서 .ts 파일이란?

HLS 스트리밍에서 .ts는 MPEG-TS (MPEG Transport Stream) 형식의 비디오 세그먼트 파일

  • 비디오와 오디오 데이터를 포함한 실시간 전송용 포맷
  • .ts = Transport Stream
  • 스트리밍을 위해 짧게 나뉜 (예: 5~10초) 미디어 조각들

예시로 비교

파일 종류 확장자 의미

스트리밍 비디오 세그먼트 .ts MPEG Transport Stream
웹 프로그래밍 언어 파일 .ts TypeScript 소스코드

스트리밍에서 .ts 사용 예시

#EXTINF:10.0,
video1.ts
#EXTINF:10.0,
video2.ts
#EXTINF:10.0,
video3.ts

여기서 video1.ts, video2.ts 등은 비디오 데이터 조각들이고, 순서대로 스트리밍

 
반응형

'공부 > CS' 카테고리의 다른 글

WAF, ZTN  (1) 2025.04.27
API Gateway  (0) 2025.03.24
워터마크 기술 개념  (0) 2025.03.03
아키텍처 간략 정리  (0) 2025.01.05
언어별 연산 속도  (0) 2024.12.30
반응형

단일 장애 지점(Single Point Of Failure)

SPOF 문제는 개발 인프라를 구성할 때 빼 놓을 수 없는 고려점이다.

SPOF(Single Point of Failure)는 단일 구성 요소에 장애가 발생했을 때, 전체 시스템이 영향을 받아 서비스를 이용할 수 없게 되는 상황을 의미한다 예를 들어, 클라이언트가 요청을 보내는 서버가 하나뿐이라면, 해당 서버에 장애가 발생할 경우 서비스를 이용할 수 없게 된다.

다음은 웹 요청의 일반적인 흐름을 SPOF 관점에서 단순화한 예시이다.

모든 인프라에서 SPOF를 고려하기 위해 위와 같은 예시를 들었으며, 각 계층별로 SPOF는 반드시 고려해봐야 할 문제이다.

클라이언트가 서버에 요청을 진행하면, L4 로드밸런서가 요청을 받아 각 Proxy Server에 데이터를 넘기며, Proxy 서버는 요청을 내부의 WAS로 전달한다. WAS에서는 Database에 있는 값을 확인해 생성된 데이터를 Client에게 반환합니다.

L4 Load Balancer

L4 로드밸런서는 TCP/UDP 레벨에서 요청을 분산 처리하는 역할을 한다.

해당 계층에서 SPOF를 방지하기 위한 방법은 다음과 같다.

  • 이중화 구성 (Active-Active 또는 Active-Passive)
  • VRRP(Virtual Router Redundancy Protocol)를 통한 고가용성 구성
  • 클라우드 환경에서는 관리형 L4 (예: AWS NLB, Azure Load Balancer)를 활용해 내결함성 확보

SPOF 예방 방안

  • L4 LB를 두 대 이상 배치
  • 헬스 체크 기반의 자동 장애 전환(failover) 구성

Proxy Server

Proxy 서버는 클라이언트 요청을 받아 내부 WAS로 전달하거나 캐싱, 인증, 보안 처리 등의 역할을 한다.

프록시가 하나일 경우 SPOF가 발생하므로 수평 확장 및 L4 앞단 분산이 필수다.

SPOF 예방 방안

  • 여러 대의 프록시 서버를 L4 로드밸런서를 통해 분산
  • Stateless 설계로 프록시 간 장애 영향을 최소화
  • Proxy 레벨에서의 Failover 및 헬스 체크 기능 사용

WAS

WAS는 실제 비즈니스 로직이 실행되는 계층이다. 하나의 WAS 인스턴스에 모든 처리를 맡길 경우, 서비스 전체 장애가 발생할 수 있다.

SPOF 예방 방안

  • WAS 인스턴스를 다중 구성(Auto Scaling 포함)
  • Proxy 또는 L7 Load Balancer에서 로드밸런싱
  • 세션 클러스터링 또는 세션 스토리지 분리(Redis 등)를 통해 무상태 아키텍처 구현

Database

데이터베이스는 서비스의 핵심 데이터를 저장하므로, 장애 시 영향도가 가장 크다.

DB는 전통적으로 SPOF가 발생하기 쉬운 계층이므로, 고가용성 구성이 필수이다.

SPOF 예방 방안

  • Master-Slave 또는 Master-Master 복제 구성
  • 리더-팔로워 구조 + 자동 Failover (예: RDS Multi-AZ, MySQL with MHA)
  • 샤딩 또는 분산 DB 도입 고려
  • 정기 백업 및 장애 복구 절차 수립

SPOF는 모든 인프라 구성에서 반드시 고려해야 할 요소이며, 계층별로 고가용성을 확보하는 구조 설계가 안정적인 시스템 운영의 핵심이다.

반응형
반응형

S3에 장기보관하기 위한 목적을 가진 S3스토리지 클래스 DEEP_ARCHIVE는 Amazon S3 Glacier Deep Archive에서 사용되는 S3의 가장 저렴한 스토리지 클래스로, 자주 사용하지 않는 데이터, 장기 보관(Long-term Archival)을 위한 데이터 저장에 적합하다.

주요 특징

  1. 용도
    • 수 년에서 수십 년 동안 거의 접근하지 않지만, 규제나 컴플라이언스 목적으로 반드시 보관해야 하는 데이터를 저장할 때 사용
    • 예: 법적 기록, 의료 기록, 장기 백업 데이터
  2. 비용
    • S3 스토리지 클래스 중 가장 낮은 GB당 저장 비용
    • 대신, 검색(복원) 요청 및 검색 데이터 전송 비용이 상대적으로 높음
  3. 지연 시간
    • 복원 시간이 수 시간(12시간 이내) 소요
    • (2가지 옵션 제공: Standard - 최대 12시간, Bulk - 최대 48시간, Express - 수 분)
  4. 가용성/내구성
    • 내구성은 S3 표준과 동일한 99.999999999% (11 9's)
    • 가용성이 낮기에 자주 사용하지 않는 데이터에 대해서만 사용
  5. 액세스 방식
    • 데이터를 바로 읽을 수 없으며, 먼저 복원 요청을 해야 함.
    • 복원 요청이 완료되면 설정된 유지 기간 동안 임시적으로 표준 S3처럼 접근 가능.
  6. 적용 사례
    • 규제 준수 저장
    • 대규모 비활성 로그 데이터
    • 법적 증거자료 백업
    • 장기 백업 및 DR(Disaster Recovery) 데이터

정리

  • 최저 비용
  • 수년간 거의 액세스하지 않는 데이터
  • 즉시 액세스 불가 (복원 요청 필요)
  • 복원까지 수 시간 소요
반응형
반응형

MySQL의 시간 표현형식인 DATETIME, TIMESTAMP
두 표현형식에 대해서 알아보자

* 해당 글에서 말하는 local time이란 서버컴퓨터에 설정되어 있는 날짜 기준 시각을 의미

항목 TIMESTAMP DATETIME
용량 4바이트 8바이트
범위 1970-01-01 ~ 2038-01-19 1000-01-01 ~ 9999-12-31
시간대 영향 있음 (타임존 변환 자동 적용) 없음 (그대로 저장)
저장 방식 UNIX timestamp (초 단위) 구조화된 날짜/시간 필드
주의 사항 2038 문제, 시간대 혼동 가능 타임존 변환 로직 수동 구현 필요

TIMESTAMP

  • 저장 용량 : 4Byte
  • 저장 범위 : 1970-01-01 ~ 2038-01-19
  • 시간대 영향 : 서버 Timezone에 따라 변환
  • 내부 저장 방식 : UNIX 시간(초) 기반
  • 주의 사항 : 2038년 문제, timezone 혼동

특징

자동 시간대 관리

저장 : 시간 저장할 때 서버의 timezone → UTC로 변환되어 저장

조회 : 저장된 UTC → 현재 세션/서버의 timezone 기준으로 보여줌

장점

글로벌 서비스에서 사용자 시간대별로 시간 값을 표시할 때, TIMESTAMP는 자동으로 변환되므로 별도의 시간대 계산 로직 없이도 사용자에게 맞는 현지 시간을 보여줄 수 있다.

2038년 문제

TIMESTAMP는 4바이트 날짜 표현 데이터로써 초 단위로 저장하기에, 표현 가능한 범위가 -2147483548 ~ 2147483647이다. 해당 값의 최대값이 2038-01-19 03:14:07 UTC 이기에, 이후 시간 표현에 대해서 문제가 생긴다.

timezone 혼동

  • 서버로 요청하는 클라이언트의 local time이 변경되었을 경우

    • ex) 2025-05-05 10:00:00 → 2025-05-05 01:00:00

    • Asia/Seoul UTC +9* 타임존을 사용하고 있는 서버에서 서버의 TIMEZONE 설정을 UTC로 변경

      ⇒ 기존에 +9시간으로 나오던 시간이 +9가 안된 채로 보여줌

  • 같은 TIMESTAMP 값을 서로 다른 환경에서 비교할 때 오류

    • ex) A 서버 (Asia/Seoul)와 B 서버 (UTC)가 서로 TIMESTAMP 데이터를 주고받는 상황
    • A 서버 : 2025-05-05 12:00:00 UTC +9
    • B 서버 : 2025-05-05 03:00:00 UTC

DATETIME

  • 저장 용량 : 8Byte
  • 저장 범위 : 1000-01-01 ~ 9999-12-31
  • 시간대 영향 : 입력된 값 그대로 저장
  • 내부 저장 방식 : 구조화된 날짜.시간 필드
  • 주의 사항 : UTC 저장이 필요하면 직접 처리해야함

특징

8바이트 구조화된 방식으로 날짜·시간 정보를 별도 필드에 저장하며, 값 변환 없이 그대로 저장된다. 예: 9999-12-31과 같은 값도 안정적으로 표현 가능 (약 47비트 수준이지만 여유 있게 8바이트 확보)

장점

  • 서버 환경, 클라이언트 지역, 타임존 설정과 무관하게 항상 일정한 값 유지
  • TIMESTAMP와 다르게 8바이트의 넓은 범위 저장 가능
  • 타임존에 영향받지 않으며, 타임존 로직은 애플리케이션에서 명시적으로 제어 가능

기준 시간 지정 시 별도의 로직 필요

글로벌 서비스에서 DATETIME을 사용할 경우, 사용자 시간대에 맞게 표시하려면 애플리케이션에서 명시적인 기준 시간(예: UTC) 변환 로직이 필요하다.

반응형

'공부 > Database' 카테고리의 다른 글

RDBMS 쿼리 성능 개선 기초 ( 다수의 WHERE절 쿼리)  (0) 2024.07.24
반응형

보안설계에서 중요한 키워드 WAF, Zero Trust Network


1. WAF (Web Application Firewall)

정의

웹 애플리케이션 계층(L7)의 보안 방화벽

HTTP 요청/응답을 검사해서 악의적인 공격을 차단하는 역할


WAF가 막아주는 공격 유형:

공격 설명

SQL Injection 쿼리에 악성 코드 삽입 시도
XSS (크로스 사이트 스크립팅) 자바스크립트 삽입 공격
CSRF 인증된 사용자의 권한 도용
경로 탐색(Path Traversal) 파일 시스템 침투 시도
봇 트래픽 차단 스크래퍼, 크롤러, 무차별 대입 공격 차단 등

WAF는 어디에 위치하냐면:

[클라이언트]
   ↓
[WAF] ← 모든 HTTP 요청 검사
   ↓
[웹 서버 / 프록시 서버]
   ↓
[WAS]


WAF 종류

구분 예시

하드웨어 F5 ASM, Imperva
소프트웨어 ModSecurity (Apache/Nginx), NAXSI
클라우드형 AWS WAF, Cloudflare WAF, Azure WAF

2. Zero Trust Network (제로 트러스트 네트워크)

정의

"절대 아무도 신뢰하지 마라.

네트워크 내부든 외부든 모든 요청을 검증하고 최소한의 권한만 허용하라."


핵심 개념:

개념 의미

No implicit trust 내부망이라고 무조건 믿지 않음
모든 요청 인증/인가 사용자, 장치, 앱 단위 인증 필수
최소 권한 원칙 필요한 자원에만 접근 가능
세션 기반 보안 로그인 이후에도 지속적 확인 (MFA, 토큰 검사 등)

Zero Trust 흐름 예시:

[사용자 또는 디바이스 요청]
      ↓
[인증 시스템 (IDP, MFA 등)]
      ↓
[Zero Trust 게이트웨이 (ZTNA Proxy)]
      ↓
[애플리케이션]


구성 요소 예시:

요소 예시

ID 관리 Okta, Azure AD
접근 제어 Zscaler, Cloudflare Zero Trust, Tailscale
정책 엔진 Google BeyondCorp, Istio (서비스메쉬)

WAF vs Zero Trust 비교

항목 WAF Zero Trust

방어 대상 웹 애플리케이션 네트워크 전체 (사용자/디바이스/앱 등)
작동 계층 L7 (HTTP) 전 계층 (ID, 네트워크, 앱, 세션 등)
보안 방식 패턴 매칭, 룰 기반 인증, 정책, 신뢰 검증
목적 공격 차단 (XSS, SQLi 등) 접근 제한 + 인증 기반 통제
설치 위치 웹 서버 앞단 네트워크 게이트웨이, 클라이언트 단 등

한 줄 정리

용어 요약

WAF 웹 공격 막는 L7 보안 필터
Zero Trust "내부망도 믿지 마" 철학으로 모든 요청을 지속적으로 검증
반응형

'공부 > CS' 카테고리의 다른 글

HLS 프로토콜  (1) 2025.06.02
API Gateway  (0) 2025.03.24
워터마크 기술 개념  (0) 2025.03.03
아키텍처 간략 정리  (0) 2025.01.05
언어별 연산 속도  (0) 2024.12.30
반응형

volatile은 자바에서 멀티스레딩 환경에서 자주 사용되는 키워드로, 변수에 대한 가시성(visibility)을 보장해 주는 기능


volatile이란?

volatile 키워드는 변수 선언 앞에 붙여서 사용되며, 해당 변수가 여러 스레드에서 동시에 접근될 수 있음을 나타냅니다.


private volatile boolean running = true;

필요한 상황

자바에서 멀티스레딩을 할 때, 각 스레드는 자신만의 캐시에 변수 값을 저장할 수 있음

이때, 한 스레드가 변경한 값이 다른 스레드에 보이도록 캐시 업데이트 진행

예시:

class Example implements Runnable {
    private boolean running = true;

    public void run() {
        while (running) {
            // do something
        }
    }

    public void stop() {
        running = false;
    }
}

이 코드는 stop() 메서드에서 runningfalse로 바꾸더라도, run() 내부의 스레드는 true만 계속 보고 멈추지 않음


private volatile boolean running = true;

volatile의 효과

  1. 가시성 보장 (Visibility)
    • 어떤 스레드가 값을 바꾸면, 다른 모든 스레드는 그 변경을 즉시 볼 수 있습니다.
  2. 원자성은 보장하지 않음 (No Atomicity)
    • volatile읽기/쓰기 자체는 원자적이지만, 복합 연산(++, += 등)은 원자적이지 않아요.
    • 예: count++volatile로도 안전하지 않습니다.

volatile vs synchronized

특징 volatile synchronized
가시성 O O
원자성 X O
성능 빠름 상대적으로 느림 (락 걸림)
용도 단순 플래그, 읽기/쓰기 변수 복잡한 상태 공유, 연산 등

🔸 사용 예시

public class FlagExample {
    private volatile boolean flag = false;

    public void setFlagTrue() {
        flag = true;
    }

    public void waitForFlag() {
        while (!flag) {
            // 대기 중
        }
        System.out.println("Flag detected!");
    }
}

요약

  • volatile은 멀티 스레드 환경에서 변수 값의 변경이 다른 스레드에 보이지 않는 문제(가시성 문제)를 해결하기 위해 사용된다.
  • 일반적으로 CPU는 변수 값을 자신의 캐시에 저장하고 사용하기 때문에, 한 스레드에서 변경한 값이 다른 스레드의 캐시에 반영되지 않아 변경이 전파되지 않는 문제가 발생할 수 있다.
  • volatile 키워드를 사용하면, 변수의 값을 항상 메인 메모리에서 읽고 쓰게 되어 최신 값이 모든 스레드에 보이도록 보장할 수 있다.

  • Thread A는 여전히 true인 줄 알고 계속 루프를 돔
  • Thread B는 메모리에서 false로 바꿨지만, A는 캐시된 값을 사용 중

  • Thread B가 false로 바꾸면
  • Thread A도 즉시 최신 값을 보고 루프 종료
반응형
반응형

목적

API Gateway의 목적은 클라이언트와 백엔드 서비스 간의 중간 계층 역할을 하면서 다양한 기능들을 수행하여 시스템의 효율성과 보안성을 높이는 것

특징

1. 단일 진입점 제공 (Single Entry Point)

  • 클라이언트는 여러 백엔드 서비스를 직접 호출하지 않고, API Gateway 하나만 호출하면 됨.
  • 마이크로서비스 아키텍처에서 특히 유용.

2. 요청 라우팅 (Request Routing)

  • 들어오는 요청을 적절한 백엔드 서비스로 라우팅
  • 예: /user → 사용자 서비스, /order → 주문 서비스

3. 보안 관리

  • 인증(Authentication), 인가(Authorization)를 중앙에서 처리
  • JWT 토큰 검사, API 키 체크 등

4. 로깅 및 모니터링

  • 요청 로그를 수집하거나, 트래픽 분석 등 관측 기능을 제공
  • 성능 모니터링, 트래픽 제어 등도 가능

5. 요청/응답 변환

  • 요청 또는 응답의 포맷을 변환 (예: XML ↔ JSON)
  • 백엔드는 단순하게 유지하고, 클라이언트 맞춤 응답 제공 가능

6. 로드 밸런싱 및 장애 처리

  • 여러 백엔드 인스턴스 사이에서 트래픽 분산
  • 장애 발생 시 다른 인스턴스로 우회

7. 속도 제한 및 트래픽 제어 (Rate Limiting)

  • 남용 방지를 위해 호출 빈도 제한
  • 과도한 요청에 대한 보호

8. 캐싱

  • 빈번한 요청 결과를 캐싱하여 응답 속도 개선 및 서버 부하 감소.

API Gateway는 다음과 같은 역할을 하며 시스템을 더 안전하고, 효율적이며, 확장 가능하게 도움을 준다.

API Gateway의 부하 분산

1. API Gateway가 부하 병목이 될 수 있는 이유

  • 모든 요청을 한 곳(API Gateway)으로 집결시키므로, 트래픽 집중이 발생.
  • 트래픽이 급증하면, API Gateway가 요청을 처리하는 데 시간이 오래 걸릴 수 있음.

2. 부하를 분산시키는 방법

2.1 수평 확장(Scaling Out)

  • API Gateway 서버를 여러 대 운영하고, 그 앞단에 로드 밸런서(Load Balancer) 를 두어 부하를 분산
  • 예: Nginx, AWS ALB, Google Cloud Load Balancing 등

2.2 캐싱(Caching) 활용

  • 자주 요청되는 결과를 캐싱하면, Gateway가 각 요청마다 백엔드까지 직접 호출할 필요가 없어짐
  • 응답 속도 향상 및 서버 부하 감소

2.3 비동기 처리(Async)와 메시지 큐(Message Queue)

  • 어떤 요청은 즉시 처리가 필요하지 않을 수 있습니다(예: 이메일 전송, 비동기 트랜잭션 등)
  • 메시지 큐(Kafka, RabbitMQ 등)를 통해 처리할 수 있도록 하여 Gateway가 동기 처리 부담을 완화

2.4 서버리스(Serverless) 사용

  • AWS API Gateway + Lambda 조합 등으로 필요한 시점에만 자동 확장이 가능하도록 설계
  • 초당 수백만 건의 요청도 일정 수준까지는 감당하도록 구성 가능

2.5 API Gateway 경량화

  • Gateway 레이어에 지나치게 많은 기능(인증/인가, 변환, 로깅 등)을 몰아넣으면 부하가 커지기에 잘 고려해야함
  • 꼭 필요한 기능만 Gateway에서 처리하고, 나머지는 별도 마이크로서비스 혹은 다른 계층에서 담당하게 하여 Gateway의 역할을 경량화

3. 단일 장애 지점을 피하는 고가용성(HA) 구성

  • API Gateway가 멈추면 모든 서비스가 사실상 중단될 가능성이 있음
  • 따라서, 멀티 AZ(가용 영역), 멀티 리전 또는 다중 Gateway 인스턴스 구성을 통해 장애 발생 시에도 서비스 중단이 최소화되도록 하는 구성이 필요

4. 결론

  • API Gateway가 모든 트래픽의 단일 진입점으로 동작하므로, 제대로 설계하고 확장 전략을 마련하지 않으면 병목 및 장애 지점이 될 수 있다.
  • 하지만 수평 확장, 캐싱, 비동기 처리, 고가용성 구성 등을 통해 충분히 분산 설계가 가능함
  • 즉, 잘못 설계하면 병목이 되지만, 올바른 인프라/아키텍처 구성과 모니터링을 통해 API Gateway의 이점(중앙 집중 관리, 보안, 모니터링 등)을 극대화하면서도 부하 문제 완화가능
반응형

'공부 > CS' 카테고리의 다른 글

HLS 프로토콜  (1) 2025.06.02
WAF, ZTN  (1) 2025.04.27
워터마크 기술 개념  (0) 2025.03.03
아키텍처 간략 정리  (0) 2025.01.05
언어별 연산 속도  (0) 2024.12.30
반응형

워터마크(Watermark)란?

워터마크(Watermark)는 디지털 콘텐츠(이미지, 영상, 오디오, 문서 등)에 저작권 보호, 출처 표기, 위변조 방지 등의 목적으로 삽입되는 표식이다. 워터마크는 가시적(Visible)비가시적(Invisible) 방식으로 나뉜다.


1. 가시적 워터마크 (Visible Watermark)

  • 정의

이미지, 영상, 문서 등에 눈에 보이는 형태로 삽입된 워터마크를 의미한다.

  • 특징
    • 사람이 직접 볼 수 있음 (예: 로고, 텍스트, 투명한 마크)
    • 저작권 보호 및 출처 표시 목적
    • 복제 방지를 위한 억제 효과
    • 그러나 이미지 편집 기술(포토샵 등)로 제거 가능
  • 예시
    • 사진에 삽입된 "© 2025 PhotographerName" 표시
    • 영상의 한쪽 구석에 있는 방송국 로고 (예: "KBS", "MBC")
    • PDF 문서의 배경에 투명하게 삽입된 회사명

2. 비가시적 워터마크 (Invisible Watermark)

  • 정의

사람의 눈에는 보이지 않지만, 디지털 신호(이미지, 영상, 오디오, 문서)에 숨겨진 형태로 삽입된 워터마크를 의미한다.

  • 특징
    • 사람이 직접 볼 수 없음 (특정 소프트웨어나 알고리즘을 통해 확인 가능)
    • 저작권 보호 및 원본 출처 확인
    • 변형, 편집 후에도 검출 가능 (강인성에 따라 다름)
    • 이미지, 오디오, 영상에 널리 사용됨
  • 기술적 기법
    • 공간 영역 기법: 픽셀값에 미세한 변화 삽입
    • 주파수 영역 기법: 푸리에 변환(DFT), 웨이브렛 변환(DWT) 등을 활용해 삽입
    • 양자화 지수 변조(QIM): 특정 패턴을 신호에 삽입하여 탐지
  • 예시
    • 사진 속 특정 픽셀에 디지털 서명 숨기기
    • 영화나 음악 파일에 저작권 정보 삽입
    • 문서에 특정한 패턴을 추가해 출처 확인

3. 가시적 vs 비가시적 워터마크 비교

비교 항목 가시적 워터마크 비가시적 워터마크
눈으로 보이는지 O (보임) X (보이지 않음)
저작권 보호 효과 높음 (사람들이 인식) 높음 (탐지 필요)
위변조 방지 제거 가능성 높음 강인한 방식은 제거 어려움
출처 추적 육안으로 확인 가능 디지털 분석 필요
사용 예시 사진 로고, 방송국 마크, PDF 배경 디지털 인증, 영상·음원 추적

결론

  • 가시적 워터마크는 저작권 보호를 강조하고 쉽게 알아볼 수 있는 장점이 있지만 제거될 가능성이 있다.
  • 비가시적 워터마크는 콘텐츠의 무결성을 유지하면서도 추적이 가능하지만, 분석 도구가 필요하다.
  • 두 가지 방법을 함께 사용하면 보안성과 저작권 보호 효과를 극대화할 수 있다.
반응형

'공부 > CS' 카테고리의 다른 글

WAF, ZTN  (1) 2025.04.27
API Gateway  (0) 2025.03.24
아키텍처 간략 정리  (0) 2025.01.05
언어별 연산 속도  (0) 2024.12.30
Context Switching(문맥 교환)  (0) 2024.09.19
반응형

백준 감소하는 수(줄어드는 수)

https://www.acmicpc.net/problem/1174

https://www.acmicpc.net/problem/1038

접근 방식

최초엔 n까지 범위의 수를 생각했는데, 잘못 생각한 것이였고, 앞자리부터 점점 감소하는 수의 모든 경우의 수 중 몇번째인지 n으로 입력받아 찾는 문제


구현 방법

  • 감소하는 수에 대해 모든 조합을 찾은 후 정렬해 수행
  • 이 때 최대 수의 범위까지 1씩 더해가며 찾는 것이 아닌, 값이 들어갈 수 있는 범위에 대해서만 찾기

  • 9876543210 까지가 최대 수
  • 재귀에서 자릿수(depth)를 받아서 depth 범위만큼 foreach돈다.
  • 기본적으로 for문 돌 때 자기보다 낮은 수에 대해서만 수행
  • 재귀 안에서 count가 같으면 return - count는 static으로 갖고있기에 종료가능
  • for문이 다 돌면 재귀호출 시행

풀이

package Baekjoon.gold;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class p1174 {

    static Stack<Long> st = new Stack<>();
    static ArrayList<Long> al = new ArrayList<>();

    static int count = 0;
    static int n;
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        n = Integer.parseInt(br.readLine());

        /*
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9
         10 | 20, 21 | 30, 31, 32 | 40, 41, 42, 43 | 50, 51, 52, 53, 54 |
         60, 61, 62, 63, 64, 65 | 70, 71, 72, 73, 74, 75, 76 |
         80, 81, 82, 83, 84, 85, 86, 87 | 90, 91, 92, 93, 94, 95, 96, 97, 98 |
         210 |320, 321, 310 | 410, 420, 421, 430, 431, 432
         */

        //9 -> 8 7 6 5 4 3 2 1 0
        //8 -> 7 6 5 4 3 2 1 0
        //7 -> 6 5 4 3 2 1 0
        //6 -> 5 4 3 2 1 0
        //5 -> 4 3 2 1 0
        //4 -> 3 2 1 0
        //3 -> 2 1 0
        //2 -> 1 0
        //1 -> 0

        // 10 20 21 30 31 32
        //9876543210 까지가 최대 수
        //재귀에서 자릿수(depth)를 받아서 depth 범위만큼 foreach돈다.
        //기본적으로 for문 돌 때 자기보다 낮은 수에 대해서만 수행
        //재귀 안에서 count가 같으면 return - count는 static으로 갖고있기에 종료가능
        //for문이 다 돌면 재귀호출 시행

        if(n <= 10){
            System.out.println(n-1);
            return;
        }
        recur(10);
        List<Long> list = al.stream().sorted().collect(Collectors.toList());

        long result = -1;
        if(list.size() >= n){
            result = list.get(n-1);
        }

        System.out.println(result);
    }

    private static void recur(long nowNum){
        for(long i = 0; i < nowNum; i++){
            count++;
            st.push(i);
            st.forEach(sb::append);
            al.add(Long.valueOf(sb.toString()));
            sb.setLength(0);
            recur(i);
            st.pop();
        }
    }
}

후기

최초에 문제를 잘못 읽었고, 이후엔 전체 탐색을 효율적으로 하기위한 노력(가지치기)을 하는 데 시간을 많이 썼음

반응형

+ Recent posts