내보내기(0) 인쇄
모두 확장
이 항목은 아직 평가되지 않았습니다.- 이 항목 평가

Service Bus 조정된 메시징을 사용한 성능 개선 모범 사례

업데이트 날짜: 2014년 4월

이 항목에서는 Windows Azure 서비스 버스를 사용하여 조정된 메시지를 교환할 때 성능을 최적화하는 방법을 설명합니다. 이 항목의 전반부에서는 성능을 개선하기 위해 제공되는 다양한 메커니즘에 대해 설명하고, 후반부에서는 지정된 시나리오에서 최상의 성능을 제공할 수 있는 방식으로 Service Bus를 사용하는 방법에 대한 지침을 제공합니다.

이 항목 전체에서 "클라이언트"라는 용어는 Service Bus에 액세스하는 엔터티를 지칭합니다. 클라이언트는 발신자 또는 수신자 역할을 할 수 있습니다. "발신자"라는 용어는 Service Bus 큐 또는 항목으로 메시지를 보내는 Service Bus 큐 또는 항목 클라이언트에 사용됩니다. "수신자"라는 용어는 Service Bus 큐 또는 구독에서 메시지를 받는 Service Bus 큐 또는 구독 클라이언트를 지칭합니다.

메커니즘

이 섹션에서는 Service Bus에서 성능을 높이기 위해 적용하는 다양한 개념을 소개합니다.

프로토콜

Service Bus에서는 클라이언트가 두 가지 프로토콜, 즉 Service Bus 클라이언트 프로토콜과 HTTP를 사용하여 메시지를 보내고 받을 수 있습니다. Service Bus 클라이언트 프로토콜은 메시지 팩터리가 있으면 Service Bus 서비스에 대한 연결을 유지하므로 더욱 효율적입니다. 또한 이 프로토콜은 일괄 처리 및 프리페치도 구현합니다. .NET 관리되는 API를 사용하는 .NET 응용 프로그램에서 Service Bus 클라이언트 프로토콜을 사용할 수 있습니다.

명시적으로 언급되지 않는 한 이 항목의 모든 내용은 Service Bus 클라이언트 프로토콜을 사용하는 것으로 가정합니다.

팩터리 및 클라이언트 다시 사용

Service Bus 클라이언트 개체(예: QueueClient 또는 MessageSender)는 MessagingFactory 개체(연결의 내부 관리를 제공하기도 함)를 통해 만들어집니다. 메시지를 보낸 후 메시징 팩터리 또는 큐, 항목 및 구독 클라이언트를 닫았다가 다음 메시지를 보낼 때 다시 만들어서는 안 됩니다. 메시징 팩터리를 닫으면 Service Bus 서비스에 대한 연결이 삭제되고, 팩터리를 다시 만들면 새 연결이 설정됩니다. 연결 설정 작업에는 비용이 많이 소요되므로 여러 작업에 같은 팩터리 및 클라이언트 개체를 다시 사용하면 이러한 작업을 반복해서 수행하지 않아도 됩니다.

동시 작업

보내기, 받기, 삭제 등의 작업을 수행하려면 시간이 걸립니다. 이 시간에는 Service Bus 서비스에서 작업을 처리하는 시간과 요청 및 회신의 대기 시간이 포함됩니다. 일정 시간당 작업을 더 많이 수행하려면 작업을 동시에 실행해야 합니다. 이때 다음의 여러 방식을 사용할 수 있습니다.

  • 비동기 작업: 클라이언트가 비동기 작업을 수행해 여러 작업을 파이프라인으로 연결합니다. 이전 요청이 완료되기 전에 다음 요청이 시작됩니다. 다음은 비동기 보내기 작업의 예제입니다.

    BrokeredMessage m1 = new BrokeredMessage(body);
    BrokeredMessage m2 = new BrokeredMessage(body);
    queueClient.BeginSend(m1, processEndSend, queueClient); // Send message 1.
    queueClient.BeginSend(m2, processEndSend, queueClient); // Send message 2.
    
    void processEndSend(IAsyncResult result)
    {
        QueueClient qc = result.AsyncState as QueueClient;
        qc.EndSend(result);
        Console.WriteLine("Message sent");
    }
    
    다음은 비동기 받기 작업의 예제입니다.

    queueClient.BeginReceive(processEndReceive, queueClient); // Receive message 1.
    queueClient.BeginReceive(processEndReceive, queueClient); // Receive message 2.
    
    void processEndReceive(IAsyncResult result) 
    {
        QueueClient qc = result.AsyncState as QueueClient;
        BrokeredMessage m = qc.EndReceive(result);
        m.BeginComplete(processEndComplete, m);
        Console.WriteLine("Received message " + m.Label);
    }
    
    void processEndComplete(IAsyncResult result)
    {
        BrokeredMessage m = result.AsyncState as BrokeredMessage;
        m.EndComplete(result);
        Console.WriteLine("Completed message " + m.Label);
    }
    
  • 여러 팩터리: 같은 팩터리를 통해 작성되는 모든 클라이언트(발신자와 수신자)는 단일 TCP 연결을 공유합니다. 최대 메시지 처리량은 이 TCP 연결을 통과할 수 있는 작업 수로 제한됩니다. 단일 팩터리를 통해 제공되는 처리량은 TCP 왕복 시간과 메시지 크기에 따라 크게 달라집니다. 처리량 속도를 높이려면 여러 메시징 팩터리를 사용해야 합니다.

