Aracılığıyla paylaş


Reliable Services iletişim API'lerini kullanma

Platform olarak Azure Service Fabric, hizmetler arasındaki iletişimden tamamen bağımsızdır. UDP'den HTTP'ye kadar tüm protokoller ve yığınlar kabul edilebilir. Hizmetlerin nasıl iletişim kuracaklarını seçmek hizmet geliştiricisine bağlı. Reliable Services uygulama çerçevesi, yerleşik iletişim yığınlarının yanı sıra özel iletişim bileşenlerinizi oluşturmak için kullanabileceğiniz API'ler sağlar.

Hizmet iletişimini ayarlama

Reliable Services API'sinde hizmet iletişimi için basit bir arabirim kullanılır. Hizmetinize yönelik bir uç nokta açmak için şu arabirimi uygulamanız yeterlidir:


public interface ICommunicationListener
{
    Task<string> OpenAsync(CancellationToken cancellationToken);

    Task CloseAsync(CancellationToken cancellationToken);

    void Abort();
}

public interface CommunicationListener {
    CompletableFuture<String> openAsync(CancellationToken cancellationToken);

    CompletableFuture<?> closeAsync(CancellationToken cancellationToken);

    void abort();
}

Ardından, iletişim dinleyicisi uygulamanızı hizmet tabanlı sınıf yöntemi geçersiz kılmada döndürerek ekleyebilirsiniz.

Durum bilgisi olmayan hizmetler için:

public class MyStatelessService : StatelessService
{
    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        ...
    }
    ...
}
public class MyStatelessService extends StatelessService {

    @Override
    protected List<ServiceInstanceListener> createServiceInstanceListeners() {
        ...
    }
    ...
}

Durum bilgisi olan hizmetler için:

    @Override
    protected List<ServiceReplicaListener> createServiceReplicaListeners() {
        ...
    }
    ...
public class MyStatefulService : StatefulService
{
    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
    {
        ...
    }
    ...
}

Her iki durumda da bir dinleyici koleksiyonu döndürürsün. Birden çok dinleyici kullanmak, hizmetinizin farklı protokoller kullanma olasılığı olan birden çok uç noktayı dinlemesine olanak tanır. Örneğin, bir HTTP dinleyiciniz ve ayrı bir WebSocket dinleyiciniz olabilir. Önce hem güvenli olmayan bir dinleyiciye hem de güvenli bir dinleyiciye sahip olarak her iki senaryoya da olanak tanıyarak güvenli olmayan uzaktan iletişimden güvenli uzaktan iletişime geçiş yapabilirsiniz. Her dinleyici bir ad alır ve sonuçta elde edilen ad : adres çiftleri koleksiyonu, bir istemci bir hizmet örneği veya bölümü için dinleme adreslerini istediğinde bir JSON nesnesi olarak temsil edilir.

Durum bilgisi olmayan bir hizmette geçersiz kılma, serviceInstanceListeners koleksiyonunu döndürür. A ServiceInstanceListener , oluşturmak ICommunicationListener(C#) / CommunicationListener(Java) için bir işlev içerir ve ona bir ad verir. Durum bilgisi olan hizmetler için geçersiz kılma bir ServiceReplicaListeners koleksiyonu döndürür. Bu durum bilgisi olmayan karşılıklarından biraz farklıdır, çünkü bir ServiceReplicaListener ikincil çoğaltmada açma ICommunicationListener seçeneği vardır. Bir hizmette birden çok iletişim dinleyicisi kullanmakla kalmaz, aynı zamanda hangi dinleyicilerin ikincil çoğaltmalardaki istekleri kabul edip hangilerinin yalnızca birincil çoğaltmalarda dinlediğini de belirtebilirsiniz.

Örneğin, yalnızca birincil çoğaltmalarda RPC çağrılarını alan bir ServiceRemotingListener ve HTTP üzerinden ikincil çoğaltmalarda okuma isteklerini alan ikinci bir özel dinleyiciniz olabilir:

protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
    return new[]
    {
        new ServiceReplicaListener(context =>
            new MyCustomHttpListener(context),
            "HTTPReadonlyEndpoint",
            true),

        new ServiceReplicaListener(context =>
            this.CreateServiceRemotingListener(context),
            "rpcPrimaryEndpoint",
            false)
    };
}

Not

Bir hizmet için birden çok dinleyici oluştururken, her dinleyiciye benzersiz bir ad verilmelidir .

