기본 콘텐츠로 건너뛰기

동기 외부 API 호출이 느려질 때 서버 장애로 번지지 않게 막는 방법

동기 외부 API 호출이 느려질 때 서버 장애로 번지지 않게 막는 방법

빠른 답

  • 동기 외부 호출은 connection timeout, read timeout, connection pool wait timeout을 나눠 설정해야 합니다.
  • 외부 서비스 여러 개가 같은 HTTP 커넥션 풀을 공유하면, 한 서비스의 지연이 다른 연동까지 막을 수 있습니다.
  • 서비스별 커넥션 풀, 동시 실행량 제한, 서킷 브레이커를 함께 두면 장애 전파 범위를 줄일 수 있습니다.
  • fallback은 실패를 숨기는 장치가 아니라, 실패를 기록하면서 사용자 흐름을 어디까지 유지할지 정하는 정책입니다.

시간 흐름으로 이해하기

장애 시작
외부 API A의 응답 시간이 길어지고, 내부 요청 스레드가 응답을 기다립니다.
호출 누적
사용자 요청은 계속 들어오고, A를 호출하는 요청이 커넥션과 스레드를 오래 점유합니다.
대기 확산
커넥션 풀의 사용 가능한 연결이 줄어들고, 새 요청은 외부 API로 나가기 전부터 풀 앞에서 기다립니다.
내부 영향
timeout, 벌크헤드, 서킷 브레이커가 없으면 A의 지연이 내부 API 전체 응답 시간과 실패율로 번집니다.
보호 동작
실패율이나 느린 호출 비율이 기준을 넘으면 서킷 브레이커가 호출을 잠시 막고 빠른 실패나 fallback으로 전환합니다.

선택 기준 매트릭스

외부 API가 가끔 느려지는 상황
타임아웃을 먼저 설정합니다. 요청이 끝없이 대기하지 않도록 서버 자원 점유 시간을 제한할 수 있습니다.
특정 외부 서비스 장애가 다른 연동까지 밀어내는 상황: 외부 서비스별 커넥션 풀을 분리합니다. 한 풀의 고갈이 전체 외부 호출 장애로 번지는 범위를 줄입니다.
같은 애플리케이션 안에 중요한 기능과 부가 기능이 섞인 상황: 벌크헤드 패턴을 적용합니다. 기능별 동시 실행량을 나눠 일부 기능의 지연을 격리합니다.
외부 API 장애가 몇 분 이상 이어지는 상황: 서킷 브레이커를 사용합니다. 실패가 반복될 때 매번 timeout까지 기다리지 않고 빠르게 실패시킵니다.
재시도를 넣어야 하는 상황
짧은 타임아웃, 제한된 재시도 횟수, 지수 백오프, jitter를 함께 둡니다. 재시도만 늘리면 장애 중 호출량이 더 커질 수 있습니다.
fallback을 줄 수 있는 조건
캐시, 기본값, 빈 결과, 지연 처리 큐 중 비즈니스 의미가 깨지지 않는 선택지를 사용합니다.

외부 API 지연이 내부 장애로 번지는 이유

동기 방식의 외부 API 호출은 내부 서버가 외부 서비스의 응답을 받은 뒤 다음 처리를 이어가는 구조입니다. 흐름이 단순하고 결과를 다루기 쉽지만, 외부 서비스가 느려질 때 내부 서버의 스레드, 커넥션, 메모리도 함께 오래 묶입니다.

예를 들어 주문 API가 결제 승인 API를 동기 호출한다고 가정해 보겠습니다. 결제사가 100ms 안에 응답할 때는 문제가 잘 보이지 않습니다. 그런데 결제사 응답이 5초, 10초로 늘어나면 주문 서버는 그 시간 동안 요청 처리를 끝내지 못합니다. 사용자는 응답을 기다리고, 애플리케이션 스레드는 반환되지 않으며, HTTP 커넥션 풀도 점점 비어갑니다.