수신 모드

큐 또는 구독 클라이언트를 만들 때는 수신 모드를 보기-잠금 또는 받기 및 삭제 중 하나로 지정할 수 있습니다. 기본 수신 모드는 PeekLock입니다. 클라이언트는 이 모드로 작동할 때 Service Bus에서 메시지를 받기 위한 요청을 보냅니다. 그리고 메시지를 받고 나면 메시지를 완료하기 위한 요청을 보냅니다.

수신 모드를 ReceiveAndDelete로 설정하면 이 두 단계가 단일 요청으로 결합됩니다. 따라서 전체 작업 수가 줄어들고 전체 메시지 처리량이 높아집니다. 이러한 성능 향상은 메시지 손실의 위험을 무릅쓴 결과입니다.

Service Bus에서는 받기 및 삭제 작업의 트랜잭션이 지원되지 않습니다. 또한 클라이언트가 메시지를 지연시키거나 배달 못한 메시지로 지정하려는 모든 시나리오에서는 보기-잠금 의미 체계가 필요합니다.

클라이언트 쪽 일괄 처리

클라이언트 쪽 일괄 처리 기능을 통해 큐 또는 항목 클라이언트가 일정 기간 동안 메시지 보내기를 연기할 수 있습니다. 클라이언트가 이 기간 동안 추가 메시지를 보내면 단일 일괄 처리로 메시지를 전송합니다. 또한 클라이언트 쪽 일괄 처리를 사용하는 경우 큐/구독 클라이언트가 여러 완료 요청을 단일 요청으로 일괄 처리합니다. 일괄 처리는 비동기 보내기완료 작업의 경우에만 수행할 수 있습니다. 동기 작업은 Service Bus 서비스로 즉시 발송됩니다. 보기 또는 받기 작업이나 클라이언트 전체에 대해서는 일괄 처리가 수행되지 않습니다.

일괄 처리가 최대 메시지 크기를 초과하는 경우 마지막 메시지가 일괄 처리에서 제거되고 클라이언트가 일괄 처리를 즉시 보냅니다. 그러면 마지막 메시지가 다음 일괄 처리에서 첫 번째 메시지가 됩니다. 기본적으로 클라이언트에서 사용하는 일괄 처리 간격은 20ms입니다. 메시징 팩터리를 만들기 전에 BatchFlushInterval 속성을 설정하면 일괄 처리 간격을 변경할 수 있습니다. 이 설정은 해당 팩터리를 통해 작성되는 모든 클라이언트에 적용됩니다. 일괄 처리를 사용하지 않도록 설정하려면 BatchFlushInterval 속성을 TimeSpan.Zero로 설정합니다. 예를 들면 다음과 같습니다.

MessagingFactorySettings mfs = new MessagingFactorySettings();
mfs.TokenProvider = tokenProvider;
mfs.NetMessagingTransportSettings.BatchFlushInterval = TimeSpan.FromSeconds(0.05);
MessagingFactory messagingFactory = MessagingFactory.Create(namespaceUri, mfs);

일괄 처리는 청구 가능 메시징 작업의 수에 영향을 주지 않고 Service Bus 클라이언트 프로토콜에 대해서만 사용 가능합니다. HTTP 프로토콜은 일괄 처리를 지원하지 않습니다.

