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ştiriciye 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. Hizmetiniz için 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ürsiniz. 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. 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 koleksiyonu : adres çiftleri, istemci bir hizmet örneği veya bölüm için dinleme adreslerini istediğinde JSON nesnesi olarak temsil edilir.
Durum bilgisi olmayan bir hizmette geçersiz kılma bir ServiceInstanceListeners koleksiyonu döndürür. A ServiceInstanceListener
, oluşturmak ICommunicationListener(C#) / CommunicationListener(Java)
için bir işlev içerir ve buna bir ad verir. Durum bilgisi olan hizmetler için geçersiz kılma bir ServiceReplicaListeners koleksiyonu döndürür. İkincil çoğaltmalarda açma ICommunicationListener
seçeneği olduğundan ServiceReplicaListener
bu durum bilgisi olmayan karşılıklarından biraz farklıdı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 istekleri 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, hizmet bildiriminde uç noktalar bölümündeki 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çinden ona ayrılan uç nokta kaynaklarına CodePackageActivationContext
ServiceContext
erişebilir. Ardından dinleyici, 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 paketi için 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)
Yöntemi ICommunicationListener(C#) / CommunicationListener(Java)
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ümede taşınır. Bu, istemcilerin bir hizmetin dinleme adresini çözümlemesine olanak sağlayan mekanizmadır.
Not
İletişim dinleyicisi yazma hakkında ayrıntılı bilgi için bkz . C# için OWIN kendi kendine barındırması olan Service Fabric Web API hizmetleri, Java için ise kendi HTTP sunucu 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 istemciler yazmak için aşağıdaki kitaplıklar sağlanır.
Hizmet uç noktası çözümlemesi
Bir hizmetle iletişim kurmanın ilk adımı, konuşmak istediğiniz hizmetin bölümünün veya örneğinin uç nokta adresini çözümlemektir. Yardımcı ServicePartitionResolver(C#) / FabricServicePartitionResolver(Java)
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. Örneğin:
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 denetim sahibi 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());
Daha sonra 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 denenebilir (örneğin, hizmet taşındı veya geçici olarak kullanılamıyor) veya kalıcı bir hata (örneğin, hizmet silindi veya istenen kaynak artık yok). Hizmet örnekleri veya çoğaltmaları, birden çok nedenden dolayı herhangi bir zamanda düğümden düğüme geçiş yapabilir. 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. Öncekinin ResolvedServicePartition
sağlanması, çözümleyicinin ö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 deseni uygular. Siz hata işleyicilerini sağlarken fabrika kitaplığı 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'nin 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 bir uygulamasını sağlar ve tüm iletişim yığınları için 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ıyı koruyan diğer protokoller de, bağlantının yeniden oluşturulması gerekip gerekmediğini belirlemek için fabrika tarafından 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, bir özel durum işleyicisi bir özel durum oluştuğunda hangi eylemin gerçekleştireceklerini 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 geçici ve geçici olmayan olarak kategorilere ayrılır.
- Geçici özel durumlar, hizmet uç noktası adresi yeniden çözümlenmeden yalnızca yeniden denenebilen 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, hizmetin farklı bir düğüme taşındığını gösteren hizmet uç noktasına ulaşılamadığını gösteren özel durumları içerir.
belirli TryHandleException
bir özel durumla ilgili bir karar verir. Bir özel durumla ilgili olarak hangi kararların alındığını bilmiyorsa false döndürmelidir. Kararın ne olduğunu biliyorsa sonucu buna göre ayarlamalı ve true 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.
*/
});