이때 장애는 외부 API 하나에서 시작했지만 내부 서버에서는 다음 신호로 관찰됩니다.

  • 특정 API의 p95, p99 응답 시간이 증가합니다.
  • WAS 또는 애플리케이션 서버의 활성 스레드 수가 증가합니다.
  • 외부 API 커넥션 풀의 active, pending 값이 증가합니다.
  • 정상인 다른 외부 서비스 호출까지 지연됩니다.
  • 게이트웨이나 애플리케이션에서 504, 503, 500 응답이 늘어납니다.

동기 호출에서는 기다리는 행위 자체가 내부 서버의 자원을 점유합니다. 그래서 외부 장애를 내부 장애로 만들지 않으려면 “얼마나 기다릴지”, “어떤 기능이 어떤 자원을 쓸 수 있는지”, “계속 실패할 때 호출을 멈출지”를 미리 정해 두어야 합니다.

동기 호출 흐름과 대기 지점

외부 API 호출은 단순히 요청을 보내는 한 줄의 코드처럼 보이지만, 운영 환경에서는 여러 대기 지점을 지나갑니다. 각각의 대기 지점을 구분해야 장애가 연결 문제인지, 외부 서버 처리 지연인지, 내부 풀 고갈인지 나눠 볼 수 있습니다.

일반적인 요청 흐름은 다음 순서로 이어집니다.

  • 요청 유입: 사용자 요청이 게이트웨이, 로드 밸런서, 애플리케이션 서버로 들어옵니다.
  • 게이트웨이 또는 프록시: 요청 제한, 라우팅, 전체 요청 타임아웃이 적용될 수 있습니다.
  • 애플리케이션 처리: 비즈니스 로직이 실행되고 외부 API 호출 코드에 도달합니다.
  • 외부 서비스 대기: HTTP 연결 획득, TCP 연결, 응답 읽기 중 하나 이상의 구간에서 대기합니다.
  • 모니터링과 응답: 성공, 실패, timeout, fallback 여부가 로그와 메트릭으로 남습니다.

외부 API 호출에서 특히 중요한 대기 지점은 세 곳입니다. 첫째, 외부 서버와 연결을 맺는 시간입니다. 둘째, 연결을 맺은 뒤 응답 데이터를 읽는 시간입니다. 셋째, 내부 커넥션 풀에서 사용할 연결을 빌릴 때까지 기다리는 시간입니다.

이 셋은 서로 다른 문제를 가리킵니다. 연결 자체가 안 되는 문제인지, 연결은 됐지만 외부 서버가 응답을 늦게 주는 문제인지, 아니면 우리 애플리케이션의 커넥션 풀이 이미 고갈된 문제인지가 다릅니다. 운영 중에는 이 구분이 점검 순서의 출발점이 됩니다.

타임아웃 3가지를 나눠 설정하기

동기 외부 API 호출에서 타임아웃은 하나만 두면 부족합니다. connection timeout, read timeout, connection pool wait timeout은 서로 다른 구간을 제한합니다.

connection timeout은 외부 서버와 네트워크 연결을 맺는 데 허용할 시간입니다. DNS, 라우팅, 방화벽, 외부 서버 포트 문제 등이 있으면 이 구간에서 실패할 수 있습니다.

read timeout은 연결을 맺은 뒤 응답 데이터를 기다리는 시간입니다. 외부 서버가 요청을 받았지만 내부 처리 지연, DB 병목, 장애 등으로 응답을 늦게 주면 이 타임아웃에 걸립니다.

connection pool wait timeout은 내부 애플리케이션이 커넥션 풀에서 연결을 빌릴 때까지 기다리는 시간입니다. 외부 API 응답이 느려져 기존 커넥션이 오래 반환되지 않으면 새 요청은 외부 서비스로 나가기 전부터 풀 앞에서 대기합니다.

아래는 외부 서비스별로 타임아웃과 풀 크기를 분리한 설정 예시입니다. 실제 값은 트래픽, 외부 API SLA, 게이트웨이 timeout, 사용자 요청 허용 시간을 함께 놓고 조정해야 합니다.

