반응형

발생 현상

  • AUIGrid(자바스크립트 라이브러리)를 사용하는 엑셀 다운로드 시 깨진 파일을 다운받음
  • 그러나 백엔드 서버에서 해당 파일을 저장해둔 위치에 가서 파일을 열어보면 정상적으로 열리는 상태
  • 다운로드 받은 파일(깨진 파일)과 정상 파일을 메모장으로 열어서 데이터 비교했을 때 파일이 쓰이다 만 것처럼 데이터가 들어가 있음(깨진 파일은 데이터가 중간에 끊김)

발생 원인

  • 파일이 중간에 깨진 이유는 디스크 쓰기 작업이 완료(flush)되기 전에 파일을 반환했기 때문에 발생
  • 백엔드 서버의 로직을 봤을 때 해당 코드는 동기적으로 처리되어야 정상인데 왜 문제가 발생했는가?
    • AIP 서버에서 파일 데이터를 수신하면, 해당 데이터는 먼저 메모리에 존재하는 파일 스트림에 저장됨. 이 시점에서 쉘 스크립트는 파일 쓰기 작업이 완료된 것으로 간주(php 코드도 동일)하고, 바로 다음 단계로 넘어간다. 하지만 파일 스트림의 내용이 실제 디스크에 완전히 flush되기 전에 프론트에서 해당 파일을 다운로드받아 문제가 생기고 있었음
  • 엑셀 다운로드 흐름

해결 방안

  • 3초 딜레이 적용
    • AUIGrid에서 사용하는 백엔드 호출 로직(DrmService.php)에 sleep(3)을 추가하여 디스크 flush가 완료되도록 유도
  • 쉘 스크립트 내에서 파일 디스크 flush 유도
    • mv 명령어 사용 시 OS 스케줄러의 디스크 flush를 유도하는 커널 레벨 특성을 이용
    • 반환받은 파일 데이터를 .tmp 확장자로 저장한 후, mv file.xlsx.tmp file.xlsl 방식으로 이름 변경 처리
    • 이 과정을 통해 flush가 완료된 시점에만 최종 파일로 접근 가능하게 만듦
  • python flush() 시스템콜 직접 호출
    • 아래의 파이썬 호출 코드를 쉘 스크립트 에서 실행 python3 -c "f = open('${ORIGINAL_PATH}', 'rb+'); import os; os.fsync(f.fileno()); f.close()"

고려 사항

  • 해당 문제는 운영 환경에서만 발생하며, 개발 환경에서는 재현되지 않기 때문에 정확한 원인 분석이 제한적
  • 운영 서버에서 직접 코드를 수정하거나 임시 로직을 삽입해 테스트할 필요가 있음
  • 백엔드에서 생성하는 다른 엑셀 암호화 파일들도 같은 문제의 가능성이 존재
    • 다만, 해당 로직은 후처리 과정이 존재하기 때문에 자연스러운 딜레이가 발생해 flush가 완료되고, 문제 없이 다운로드가 가능했던 것으로 보임. 따라서 AIP 암호화 처리시 반드시 호출하는 쉘 스크립트 내에서 해결하는 것이 Best

요약

반응형
반응형

목적

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' 카테고리의 다른 글

워터마크 기술 개념  (0) 2025.03.03
아키텍처 간략 정리  (0) 2025.01.05
언어별 연산 속도  (0) 2024.12.30
Context Switching(문맥 교환)  (0) 2024.09.19
해시 - 솔트치기  (0) 2024.08.25
반응형

백준 포도주 시식

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

접근 방식

조건 : 연속으로 놓여 있는 3잔을 모두 마실 수는 없음

최초에 값을 초기화할 때 앞의 2개의 잔을 모두 마실 필요가 있나? x

마셨을 때 : 1

마시지 않았을 때 0

기준으로 표현하자면,

경우의 수는 110, 101, 011로 좁혀지고, 010은 고려대상이 아님


구현 방법

  • DP배열에서 위 접근방식을 적용하면 해결됨

  • 바텀업으로 값을 채워나감
  • 최초 값은 index 2까지 초기화
    • 0 : 1
    • 1 : 11
    • 2 : 101, 110, 011
  • 이후 점화식을 코드로 구현
    • i index 기준으로 봤을 때 각 경우의 수는 아래와 같이 표현됨
    • 110 : dp[i-1]
    • 101 : dp[i-2] + arr[i]
    • 011 : dp[i-3] + arr[i-1] + arr[i]

풀이

import java.io.*;
import java.util.*;

public class p2156 {
    static int[] arr;
    static int[] dp;

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

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

        arr = new int[n];
        dp = new int[n];

        for(int i = 0; i < n; i++){
            arr[i] = Integer.parseInt(br.readLine());
        }

        if(n == 1){
            System.out.println(arr[0]);
            return;
        }

        if(n == 2){
            System.out.println(arr[0] + arr[1]);
            return;
        }

        dp[0] = arr[0];
        dp[1] = arr[0] + arr[1];
        dp[2] = Integer.max(dp[1],
                Integer.max(dp[0] + arr[2], // 101
                        arr[1] + arr[2])); // 011

        for(int i = 3; i < n; i++){
            dp[i] = Integer.max(dp[i-1], // 110
                    Integer.max(dp[i-2] + arr[i], // 101
                            dp[i-3] + arr[i-1] + arr[i])); // 011
        }

        System.out.println(dp[n-1]);
    }
}


후기

점화식을 세워서 진행하는 바텀업 DP 문제는 경우의 수를 어떻게 잘 구현 해야할지 머릿속에서 잘 구상해야하는데 이게 아직도 어려운 것 같다.

반응형

+ Recent posts