저장소 액세스 일괄 처리

큐/항목/구독의 처리량을 높이기 위해 Service Bus 서비스는 내부 저장소에 쓸 때 여러 메시지를 일괄 처리합니다. 큐 또는 항목에서 사용하도록 설정된 경우 저장소에 대한 메시지 쓰기가 일괄 처리됩니다. 큐 또는 구독에서 사용하도록 설정된 경우 저장소로부터의 메시지 삭제도 일괄 처리됩니다. 엔터티에 대해 일괄 처리된 저장소 액세스가 사용하도록 설정된 경우 Service Bus는 해당 엔터티에 대한 저장소 쓰기 작업을 최대 20ms까지 연기합니다. 이 간격 중에 수행되는 추가 저장소 작업이 일괄 처리에 추가됩니다. 일괄 처리된 저장소 액세스는 보내기완료 작업에만 영향을 주고, 받기 작업에는 영향을 주지 않습니다. 일괄 처리된 저장소 액세스는 엔터티에 대한 속성입니다. 즉, 일괄 처리된 저장소 액세스가 가능한 모든 엔터티에서 일괄 처리가 수행됩니다.

새 큐, 항목 또는 구독을 만들면 일괄 처리된 저장소 액세스를 기본적으로 사용하도록 설정됩니다. 일괄 처리된 저장소 액세스를 사용하지 않도록 설정하려면 엔터티를 만들기 전에 EnableBatchedOperations 속성을 false로 설정합니다. 예를 들면 다음과 같습니다.

QueueDescription qd = new QueueDescription();
qd.EnableBatchedOperations = false;
Queue q = namespaceManager.CreateQueue(qd);

일괄 처리된 저장소 액세스는 큐, 항목 또는 구독의 속성이며, 청구 가능 메시징 작업의 수에 영향을 주지 않습니다. 즉, 일괄 처리된 데이터베이스 액세스는 클라이언트와 Service Bus 서비스 간에 사용되는 프로토콜 및 수신 모드에 독립적입니다.

프리페치

큐 또는 구독 클라이언트는 프리페치를 통해 받기 작업을 수행하면 서비스에서 추가 메시지를 로드할 수 있습니다. 클라이언트는 이러한 메시지를 로컬 캐시에 저장합니다. 캐시 크기는 PrefetchCountPrefetchCount 속성으로 결정됩니다. 프리페치 메커니즘을 사용하도록 설정하는 각 클라이언트가 자체 캐시를 유지 관리합니다. 즉, 캐시가 클라이언트 간에 공유되지 않습니다. 클라이언트가 받기 작업을 시작할 때 캐시가 비어 있으면 서비스에서 메시지 일괄 처리를 전송합니다. 배치 크기는 캐시 크기 또는 256KB 중에서 더 작은 쪽과 일치합니다. 클라이언트가 받기 작업을 시작할 때 캐시에 메시지가 포함되어 있으면 캐시에서 해당 메시지를 가져옵니다.

메시지를 프리페치할 때 서비스는 프리페치된 메시지를 잠급니다. 이렇게 하면 다른 수신자가 프리페치된 메시지를 받을 수 없습니다. 잠금이 만료되기 전에 수신자가 메시지를 완료할 수 없으면 다른 수신자가 해당 메시지를 사용할 수 있게 됩니다. 프리페치된 메시지 복사본은 캐시에 유지됩니다. 만료된 상태의 캐시된 복사본을 사용하는 수신자가 해당 메시지를 완료하려고 하면 예외가 수신됩니다. 기본적으로 메시지 잠금은 60초 후에 만료됩니다. 이 값은 5분까지 연장할 수 있습니다. 만료된 메시지가 사용되지 않도록 하려면 캐시 크기는 잠금 시간 제한 간격 내에 클라이언트가 사용할 수 있는 메시지 수보다 항상 작아야 합니다.

기본 잠금 만료 시간인 60초를 사용하는 경우 적절한 SubscriptionClient.PrefetchCount 값은 모든 팩터리 수신자의 최대 처리 속도*20입니다. 예를 들어 팩터리가 수신자 3개를 만들고, 각 수신자가 초당 메시지를 10개까지 처리할 수 있다고 가정할 때 프리페치 개수가 20*3*10 = 600을 초과해서는 안 됩니다. 기본적으로 QueueClient.PrefetchCount는 0으로 설정되므로 서비스에서 메시지를 추가로 가져오지 않습니다.