external-api:
  payment:
    base-url: "https://payment.example.com"
    connect-timeout-ms: 500
    read-timeout-ms: 1500
    pool-wait-timeout-ms: 200
    max-connections: 50

  shipping:
    base-url: "https://shipping.example.com"
    connect-timeout-ms: 500
    read-timeout-ms: 1000
    pool-wait-timeout-ms: 200
    max-connections: 30

게이트웨이 timeout과 애플리케이션 내부 timeout도 함께 맞아야 합니다. 게이트웨이 timeout이 3초인데 내부 외부 API read timeout이 5초라면, 사용자는 이미 실패 응답을 받았는데 애플리케이션은 뒤늦게 외부 응답을 기다리는 상황이 생길 수 있습니다.

커넥션 풀 분리와 벌크헤드

여러 외부 서비스를 하나의 HTTP 커넥션 풀로 묶는 구성은 처음에는 간단합니다. 하지만 결제 API가 느려져 커넥션을 오래 붙잡으면, 배송 API나 알림 API 호출도 같은 풀에서 커넥션을 빌리지 못해 지연될 수 있습니다.

벌크헤드 패턴은 자원을 나누어 일부 장애가 전체로 번지지 않게 하는 방식입니다. 서버 애플리케이션에서는 외부 서비스별 커넥션 풀, 스레드 풀, 동시 실행량 제한으로 구현할 수 있습니다. 중요한 점은 “풀을 많이 만든다”가 아니라 “장애가 난 외부 서비스가 사용할 수 있는 자원의 경계를 둔다”는 데 있습니다.

아래 코드는 외부 서비스별 HTTP 클라이언트를 분리한다는 의도를 보여주는 예시입니다. 사용하는 HTTP 클라이언트 라이브러리에 따라 속성 이름은 달라질 수 있지만, 결제와 배송이 같은 풀을 공유하지 않도록 구성하는 방향은 같습니다.

public final class ExternalApiClients {
    public CloseableHttpClient paymentClient() {
        PoolingHttpClientConnectionManager manager =
            new PoolingHttpClientConnectionManager();

        manager.setMaxTotal(50);
        manager.setDefaultMaxPerRoute(50);

        RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(Timeout.ofMilliseconds(500))
            .setResponseTimeout(Timeout.ofMilliseconds(1500))
            .setConnectionRequestTimeout(Timeout.ofMilliseconds(200))
            .build();

        return HttpClients.custom()
            .setConnectionManager(manager)
            .setDefaultRequestConfig(config)
            .build();
    }

    public CloseableHttpClient shippingClient() {
        PoolingHttpClientConnectionManager manager =
            new PoolingHttpClientConnectionManager();

        manager.setMaxTotal(30);
        manager.setDefaultMaxPerRoute(30);

        RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(Timeout.ofMilliseconds(500))
            .setResponseTimeout(Timeout.ofMilliseconds(1000))
            .setConnectionRequestTimeout(Timeout.ofMilliseconds(200))
            .build();

        return HttpClients.custom()
            .setConnectionManager(manager)
            .setDefaultRequestConfig(config)
            .build();
    }
}

커넥션 풀을 분리했다면 메트릭도 함께 분리해야 합니다. external.payment.latency, external.payment.timeout, external.shipping.latency, external.shipping.pool.pending처럼 서비스별 지연 시간과 실패율을 따로 봐야 장애가 어디에서 시작됐는지 확인할 수 있습니다.

서킷 브레이커와 fallback 설계

타임아웃은 오래 기다리는 문제를 줄여 주지만, 외부 API가 계속 실패하는 상황에서는 매 요청마다 timeout까지 기다리는 것 자체가 비용이 됩니다. 서킷 브레이커는 실패율이나 느린 호출 비율이 기준을 넘으면 일정 시간 호출을 막고 빠르게 실패하도록 돕습니다.

서킷 브레이커에는 보통 세 가지 상태가 있습니다. closed는 평소처럼 호출하는 상태입니다. open은 실패가 많아 호출을 막는 상태입니다. half-open은 일정 시간이 지난 뒤 일부 호출만 통과시켜 회복 여부를 확인하는 상태입니다.