Son olarak, uç noktalar bölümündeki hizmet bildiriminde hizmet için gerekli olan uç noktaları açıklayın.

<Resources>
    <Endpoints>
      <Endpoint Name="WebServiceEndpoint" Protocol="http" Port="80" />
      <Endpoint Name="OtherServiceEndpoint" Protocol="tcp" Port="8505" />
    <Endpoints>
</Resources>

İletişim dinleyicisi, içindeki içinden ona ayrılan uç nokta kaynaklarına CodePackageActivationContextServiceContexterişebilir. Dinleyici daha sonra açıldığında istekleri dinlemeye başlayabilir.

var codePackageActivationContext = serviceContext.CodePackageActivationContext;
var port = codePackageActivationContext.GetEndpoint("ServiceEndpoint").Port;

CodePackageActivationContext codePackageActivationContext = serviceContext.getCodePackageActivationContext();
int port = codePackageActivationContext.getEndpoint("ServiceEndpoint").getPort();

Not

Uç nokta kaynakları tüm hizmet paketinde ortaktır ve hizmet paketi etkinleştirildiğinde Service Fabric tarafından ayrılır. Aynı ServiceHost'ta barındırılan birden çok hizmet çoğaltması aynı bağlantı noktasını paylaşabilir. Bu, iletişim dinleyicisinin bağlantı noktası paylaşımını desteklemesi gerektiği anlamına gelir. Bunu yapmanın önerilen yolu, iletişim dinleyicisinin dinleme adresini oluştururken bölüm kimliğini ve çoğaltma/örnek kimliğini kullanmasıdır.

Hizmet adresi kaydı

Adlandırma Hizmeti adlı bir sistem hizmeti, Service Fabric kümelerinde çalışır. Adlandırma Hizmeti, hizmetlerin ve hizmetin her örneğinin veya çoğaltmasının dinlediği adresleri için bir kayıt şirketidir. OpenAsync(C#) / openAsync(Java) Bir ICommunicationListener(C#) / CommunicationListener(Java) yöntemi tamamlandığında, dönüş değeri Adlandırma Hizmeti'ne kaydedilir. Adlandırma Hizmeti'nde yayımlanan bu dönüş değeri, değeri herhangi bir şey olabilecek bir dizedir. Bu dize değeri, istemcilerin Adlandırma Hizmeti'nden hizmet için bir adres istediklerinde gördükleri değerdir.

public Task<string> OpenAsync(CancellationToken cancellationToken)
{
    EndpointResourceDescription serviceEndpoint = serviceContext.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
    int port = serviceEndpoint.Port;

    this.listeningAddress = string.Format(
                CultureInfo.InvariantCulture,
                "http://+:{0}/",
                port);

    this.publishAddress = this.listeningAddress.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);

    this.webApp = WebApp.Start(this.listeningAddress, appBuilder => this.startup.Invoke(appBuilder));

    // the string returned here will be published in the Naming Service.
    return Task.FromResult(this.publishAddress);
}
public CompletableFuture<String> openAsync(CancellationToken cancellationToken)
{
    EndpointResourceDescription serviceEndpoint = serviceContext.getCodePackageActivationContext.getEndpoint("ServiceEndpoint");
    int port = serviceEndpoint.getPort();

    this.publishAddress = String.format("http://%s:%d/", FabricRuntime.getNodeContext().getIpAddressOrFQDN(), port);

    this.webApp = new WebApp(port);
    this.webApp.start();

    /* the string returned here will be published in the Naming Service.
     */
    return CompletableFuture.completedFuture(this.publishAddress);
}

Service Fabric, istemcilerin ve diğer hizmetlerin bu adresi hizmet adına göre istemesine olanak sağlayan API'ler sağlar. Hizmet adresi statik olmadığından bu önemlidir. Hizmetler, kaynak dengeleme ve kullanılabilirlik amacıyla küme içinde taşınır. Bu, istemcilerin bir hizmetin dinleme adresini çözümlemesine olanak sağlayan mekanizmadır.

Not

İletişim dinleyicisi yazma konusunda ayrıntılı bir kılavuz için bkz. C# için OWIN kendi kendine barındırma ile Service Fabric Web API hizmetleri , Java için ise kendi HTTP sunucusu uygulamanızı yazabilirsiniz. Adresinde EchoServer uygulaması örneği https://github.com/Azure-Samples/service-fabric-java-getting-startedbölümüne bakın.