메시지를 프리페치하는 경우 전체 메시지 작업 수 또는 왕복 횟수가 감소하므로, 큐 또는 구독의 전체 처리량이 높아집니다. 그러나 메시지 크기가 증가하므로 첫 번째 메시지를 가져오는 데 시간이 더 오래 걸립니다. 프리페치된 메시지는 이미 클라이언트에서 다운로드한 상태이므로 수신 속도가 더 빠릅니다.

서버는 클라이언트로 메시지를 보낼 때 메시지의 TTL(Time-To-Live) 속성을 확인합니다. 클라이언트는 메시지를 받을 때 메시지의 TTL 속성을 확인하지 않습니다. 대신 클라이언트가 메시지를 캐시하는 동안 메시지의 TTL이 전달되었더라도 메시지를 받을 수 있습니다.

프리페치는 청구 가능 메시징 작업의 수에 영향을 주지 않고 Service Bus 클라이언트 프로토콜에 대해서만 사용 가능합니다. HTTP 프로토콜은 프리페치를 지원하지 않습니다. 프리페치는 동기 및 비동기 받기 작업에 사용할 수 있습니다.

분할된 큐 또는 항목 사용

내부적으로 Service Bus는 동일한 노드와 메시징 저장소를 사용하여 메시징 엔터티(큐 또는 항목)에 대한 모든 메시지를 처리하고 저장합니다. 반면, 분할된 큐 또는 항목은 여러 노드와 메시징 저장소에 분산됩니다. 분할된 큐 및 항목은 일반적인 큐 및 항목보다 처리량이 더 높을 뿐 아니라 뛰어난 가용성을 제공합니다. 분할된 엔터티를 만들려면 다음 예제에서처럼 EnablePartitioning 속성을 true로 설정합니다. 분할된 엔터티에 대한 자세한 내용은 메시징 엔터티 분할을 참조하십시오.

// Create partitioned queue.
QueueDescription qd = new QueueDescription(QueueName);
qd.EnablePartitioning = true;
namespaceManager.CreateQueue(qd);

여러 큐 사용

분할된 큐 또는 항목을 사용할 수 없거나 분할된 단일 큐 또는 항목에서 예상 부하량을 처리할 수 없는 경우 여러 메시징 엔터티를 사용해야 합니다. 여러 엔터티를 사용할 때는 모든 엔터티에 같은 클라이언트를 사용하는 대신, 각 엔터티에 대해 전용 클라이언트를 만듭니다.

시나리오

다음 섹션에서는 일반적인 메시징 시나리오와 기본 Service Bus 설정을 설명합니다. 처리량 속도는 낮음(<1msg/s), 보통(≥1msg/s, <100msg/s), 높음(≥100msg/s)으로 분류됩니다. 그리고 클라이언트 수는 적음(≤5), 보통(>5 ≤ 20), 많음(>20)으로 분류됩니다.

처리량이 높은 큐

목표: 단일 큐의 처리량을 최대화합니다. 발신자와 수신자의 수는 적음이고,

  • 성능 및 가용성을 향상시키려면 분할된 큐를 사용합니다.

  • 큐로의 전체 보내기 속도를 높이려면 여러 메시지 팩터리를 사용하여 발신자를 만듭니다. 그리고 각 발신자에 대해 비동기 작업이나 여러 스레드를 사용합니다.

  • 큐로부터의 전체 받기 속도를 높이려면 여러 메시지 팩터리를 사용하여 수신자를 만듭니다.

  • 클라이언트 쪽 일괄 처리 기능을 사용하려면 비동기 작업을 수행합니다.

  • Service Bus 클라이언트 프로토콜 전송 횟수를 줄이려면 일괄 처리 간격을 50ms로 설정합니다. 여러 발신자를 사용하는 경우에는 일괄 처리 간격을 100ms로 늘립니다.

  • 일괄 처리된 저장소 액세스는 사용 가능한 상태로 유지합니다. 그러면 메시지를 큐에 쓸 수 있는 전체 속도가 높아집니다.

  • 프리페치 개수는 팩터리에 있는 모든 수신자의 최대 처리 속도*20으로 설정합니다. 그러면 Service Bus 클라이언트 프로토콜 전송 횟수가 줄어듭니다.