다음은 결제 API에 적용할 수 있는 설정 예시입니다. 최근 20개 호출 중 최소 10개 이상이 집계된 상태에서 실패율이 50%를 넘거나, 1.5초 이상 걸린 느린 호출 비율이 50%를 넘으면 회로를 열도록 잡았습니다.

resilience4j:
  circuitbreaker:
    instances:
      paymentApi:
        sliding-window-size: 20
        minimum-number-of-calls: 10
        failure-rate-threshold: 50
        slow-call-duration-threshold: 1500ms
        slow-call-rate-threshold: 50
        wait-duration-in-open-state: 10s
        permitted-number-of-calls-in-half-open-state: 3

서킷 브레이커는 fallback과 함께 설계해야 의미가 분명해집니다. 결제 승인처럼 정확성이 중요한 기능은 빠르게 실패시키고 사용자 재시도나 내부 보상 흐름으로 넘길 수 있습니다. 추천 상품, 부가 배너, 읽기 전용 통계처럼 핵심 흐름이 아닌 기능은 캐시된 값, 빈 목록, 기본값으로 사용자 흐름을 유지할 수 있습니다.

다만 fallback이 실패를 감추는 방식으로만 동작하면 운영자는 장애를 늦게 알아차립니다. fallback 응답을 주더라도 로그, 메트릭, 알림에서는 외부 API 실패와 서킷 상태가 분명히 보여야 합니다.

동시 실행량 제한 예시

외부 API별 커넥션 풀을 분리해도 애플리케이션 내부에서 너무 많은 동시 요청이 몰리면 자원 압박은 계속될 수 있습니다. 이때는 커넥션 풀과 별도로 동시 실행량 제한을 둘 수 있습니다.

아래 예시는 결제 API 호출을 최대 30개까지만 동시에 허용합니다. 제한을 넘으면 오래 줄 세우지 않고 빠르게 실패시켜 내부 서버의 대기열이 커지는 것을 막습니다.

public class PaymentApiCaller {
    private final Semaphore bulkhead = new Semaphore(30);
    private final HttpClient client;

    public PaymentApiCaller(HttpClient client) {
        this.client = client;
    }

    public String approve(String orderId) throws Exception {
        if (!bulkhead.tryAcquire(100, TimeUnit.MILLISECONDS)) {
            throw new IllegalStateException("payment api bulkhead full");
        }

        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://payment.example.com/approvals/" + orderId))
                .timeout(Duration.ofMillis(1500))
                .GET()
                .build();

            return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
        } finally {
            bulkhead.release();
        }
    }
}

이 제한은 일부 요청을 빠르게 실패시킬 수 있습니다. 하지만 모든 요청이 내부 서버에서 오래 대기하다가 전체 장애로 번지는 것보다, 자원 사용 상한을 두고 나머지 요청의 회복 가능성을 남기는 편이 운영 관점에서는 다루기 쉽습니다.

재시도도 같은 기준으로 봐야 합니다. read timeout이 1.5초이고 재시도를 3번 허용하면, 한 요청이 외부 API 응답을 기다리는 시간은 최대 4.5초 이상이 될 수 있습니다. 게이트웨이 timeout, 사용자 요청 timeout, 내부 스레드 점유 시간을 합쳐 계산하지 않으면 재시도 정책이 장애를 키울 수 있습니다.

디버깅과 운영 점검 순서

외부 API 지연이 의심될 때는 먼저 대기 지점을 나눠 보는 편이 좋습니다. 연결이 느린지, 응답 읽기가 느린지, 풀 대기가 긴지에 따라 조치가 달라집니다.

애플리케이션 로그는 외부 서비스 이름, timeout 종류, 소요 시간, 커넥션 풀 상태를 함께 남기는 편이 분석에 유리합니다.