Bir hizmetle iletişim kurma

Reliable Services API'sinde hizmetlerle iletişim kuran istemcileri yazmak için aşağıdaki kitaplıklar sağlanır.

Hizmet uç noktası çözümlemesi

Bir hizmetle iletişimin ilk adımı, konuşmak istediğiniz hizmetin bölümünün veya örneğinin uç nokta adresini çözümlemektir. ServicePartitionResolver(C#) / FabricServicePartitionResolver(Java) Yardımcı program sınıfı, istemcilerin çalışma zamanında bir hizmetin uç noktasını belirlemesine yardımcı olan temel bir temel öğedir. Service Fabric terminolojisinde, bir hizmetin uç noktasını belirleme işlemi hizmet uç noktası çözümlemesi olarak adlandırılır.

Bir küme içindeki hizmetlere bağlanmak için ServicePartitionResolver varsayılan ayarlar kullanılarak oluşturulabilir. Çoğu durumda önerilen kullanım budur:

ServicePartitionResolver resolver = ServicePartitionResolver.GetDefault();
FabricServicePartitionResolver resolver = FabricServicePartitionResolver.getDefault();

Farklı bir kümedeki hizmetlere bağlanmak için, küme ağ geçidi uç noktaları kümesiyle bir ServicePartitionResolver oluşturulabilir. Ağ geçidi uç noktalarının aynı kümeye bağlanmak için yalnızca farklı uç noktalar olduğunu unutmayın. Örnek:

ServicePartitionResolver resolver = new  ServicePartitionResolver("mycluster.cloudapp.azure.com:19000", "mycluster.cloudapp.azure.com:19001");
FabricServicePartitionResolver resolver = new  FabricServicePartitionResolver("mycluster.cloudapp.azure.com:19000", "mycluster.cloudapp.azure.com:19001");

Alternatif olarak, ServicePartitionResolver dahili olarak kullanmak üzere oluşturmak için bir FabricClient işlev verilebilir:

public delegate FabricClient CreateFabricClientDelegate();
public FabricServicePartitionResolver(CreateFabricClient createFabricClient) {
...
}

public interface CreateFabricClient {
    public FabricClient getFabricClient();
}

FabricClient , kümedeki çeşitli yönetim işlemleri için Service Fabric kümesiyle iletişim kurmak için kullanılan nesnedir. Bu, bir hizmet bölümü çözümleyicinin kümenizle nasıl etkileşime geçtiği üzerinde daha fazla denetime sahip olmak istediğinizde kullanışlıdır. FabricClient önbelleğe alma işlemini dahili olarak gerçekleştirir ve oluşturması genellikle pahalıdır, bu nedenle örnekleri mümkün olduğunca yeniden kullanmak FabricClient önemlidir.

ServicePartitionResolver resolver = new  ServicePartitionResolver(() => CreateMyFabricClient());
FabricServicePartitionResolver resolver = new  FabricServicePartitionResolver(() -> new CreateFabricClientImpl());

Ardından bölümlenmiş hizmetler için bir hizmetin veya hizmet bölümünün adresini almak için bir çözüm yöntemi kullanılır.

ServicePartitionResolver resolver = ServicePartitionResolver.GetDefault();

ResolvedServicePartition partition =
    await resolver.ResolveAsync(new Uri("fabric:/MyApp/MyService"), new ServicePartitionKey(), cancellationToken);
FabricServicePartitionResolver resolver = FabricServicePartitionResolver.getDefault();

CompletableFuture<ResolvedServicePartition> partition =
    resolver.resolveAsync(new URI("fabric:/MyApp/MyService"), new ServicePartitionKey());

Hizmet adresi ServicePartitionResolver kullanılarak kolayca çözülebilir, ancak çözümlenen adresin doğru şekilde kullanılabildiğinden emin olmak için daha fazla çalışma gerekir. İstemcinizin geçici bir hata nedeniyle bağlantı girişiminin başarısız olup olmadığını algılaması ve yeniden denenip denenemeyeceğini (örneğin, hizmetin taşınıp taşınmadığını veya geçici olarak kullanılamadığını) veya kalıcı bir hatayı (örneğin, hizmetin silindiğini veya istenen kaynağın artık mevcut olmadığını) algılaması gerekir. Hizmet örnekleri veya çoğaltmaları, birden çok nedenden dolayı herhangi bir zamanda düğümden düğüme geçebilir. ServicePartitionResolver aracılığıyla çözümlenen hizmet adresi, istemci kodunuz bağlanmaya çalıştığında eski olabilir. Bu durumda istemcinin adresi yeniden çözümlemesi gerekir. Öncekini ResolvedServicePartition sağlamak, çözümleyicinin yalnızca önbelleğe alınmış bir adresi almak yerine yeniden denemesi gerektiğini gösterir.

Genellikle istemci kodunun doğrudan ServicePartitionResolver ile çalışması gerekmez. Oluşturulur ve Reliable Services API'sindeki iletişim istemci fabrikalarına geçirilir. Fabrikalar, hizmetlerle iletişim kurmak için kullanılabilecek bir istemci nesnesi oluşturmak için çözümleyiciyi dahili olarak kullanır.

İletişim istemcileri ve fabrikaları

İletişim fabrikası kitaplığı, çözümlenen hizmet uç noktalarına bağlantıları yeniden denemeyi kolaylaştıran tipik bir hata işleme yeniden deneme düzeni uygular. Fabrika kitaplığı, siz hata işleyicilerini sağlarken yeniden deneme mekanizmasını sağlar.

ICommunicationClientFactory(C#) / CommunicationClientFactory(Java) , Service Fabric hizmetiyle konuşabilen istemciler üreten bir iletişim istemci fabrikası tarafından uygulanan temel arabirimi tanımlar. CommunicationClientFactory uygulamasının uygulanması, istemcinin iletişim kurmak istediği Service Fabric hizmeti tarafından kullanılan iletişim yığınına bağlıdır. Reliable Services API'sinde bir CommunicationClientFactoryBase<TCommunicationClient>sağlanır. Bu, CommunicationClientFactory arabiriminin temel uygulamasını sağlar ve tüm iletişim yığınlarında ortak olan görevleri gerçekleştirir. (Bu görevler hizmet uç noktasını belirlemek için ServicePartitionResolver kullanmayı içerir). İstemciler genellikle iletişim yığınına özgü mantığı işlemek için soyut CommunicationClientFactoryBase sınıfını uygular.

İletişim istemcisi yalnızca bir adres alır ve bir hizmete bağlanmak için bu adresi kullanır. İstemci istediği protokolü kullanabilir.

public class MyCommunicationClient : ICommunicationClient
{
    public ResolvedServiceEndpoint Endpoint { get; set; }

    public string ListenerName { get; set; }

    public ResolvedServicePartition ResolvedServicePartition { get; set; }
}
public class MyCommunicationClient implements CommunicationClient {

    private ResolvedServicePartition resolvedServicePartition;
    private String listenerName;
    private ResolvedServiceEndpoint endPoint;

    /*
     * Getters and Setters
     */
}

İstemci fabrikası öncelikli olarak iletişim istemcileri oluşturmakla sorumludur. HTTP istemcisi gibi kalıcı bir bağlantı sağlamayan istemciler için fabrikanın yalnızca istemciyi oluşturması ve döndürmesi gerekir. Bazı ikili protokoller gibi kalıcı bir bağlantı sürdüren diğer protokoller, bağlantının yeniden oluşturulması gerekip gerekmediğini belirlemek için fabrika tarafından da doğrulanmalıdır (ValidateClient(string endpoint, MyCommunicationClient client)).

public class MyCommunicationClientFactory : CommunicationClientFactoryBase<MyCommunicationClient>
{
    protected override void AbortClient(MyCommunicationClient client)
    {
    }

    protected override Task<MyCommunicationClient> CreateClientAsync(string endpoint, CancellationToken cancellationToken)
    {
    }

    protected override bool ValidateClient(MyCommunicationClient clientChannel)
    {
    }

    protected override bool ValidateClient(string endpoint, MyCommunicationClient client)
    {
    }
}
public class MyCommunicationClientFactory extends CommunicationClientFactoryBase<MyCommunicationClient> {

    @Override
    protected boolean validateClient(MyCommunicationClient clientChannel) {
    }

    @Override
    protected boolean validateClient(String endpoint, MyCommunicationClient client) {
    }

    @Override
    protected CompletableFuture<MyCommunicationClient> createClientAsync(String endpoint) {
    }

    @Override
    protected void abortClient(MyCommunicationClient client) {
    }
}

Son olarak, özel durum işleyicisi bir özel durum oluştuğunda hangi eylemin gerçekleştirilmesi gerektiğini belirlemekle sorumludur. Özel durumlar yeniden denenebilir ve yeniden denenemez olarak kategorilere ayrılır.

  • Yeniden denenemeyen özel durumlar yalnızca çağırana geri döndürülebilir.
  • yeniden denenebilir özel durumlar daha da geçici ve geçici olmayan olarak kategorilere ayrılır.
    • Geçici özel durumlar, hizmet uç noktası adresi yeniden çözümlenmeden yeniden denenebilen özel durumlardır. Bunlar, hizmet uç noktası adresinin mevcut olmadığını belirtenler dışındaki geçici ağ sorunlarını veya hizmet hatası yanıtlarını içerir.
    • Geçici olmayan özel durumlar, hizmet uç noktası adresinin yeniden çözümlenmesi gereken durumlardır. Bunlar, hizmet uç noktasına ulaşılamadığını ve hizmetin farklı bir düğüme taşındığını belirten özel durumları içerir.

belirli TryHandleException bir özel durum hakkında bir karar verir. Bir özel durum hakkında hangi kararları vermeyeceğini bilmiyorsafalse döndürmelidir. Kararın ne olduğunu biliyorsa sonucu buna göre ayarlamalı ve doğru döndürmelidir.

class MyExceptionHandler : IExceptionHandler
{
    public bool TryHandleException(ExceptionInformation exceptionInformation, OperationRetrySettings retrySettings, out ExceptionHandlingResult result)
    {
        // if exceptionInformation.Exception is known and is transient (can be retried without re-resolving)
        result = new ExceptionHandlingRetryResult(exceptionInformation.Exception, true, retrySettings, retrySettings.DefaultMaxRetryCount);
        return true;


        // if exceptionInformation.Exception is known and is not transient (indicates a new service endpoint address must be resolved)
        result = new ExceptionHandlingRetryResult(exceptionInformation.Exception, false, retrySettings, retrySettings.DefaultMaxRetryCount);
        return true;

        // if exceptionInformation.Exception is unknown (let the next IExceptionHandler attempt to handle it)
        result = null;
        return false;
    }
}
public class MyExceptionHandler implements ExceptionHandler {

    @Override
    public ExceptionHandlingResult handleException(ExceptionInformation exceptionInformation, OperationRetrySettings retrySettings) {

        /* if exceptionInformation.getException() is known and is transient (can be retried without re-resolving)
         */
        result = new ExceptionHandlingRetryResult(exceptionInformation.getException(), true, retrySettings, retrySettings.getDefaultMaxRetryCount());
        return true;


        /* if exceptionInformation.getException() is known and is not transient (indicates a new service endpoint address must be resolved)
         */
        result = new ExceptionHandlingRetryResult(exceptionInformation.getException(), false, retrySettings, retrySettings.getDefaultMaxRetryCount());
        return true;

        /* if exceptionInformation.getException() is unknown (let the next ExceptionHandler attempt to handle it)
         */
        result = null;
        return false;

    }
}

Hepsini bir araya getirme

bir ICommunicationClient(C#) / CommunicationClient(Java)iletişim protokolü etrafında oluşturulan , ICommunicationClientFactory(C#) / CommunicationClientFactory(Java)ve IExceptionHandler(C#) / ExceptionHandler(Java) ile, ServicePartitionClient(C#) / FabricServicePartitionClient(Java) bir bütün olarak sarmalar ve bu bileşenler etrafında hata işleme ve hizmet bölümü adres çözümleme döngüsü sağlar.

private MyCommunicationClientFactory myCommunicationClientFactory;
private Uri myServiceUri;

var myServicePartitionClient = new ServicePartitionClient<MyCommunicationClient>(
    this.myCommunicationClientFactory,
    this.myServiceUri,
    myPartitionKey);

var result = await myServicePartitionClient.InvokeWithRetryAsync(async (client) =>
   {
      // Communicate with the service using the client.
   },
   CancellationToken.None);

private MyCommunicationClientFactory myCommunicationClientFactory;
private URI myServiceUri;

FabricServicePartitionClient myServicePartitionClient = new FabricServicePartitionClient<MyCommunicationClient>(
    this.myCommunicationClientFactory,
    this.myServiceUri,
    myPartitionKey);

CompletableFuture<?> result = myServicePartitionClient.invokeWithRetryAsync(client -> {
      /* Communicate with the service using the client.
       */
   });

Sonraki adımlar