2011-10-20 2 views
18

그래서 WCF 응용 프로그램에서 성능을 약간 높이고 채널 및 ChannelFactory를 캐싱하려고했습니다. 내가 시작하기 전에 내가 정리해야 할 모든 것에 관한 두 가지 질문이 있습니다.WCF 채널 및 ChannelFactory 캐싱

1) ChannelFactory를 싱글 톤으로 구현해야합니까?

2) 저는 개별 채널을 캐시/재사용하는 방법에 대해 확신 할 수 없습니다. 공유하는 방법에 대한 예가 있습니까?

내 WCF 서비스가 하나의 끝점 만있는 독립 실행 형 응용 프로그램으로 배포되고 있다는 점에 유의해야합니다.

편집 :

이 응답 해 주셔서 감사합니다. 그래도 여전히 몇 가지 질문이 있습니다 ...

1) 캐싱이 발생해야하는 곳을 혼란스럽게 생각합니다. 우리 회사의 다른 부서에이 코드를 사용하는 클라이언트 API를 제공하고 있습니다. 이 캐싱은 클라이언트에서 발생합니까?

2) 클라이언트 API는 Silverlight 응용 프로그램의 일부로 사용됩니다.이 변경 사항은 무엇입니까? 특히 이러한 시나리오에서 사용할 수있는 캐싱 메커니즘은 무엇입니까?

3) GetChannelFactory 메서드의 디자인에 대해 아직 명확하지 않습니다. 하나의 서비스 만 있다면, 하나의 ChannelFactory가 만들어지고 캐시되어야합니까?

나는 아직도 (나는 그것을 할 방법에 대해 완전히 혼란 스러워요 때문에!) 어떤 캐싱 기능을 구현하지만, 여기에 내가 지금까지 클라이언트 프록시가 무엇을하지 않은

:

namespace MyCompany.MyProject.Proxies 
{ 
    static readonly ChannelFactory<IMyService> channelFactory = 
     new ChannelFactory<IMyService>("IMyService"); 

    public Response DoSomething(Request request) 
    { 
     var channel = channelFactory.CreateChannel(); 

     try 
     { 
      Response response = channel.DoSomethingWithService(request); 
      ((ICommunicationObject)channel).Close(); 
      return response; 
     } 
     catch(Exception exception) 
     { 
      ((ICommenicationObject)channel).Abort(); 
     } 
    } 
} 
+0

# 3의 경우 네 채널 팩터 리만 만들어야합니다. 기본적으로 가지고있는 서비스 엔드 포인트 당 하나의 채널 팩토리가 있습니다. 필자의 경우, 지금까지 약 6 개가 있었고 주로 2 개 계층에 걸쳐 퍼져있었습니다. 귀하의 경우, 한 가지 서비스 만 사용하려는 경우 하나의 앱만 사용하면 위의 작업 만 수행하면됩니다. 위의 코드는 올바른 방향입니다. 캐싱은 앱의 요구를 기반으로합니다. – Tim

+0

@Tim - 모든 도움에 감사드립니다. 나는 정말로 그것을 바르게 평가한다! 내 경우에는 내 서비스가 너무 단순해서 여러 개의 끝점이있는 다른 예제를 살펴 보는 것이 혼란 스러웠다 고 생각합니다. Me = 덜 혼란 스러웠던 = Tim는 훌륭한 직업을 설명했다! 고마워 친구! – Didaxis

+0

대단히 반갑습니다. 다행히 도울 수있어 - 행복한 코딩! – Tim

답변

20

사용을 ChannelFactory를 사용하여 팩토리의 인스턴스를 만든 다음 해당 인스턴스를 캐싱합니다. 그런 다음 캐시 된 내용에서 필요/원하는대로 의사 소통 채널을 만들 수 있습니다.

여러 채널 공장이 필요합니까 (예 : 여러 서비스가 있습니까)? 내 경험상, 그것은 당신이 성능면에서 가장 큰 이점을 볼 수있는 곳입니다. 채널을 만드는 것은 상당히 저렴한 작업입니다. 처음부터 시간이 걸리는 모든 것을 설정하고 있습니다.

저는 개별 채널을 캐시하지 않을 것입니다. 채널을 생성하고, 조작에 사용하고, 닫을 것입니다. 캐시하면 캐시가 만료되어 채널에 오류가 발생하므로 중지하고 어쨌든 새 채널을 만들어야합니다.

싱글 톤을 사용하여 ChannelFactory를 구현하려는 이유가 명확하지 않은데, 특히 싱글 톤을 만들고 캐시하고 단일 엔드 포인트 만있는 경우에 특히 그렇습니다.

나중에 약간의 시간이있을 때 예제 코드를 게시 할 것입니다.

UPDATE : 코드 예제

는 여기에 내가 직장에서 프로젝트에 대한이 구현하는 방법의 예입니다. ChannelFactory<T>을 사용했습니다. 개발중인 응용 프로그램은 여러 가지 서비스가있는 n 계층 응용 프로그램이며 더 많은 기능이 추가됩니다. 목표는 응용 프로그램의 수명이 끝날 때마다 클라이언트를 만든 다음 필요에 따라 통신 채널을 만드는 간단한 방법을 찾는 것입니다. 아이디어의 기본 사항은 내 것이 아니며 (웹의 기사에서 얻은 것입니다.) 필요에 맞게 구현을 수정했지만

내 응용 프로그램에 정적 도우미 클래스가 있고 해당 클래스 내에서 channelf 팩토리에서 통신 채널을 만드는 사전과 메서드가 있습니다.