2026-04-13T10:15:21.342+09:00 WARN  order-api
event=external_api_timeout
service=payment
timeout_type=read_timeout
elapsed_ms=1503
connect_timeout_ms=500
read_timeout_ms=1500
pool_wait_timeout_ms=200
pool_active=50
pool_idle=0
pool_pending=37
path=/orders
request_id=req-8f21a

이 로그에서는 연결 실패가 아니라 read_timeout이 발생했습니다. 동시에 pool_active=50, pool_idle=0, pool_pending=37이므로 결제 API 커넥션 풀이 꽉 차 있고 뒤에 기다리는 요청도 있다는 뜻입니다. 이 경우 외부 결제 API 지연이 내부 서버의 대기열로 번지고 있다고 해석할 수 있습니다.

운영 점검은 보통 다음 순서로 진행하면 원인을 좁히기 쉽습니다.

  • 게이트웨이에서 특정 경로의 응답 시간과 5xx, 504, 499 증가 여부를 확인합니다.
  • 애플리케이션에서 외부 서비스별 latency, timeout count, circuit breaker state를 확인합니다.
  • 커넥션 풀의 active, idle, pending 값을 봅니다.
  • 스레드 풀 또는 이벤트 루프가 고갈되고 있는지 확인합니다.
  • 외부 API 제공자 상태 페이지, 네트워크 지표, DNS 오류 로그를 확인합니다.
  • 최근 배포에서 timeout, pool size, retry 설정이 바뀌었는지 확인합니다.

명령 출력도 함께 남겨 두면 장애 공유가 쉬워집니다. 예를 들어 특정 API가 게이트웨이 앞단에서 이미 오래 걸리고 있는지 다음처럼 확인할 수 있습니다.

$ curl -s -o /dev/null -w "status=%{http_code} connect=%{time_connect}s starttransfer=%{time_starttransfer}s total=%{time_total}s\n" \
  https://api.example.com/orders/1001

status=504 connect=0.018s starttransfer=3.002s total=3.004s

이 출력은 TCP 연결은 0.018초로 빠르게 맺어졌지만, 첫 응답 바이트가 오기까지 약 3초가 걸렸고 결국 504가 반환된 상황을 보여줍니다. 연결 자체보다 뒤쪽 처리나 외부 호출 대기가 문제일 가능성이 큽니다.

배포와 운영 체크리스트

외부 API 장애 전파를 막는 설정은 코드에만 넣고 끝나지 않습니다. 배포 전후에 운영 환경의 timeout 계층이 서로 맞는지 확인해야 합니다. 게이트웨이, 애플리케이션, HTTP 클라이언트, 외부 API 제공자의 timeout이 충돌하면 의도와 다른 실패가 발생합니다.

배포 전에는 다음 항목을 확인합니다.

  • 외부 서비스별 HTTP 클라이언트와 커넥션 풀이 분리되어 있는지 확인합니다.
  • connection timeout, read timeout, connection pool wait timeout이 모두 명시되어 있는지 확인합니다.
  • 내부 API의 전체 timeout보다 외부 API 호출 timeout과 재시도 총합이 짧은지 계산합니다.
  • 재시도 횟수, 백오프, jitter, 재시도 가능한 오류 조건이 정의되어 있는지 확인합니다.
  • 서킷 브레이커의 실패율, 느린 호출 기준, open 유지 시간이 서비스 특성에 맞는지 확인합니다.
  • fallback 응답이 비즈니스 의미를 깨뜨리지 않는지 확인합니다.
  • 외부 서비스별 메트릭과 알림이 분리되어 있는지 확인합니다.

배포 후에는 정상 트래픽에서 기준선을 잡아야 합니다. 평소 p95, p99 응답 시간, timeout 비율, 커넥션 풀 pending 값을 알아야 장애 때 이상 징후를 빨리 볼 수 있습니다. 기준선 없이 알림 임계값만 정하면 너무 늦게 울리거나 너무 자주 울릴 수 있습니다.