처리량이 높은 큐 여러 개

목표: 여러 큐의 전체 처리량을 최대화합니다. 개별 큐의 처리량은 보통 또는 높음입니다.

여러 큐에서 최대 처리량을 달성하려면 단일 큐의 처리량을 최대화하는 설정을 사용합니다. 또한 서로 다른 팩터리를 사용하여 서로 다른 큐에서 메시지를 주고받는 클라이언트를 만듭니다.

대기 시간이 짧은 큐

목표: 큐나 항목의 종단 간 대기 시간을 최소화합니다. 발신자와 수신자의 수는 적음이고, 큐의 처리량은 낮음 또는 보통입니다.

  • 가용성을 향상시키려면 분할된 큐를 사용합니다.

  • 클라이언트 쪽 일괄 처리를 사용하지 않도록 설정합니다. 그러면 클라이언트가 메시지를 즉시 보냅니다.

  • 일괄 처리된 저장소 액세스를 사용하지 않도록 설정합니다. 그러면 서비스가 저장소에 메시지를 즉시 씁니다.

  • 단일 클라이언트를 사용하는 경우 프리페치 개수를 수신자 처리 속도*20으로 설정합니다. 여러 메시지가 동시에 큐에 도착하는 경우 Service Bus 클라이언트 프로토콜은 모든 메시지를 동시에 전송합니다. 따라서 클라이언트에서 다음 메시지를 받으면 해당 메시지는 로컬 캐시에 이미 있는 상태입니다. 캐시 크기는 작아야 합니다.

  • 여러 클라이언트를 사용하는 경우 프리페치 개수를 0으로 설정합니다. 이렇게 하면 첫 번째 클라이언트가 첫 번째 메시지를 계속 처리하는 동안 두 번째 클라이언트가 두 번째 메시지를 받을 수 있습니다.

발신자 수가 많은 큐

목표: 발신자 수가 많은 큐나 항목의 처리량을 최대화합니다. 각 발신자는 보통 속도로 메시지를 보냅니다. 수신자의 수는 적음입니다.

Service Bus에서는 단일 엔터티에 대한 동시 연결이 100개까지 허용됩니다. 큐의 경우에는 발신자와 수신자가 이 동시 연결 수를 공유합니다. 따라서 발신자에 100개 연결이 모두 필요한 경우에는 큐를 항목과 구독 하나로 교체해야 합니다. 항목은 발신자의 동시 연결을 100개까지 수락하며, 구독은 수신자의 동시 연결을 100개까지 추가로 수락합니다. 동시 발신자가 100개보다 많이 필요한 경우 발신자는 HTTP를 통해 Service Bus 프로토콜로 메시지를 보내야 합니다.

처리량을 최대화하려면 다음을 수행합니다.

  • 성능 및 가용성을 향상시키려면 분할된 큐를 사용합니다.

  • 발신자가 각각 다른 프로세스에 있는 경우 프로세스당 팩터리를 하나만 사용합니다.

  • 클라이언트 쪽 일괄 처리 기능을 사용하려면 비동기 작업을 수행합니다.

  • Service Bus 클라이언트 프로토콜 전송 횟수를 줄이려면 기본 일괄 처리 간격인 20ms를 사용합니다.

  • 일괄 처리된 저장소 액세스는 사용 가능한 상태로 유지합니다. 그러면 메시지를 큐나 항목에 쓸 수 있는 전체 속도가 높아집니다.

  • 프리페치 개수는 팩터리에 있는 모든 수신자의 최대 처리 속도*20으로 설정합니다. 그러면 Service Bus 클라이언트 프로토콜 전송 횟수가 줄어듭니다.

수신자 수가 많은 큐

목표: 수신자 수가 많은 큐나 구독의 수신 속도를 최대화합니다. 각 수신자는 보통 속도로 메시지를 받습니다. 발신자의 수와

Service Bus에서는 단일 엔터티에 대한 동시 연결이 100개까지 허용됩니다. 따라서 큐에 수신자가 100개보다 많이 필요한 경우에는 큐를 항목과 구독 여러 개로 교체해야 합니다. 각 구독은 동시 연결을 100개까지 지원할 수 있습니다. 수신자가 HTTP 프로토콜을 통해 큐에 액세스할 수도 있습니다.