사전은 다음과 같습니다 (객체는 각 채널 팩토리를 포함하므로 각 서비스마다 하나씩). 예제에서 "Cache"를 자리 표시 자의 일종으로 지정합니다. 구문을 사용중인 모든 캐싱 메커니즘으로 바꿉니다.

public static Dictionary<string, object> OpenChannels 
{ 
    get 
    { 
     if (Cache["OpenChannels"] == null) 
     { 
      Cache["OpenChannels"] = new Dictionary<string, object>(); 
     } 

     return (Dictionary<string, object>)Cache["OpenChannels"]; 
    } 
    set 
    { 
     Cache["OpenChannels"] = value; 
    } 
} 

다음은 팩토리 인스턴스에서 통신 채널을 만드는 방법입니다. 이 메서드는 팩토리가 먼저 존재하는지 확인합니다. 팩토리가 없으면 미리 만들고 사전에 넣은 다음 채널을 생성합니다. 그렇지 않으면 단순히 캐시 된 인스턴스에서 채널을 생성합니다.

public static T GetFactoryChannel<T>(string address) 
{ 

    string key = typeof(T.Name); 

    if (!OpenChannels.ContainsKey(key)) 
    { 
     ChannelFactory<T> factory = new ChannelFactory<T>(); 
     factory.Endpoint.Address = new EndpointAddress(new System.Uri(address)); 
     factory.Endpoint.Binding = new BasicHttpBinding(); 
     OpenChannels.Add(key, factory); 
    } 

    T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel(); 

    ((IClientChannel)channel).Open(); 

    return channel; 
} 

나는이 제품을 내가 직장에서 사용하는 것의 일부에서 제거했다. 이 방법으로 할 수있는 일은 많습니다. 여러 바인딩을 처리하고 인증을위한 자격 증명을 할당 할 수 있습니다. 클라이언트 생성을위한 원 스톱 쇼핑 센터입니다.

마지막으로 응용 프로그램에서 사용할 때 일반적으로 채널을 만들고 비즈니스를 수행하고 닫고 필요하면 중단합니다. 예 :

IMyServiceContract client; 

try 
{ 
    client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress"); 

    client.DoSomething(); 

    // This is another helper method that will safely close the channel, 
    // handling any exceptions that may occurr trying to close. 
    // Shouldn't be any, but it doesn't hurt. 
    Helper.CloseChannel(client); 
} 
catch (Exception ex) 
{ 
    // Something went wrong; need to abort the channel 
    // I also do logging of some sort here 
    Helper.AbortChannel(client); 
} 

위 예제는 계속 진행할 수 있기를 바랍니다. 나는 프로덕션 환경에서 약 1 년 동안 비슷한 것을 사용 해왔고 매우 잘 작동했습니다. 우리가 직면 한 모든 문제 중 99 %는 일반적으로 응용 프로그램 외부의 것 (우리의 직접 통제하에 있지 않은 외부 클라이언트 또는 데이터 소스)과 관련이 있습니다.

명확하지 않은 것이 있거나 추가 질문이 있으면 알려주십시오. 당신은 언제나 각 WCF 계약에 대한 ChannelFactory에 정적 만들 수

+0

감사합니다. 당신은 정말로 가치있는 정보를 제공했습니다. 나는 분명히 당신의 모범을 바라 볼 것입니다! – Didaxis

+0

@ user384080 - 내 대답은 코드입니다. 명확하지 않으면 알려주세요. 감사. – Tim

+0

@Tim 구현에 버그가 있습니다. 주소가 무엇이든간에 계약 유형별로 공장을 캐시합니다. 계약 유형과 주소를 모두 포함하는 키가 있어야합니다. – Anubis

5

...

당신은 닷넷 3.5에서 프록시 개체가 채널 팩터에 의한 성능 향상을 위해 풀링 알고 있어야합니다. ICommunicationObject.Close() 메서드를 호출하면 실제로 객체를 다시 사용할 수 있기를 바랍니다.

일부 최적화를 원한다면 프로파일 러를 보게 될 것입니다. 코드에서 단 하나의 IO 호출이 발생하지 않도록하면 채널 팩터 리로 수행 할 최적화보다 훨씬 중요 할 수 있습니다. 최적화 할 영역을 선택하지 마십시오. 프로파일 러를 사용하여 최적화 대상을 찾을 수 있습니다. 예를 들어 SQL 데이터베이스가있는 경우 쿼리에서 부족한 결과를 발견 할 수 있습니다. 이러한 결과가 아직 최적화되지 않은 경우 주문 증가 효과를 얻을 수 있습니다.

3

채널을 만들면 성능이 많이 저하됩니다. 실제로, 순수한 ChannelFactory 대신 ClientBase를 사용하면 WCF는 ChannelFactory에 대한 캐시 메커니즘을 이미 가지고 있습니다. 그러나 캐시는 일부 작업을 수행하면 만료됩니다 (원하는 경우 자세한 내용을 Google에 알려주십시오). ErOx의 문제에 대해서는 다른 해결책이 있다고 생각합니다. 아래를 참조하십시오 :

다른 요구 사항이있는 경우 Initiate 메소드의 로직과 매개 변수를 사용자 정의 할 수 있습니다. 이 개시 자 클래스는 단 하나의 엔드 포인트로 제한되지 않습니다. 그것은 귀하의 어플리케이션에있는 모든 엔드 포인트에 대해 강력합니다. 잘하면. 그것은 당신을 위해 잘 작동합니다. BTW. 이 해결책은 나에게서 나온 것이 아니다. 나는 책에서 이것을 얻었다.

+0

'lock'이 잘못 사용되었습니다. 잠금은'ContainsKey'에 대한 호출에서도 취해 져야합니다. –