장애 훈련도 도움이 됩니다. 스테이징 환경에서 특정 외부 API 응답을 2초 지연시키거나 50% 실패시키는 식으로 테스트하면 timeout과 서킷 브레이커가 의도대로 동작하는지 확인할 수 있습니다. 이때 사용자 API 전체가 몇 초 안에 실패하는지, 정상 외부 API 호출도 함께 느려지는지, 알림이 어느 시점에 울리는지를 같이 봐야 합니다.

흔한 오해와 주의할 점

timeout 값을 길게 잡으면 안정적이라고 생각하기 쉽습니다. timeout이 길면 일시적인 느림을 더 기다릴 수는 있지만, 장애 상황에서는 내부 자원을 더 오래 붙잡습니다. 사용자 요청의 전체 허용 시간과 서버 자원 점유 시간을 함께 봐야 합니다.

커넥션 풀 크기를 키우는 것만으로는 문제가 해결되지 않는 경우도 많습니다. 풀을 키우면 순간 처리량은 늘 수 있지만, 외부 서비스가 느린 상태에서는 더 많은 요청이 외부 장애에 매달리게 됩니다. 풀 크기 증가는 동시 실행량 제한, timeout, 서킷 브레이커와 함께 검토해야 합니다.

재시도는 짧은 네트워크 흔들림에는 도움이 될 수 있습니다. 그러나 외부 서비스가 이미 과부하인 상태에서 모든 서버가 동시에 재시도하면 호출량이 더 늘어 장애가 길어질 수 있습니다. 재시도에는 최대 횟수, 백오프, jitter, 재시도 가능한 오류 조건이 필요합니다.

fallback은 비즈니스 의미를 기준으로 나눠야 합니다. 결제 승인 실패를 성공처럼 처리할 수는 없습니다. 반대로 추천 상품이나 부가 배너처럼 핵심 흐름이 아닌 기능은 빈 결과나 캐시 응답으로도 사용자 흐름을 유지할 수 있습니다. 외부 API마다 실패 시 허용 가능한 응답을 분리해 두면 장애 상황에서 판단할 일이 줄어듭니다.

원문 참고

https://www.maeil-mail.kr/question/74

댓글

이 블로그의 인기 게시물

아이콘 폰트 (icomoon 사용법)

 장난감 프로젝트를 만들다 보면, 아이콘이 필요한 경우가 있다. 간단하게 아이콘을 인터넷에서 검색하여, 이미지로 넣어두고 이미지 태그를 이용하여, 사용하는 경우가 일반적이였지만...  요즘에는 대부분 폰트를 이용하여 아이콘을 노출 한다. 나 같은 경우에도 기본적으로  https://material.io/resources/icons 를 참고하여 아이콘 폰트를 이용할 수 있도록 처리하고, 추가적으로 필요한 아이콘이고, 일상적으로 사용 되지 않는 아이콘의 경우에는  https://icomoon.io 에서 제작하여, 아이콘 폰트로 이용 하곤 한다.  그래서 이번에는 아이콘  https://icomoon.io 의 사용법을 간단히 공유하고자 한다.   들어가자 마자 위의 icoMoonApp버튼을 누르면 아래와 같은 화면이 나타난다.  icomoon에서 무료로 제공하는 아이콘들이 보이면 위에 파란색으로 표시 되어있는 집 모양 세가지를 선택한 후, 아래의 빨간색으로 표시되어있는 Generate Font를 눌러보자.  그리고 나서 바로 다운로드를 요청해보자. icomoon.zip이 다운로드가 될텐데, 압축을 해제해 보면, 아래의 폴더 및 파일들이 있다. 아래에서 중요한 것은 font 폴더와 style.css이다. demo-files fonts demo.html Read Me.txt selection.json style.css <!doctype html > <html> <head> <link rel ="stylesheet" href ="style.css" ></head> </head> <body> <span class ="icon-home" ></span> <span class ="icon-home2" ></span> <span class ="icon-hom...

Chart js와 amchart 비교