처리량을 최대화하려면 다음을 수행합니다.

  • 성능 및 가용성을 향상시키려면 분할된 큐를 사용합니다.

  • 수신자가 각각 다른 프로세스에 있는 경우 프로세스당 팩터리를 하나만 사용합니다.

  • 수신자는 동기 또는 비동기 작업을 사용할 수 있습니다. 개별 수신자의 수신 속도가 보통일 때 완료 요청의 클라이언트 쪽 일괄 처리는 수신기 처리량에 영향을 주지 않습니다.

  • 일괄 처리된 저장소 액세스는 사용 가능한 상태로 유지합니다. 이렇게 하면 엔터티의 전체 부하가 줄어듭니다. 또한 메시지를 큐나 항목에 쓸 수 있는 전체 속도가 감소합니다.

  • 프리페치 개수를 더 작은 값으로 설정합니다(예: PrefetchCount = 10). 그러면 다른 수신자에서 캐시되는 메시지 수가 많을 때 수신자가 유휴 상태가 되지 않습니다.

구독 수가 적은 항목

목표: 구독 수가 적은 항목의 처리량을 최대화합니다. 여러 구독에서 메시지를 받으므로 모든 구독의 수신 속도가 결합된 값은 전송 속도보다 큽니다. 발신자의 수와 구독당 수신자의 수는 적음입니다.

처리량을 최대화하려면 다음을 수행합니다.

  • 성능 및 가용성을 향상시키려면 분할된 항목을 사용합니다.

  • 항목으로의 전체 보내기 속도를 높이려면 여러 메시지 팩터리를 사용하여 발신자를 만듭니다. 그리고 각 발신자에 대해 비동기 작업이나 여러 스레드를 사용합니다.

  • 구독으로부터의 전체 받기 속도를 높이려면 여러 메시지 팩터리를 사용하여 수신자를 만듭니다. 그리고 각 수신자에 대해 비동기 작업이나 여러 스레드를 사용합니다.

  • 클라이언트 쪽 일괄 처리 기능을 사용하려면 비동기 작업을 수행합니다.

  • Service Bus 클라이언트 프로토콜 전송 횟수를 줄이려면 기본 일괄 처리 간격인 20ms를 사용합니다.

  • 일괄 처리된 저장소 액세스는 사용 가능한 상태로 유지합니다. 그러면 메시지를 항목에 쓸 수 있는 전체 속도가 높아집니다.

  • 프리페치 개수는 팩터리에 있는 모든 수신자의 최대 처리 속도*20으로 설정합니다. 그러면 Service Bus 클라이언트 프로토콜 전송 횟수가 줄어듭니다.

구독 수가 많은 항목

목표: 구독 수가 많은 항목의 처리량을 최대화합니다. 여러 구독에서 메시지를 받으므로 모든 구독의 수신 속도가 결합된 값은 전송 속도보다 훨씬 큽니다. 발신자의 수와 구독당 수신자의 수는 적음입니다.

모든 메시지가 모든 구독으로 라우팅되는 경우 일반적으로 구독 수가 많은 항목의 전체 처리량은 낮습니다. 각 메시지가 여러 번 수신되고, 항목 및 모든 해당 구독에 포함된 모든 메시지가 같은 저장소에 저장되기 때문입니다. 구독당 발신자 수와 수신자 수는 적음으로 가정합니다. Service Bus에서는 항목당 구독이 2천 개까지 지원됩니다.

처리량을 최대화하려면 다음을 수행합니다.

  • 성능 및 가용성을 향상시키려면 분할된 항목을 사용합니다.

  • 클라이언트 쪽 일괄 처리 기능을 사용하려면 비동기 작업을 수행합니다.

  • Service Bus 클라이언트 프로토콜 전송 횟수를 줄이려면 기본 일괄 처리 간격인 20ms를 사용합니다.

  • 일괄 처리된 저장소 액세스는 사용 가능한 상태로 유지합니다. 그러면 메시지를 항목에 쓸 수 있는 전체 속도가 높아집니다.

  • 프리페치 개수는 초당 예상 수신 속도*20으로 설정합니다. 그러면 Service Bus 클라이언트 프로토콜 전송 횟수가 줄어듭니다.

이 정보가 도움이 되었습니까?
(1500자 남음)
의견을 주셔서 감사합니다.

커뮤니티 추가 항목

추가
표시:
© 2014 Microsoft. All rights reserved.