Chart js 특징은 위의 그림으로 대체 할 수 있을 듯 하다. 오픈 소스이고, 기본으로 제공하는 차트 종류가 8가지 Canv a s를 이용해서 차트를 그리고, 반응형을 지원한다. amchart amchart는 기본적으로 유료이며, 기본으로 제공하는 차트 종류가 기본적인 차트 + 주식 처럼 보이는 차트 + 지도에 관련된 차트(?) 까지 하면, 기본 제공 하는 종류가 20개 내외 이려나, 일일이 세기에는 양이 좀 많아 보인다. 렌더링은 svg를 통하여 그려지고, 당연 반응형도 지원이 된다. 그러면, 이 둘중에 어떤것이 내 프로젝트에 적합 하냐는 것이 문제이다. 일단, 주식 처럼 보이는 차트나 지도에 관련된 차트(?)가 필요하면, amchart를 선택해야 되는 것은 맞다. 그건 당연한 것이니 빼고 얘기 해보자! 여러 종류의 차트가 필요하다면, 일단은 amchart를 염두해 두는 것이 좋다. 돈 낸 만큼은 하는 듯 하다. 하지만, 기본적인 막대 그래프, 도넛 차트 등, 아주 기본적인 차트들인데, Chart js도 amchart도 그러한 차트가 없을 때가 문제가 된다. 그렇다면, 조금이라도 커스텀이 용이한 것을 찾는 것이 좋을 것이다.  일단 amchart에서 custom이라고 검색 하였을 때, 검색 결과가 61가지가 나온다. 차트의 종류도 많고, 각 차트마다 들어가는 속성이 매우 많기 때문에, 웬만한 내용들은 속성 값을 어떻게 주느냐에 따라서 변경이 가능 하게 된다. 커스텀의 예를 들면, 기본적으로 도넛 파이의 형태를 띄면서, 화살표로 목표를 표시해주는 차트가 필요하다고 생각 해보자. 이것은 amchart로 만든 그래프이고 이것은 chart js로 만든 그래프이다. 모양이 살짝 다르긴 하지만, 완벽하게 똑같이 구현 할 수도 있다. amchart로 만든 그래프의 경우, 저것은 도넛그래프가 아닌 guage 그래프이다. 원래 게이지 그래프는 이와 같...

javascript 압축 파일 다운로드

이번에는 전 게시글의 응용판? 이라고 해야하나....? 어쨋든! 우리는 각각의 파일들을 다운로드 해보았다. 그런데 생각보다 귀찮음?을 느꼇을 것이다. 파일을 각각 다운 받아야 한다는 현실때문에! 그래 파일 두개야 뭐 그렇다 치지... 하지만, 개발자도 사용자도 게으름뱅이이다. 자 결국, 우리가 해야 하는 것은 파일을 한 번에 둘다! 다운 받는 것이다. 물론, 클릭 한번에 여러개의 함수를 엮어서 다운받게 하면 되지만! 크롬에서 자주 봤듯이, 여러개의 파일을 다운로드를 시도하면 <- 여러개의 파일을 다운로드 합니다. 허용 합니까? 하고 물어보는 것을 볼 수 있다. 게다가 다운로드 한 파일들을 찾기도 귀찮다는 것. 자 해결책을 제시해보자면, https://github.com/Stuk/jszip 클라이언트 단에서 파일을 zip파일로 압축을 할 수가 있다! 필요한 작업은 아래와 같다. 0. 데이터 준비 1. BLOB(binary large object)를 만든다. 2. Blob을 URL.createObjectURL을 사용하여, 해당 binary의 주소를 생성. 3. 다운로드가 필요한 파일들을 Zip 객체에 셋팅! 4. a태그를 이용하여, 해당 url 셋팅 하고, 다운로드. 전 게시물과 별로 달라진게 없네... 자 그럼 샘플! 샘플을 보자! http://embed.plnkr.co/NMprnRxqYG0fkHa2J55D/ var util = {} function fixBinary(bin) { //binary to arrayBuffer var length = bin.length var buf = new ArrayBuffer(length) var arr = new Uint8Array(buf) for (var i = 0; i < length; i++) { arr[i] = bin.charCodeAt(i) } return buf } window.onload = function() { ...