Mikro hizmetler tasarlama: Alma ve iş akışıDesigning microservices: Ingestion and workflow

Mikro hizmetler, birden fazla hizmet için tek bir işlem yayılan iş akışı genellikle sahiptir.Microservices often have a workflow that spans multiple services for a single transaction. İş akışı güvenilir olması gerekir; işlem kaybeder veya bunları kısmen tamamlanmış durumda bırakın.The workflow must be reliable; it can't lose transactions or leave them in a partially completed state. Gelen istekleri alma oranını denetlemek için önemlidir.It's also critical to control the ingestion rate of incoming requests. Birbiriyle iletişim çok sayıda küçük hizmetiyle hizmetin iletişim gelen isteklerin çok sık zora sokar.With many small services communicating with each other, a burst of incoming requests can overwhelm the interservice communication.

Alımı iş akışı diyagramı

İnsansız hava aracı ile teslimat iş akışıThe drone delivery workflow

İnsansız hava aracı ile teslimat uygulaması içinde bir dağıtım zamanlamak için aşağıdaki işlemleri gerçekleştirilmelidir:In the Drone Delivery application, the following operations must be performed to schedule a delivery:

  1. Müşteri hesabı (hesap hizmet) durumunu denetleyin.Check the status of the customer's account (Account service).
  2. Yeni bir paket varlık (hizmet paketi) oluşturun.Create a new package entity (Package service).
  3. Herhangi bir üçüncü taraf taşıma Bu teslim için gerekli olup olmadığını onay alma ve teslim konumlara (üçüncü taraf taşıma hizmeti) bağlı.Check whether any third-party transportation is required for this delivery, based on the pickup and delivery locations (Third-party Transportation service).
  4. (İnsansız hava Aracı hizmeti) ile ilgili bir insansız hava aracı zamanlayın.Schedule a drone for pickup (Drone service).
  5. Yeni bir teslim varlık (teslim hizmeti) oluşturun.Create a new delivery entity (Delivery service).

Uçtan uca işlem yüksek performanslı de olarak güvenilir olması gerekir tüm uygulama setinin budur.This is the core of the entire application, so the end-to-end process must be performant as well as reliable. Belirli bazı zorluklar ele alınması gerekir:Some particular challenges must be addressed:

  • Yük Dengeleme.Load leveling. Çok sayıda istemci istekleri, hizmetin ağ trafiğini sistemiyle sık zora sokar.Too many client requests can overwhelm the system with interservice network traffic. Ayrıca, depolama veya uzak Hizmetleri gibi arka uç bağımlılıkları da sokabilir.It can also overwhelm backend dependencies such as storage or remote services. Bu, bunları sistemdeki backpressure oluşturma çağırma Hizmetleri kısıtlanarak tepki.These may react by throttling the services calling them, creating backpressure in the system. Bu nedenle, yük düzeyi bir arabellek veya işleme için sıraya koyarak sisteme, gelen istekler önemlidir.Therefore, it's important to load level the requests coming into the system, by putting them into a buffer or queue for processing.

  • Teslimi garanti.Guaranteed delivery. Herhangi bir istemci isteğinin bırakmayı önlemek için alımı bileşen iletileri en az bir kez teslim güvence altına almalıdır.To avoid dropping any client requests, the ingestion component must guarantee at-least-once delivery of messages.

  • Hata işleme.Error handling. Hizmetlerden herhangi biri bir hata kodu döndürür ya da geçici olmayan bir hatayla karşılaştığında, teslim zamanlanamaz.If any of the services returns an error code or experiences a non-transient failure, the delivery cannot be scheduled. Bir hata kodu, beklenen hata koşulu olduğunu gösteriyor olabilir (örneğin, müşterinin hesap askıya alındı) veya bir beklenmeyen sunucu hatası (HTTP 5xx).An error code might indicate an expected error condition (for example, the customer's account is suspended) or an unexpected server error (HTTP 5xx). Hizmet kullanılamıyor, ağ çağrısı zaman aşımına neden olabilir.A service might also be unavailable, causing the network call to time out.

İlk denklemi alma tarafında atacağız — sistem üretilen yüksek iş düzeylerinde gelen kullanıcı isteklerinin nasıl alabilen.First we'll look at the ingestion side of the equation — how the system can ingest incoming user requests at high throughput. Ardından insansız hava aracı ile teslimat uygulaması güvenilir bir iş akışının nasıl uygulayacağınıza dair yapabiliriz.Then we'll consider how the drone delivery application can implement a reliable workflow. Bu alma alt sisteminin tasarımı iş akışı arka uç etkiler ettik.It turns out that the design of the ingestion subsystem affects the workflow backend.

AlmaIngestion

Geliştirme ekibi, iş gereksinimlerinize bağlı olarak, aşağıdaki işlevsel olmayan gereksinimleri alımı için tanımlanan:Based on business requirements, the development team identified the following non-functional requirements for ingestion:

  • 10 bin İsteği/sn kesintisiz aktarım hızı.Sustained throughput of 10K requests/sec.
  • İstemci istekleri bırakmayı veya zaman aşımına uğruyor olmadan en fazla 50 bin/sn ani değişiklikleri işlemek kullanabilirsiniz.Able to handle spikes of up to 50K/sec without dropping client requests or timing out.
  • ' Den az 99. yüzdebirlik dilimde 500ms gecikme süresi.Less than 500ms latency in the 99th percentile.

Gereksinim ara sıra ani trafik işlemek için bir tasarım challenge sunar.The requirement to handle occasional spikes in traffic presents a design challenge. Teorik olarak, sistemin en fazla beklenen trafiği işlemeye ölçeği.In theory, the system could be scaled out to handle the maximum expected traffic. Ancak, birçok kaynak çok verimsiz olması sağlanıyor.However, provisioning that many resources would be very inefficient. Olacaktır için boşta çekirdek, çoğu zaman, uygulama o kadar kapasite değeri eklemeden maliyetlendirme para gerekli değildir.Most of the time, the application will not need that much capacity, so there would be idle cores, costing money without adding value.

Daha iyi bir yaklaşım, gelen istekleri bir arabelleğe yerleştirin ve yük Mobil yükleme rampası davranan bir arabellek sağlar oluşturmaktır.A better approach is to put the incoming requests into a buffer, and let the buffer act as a load leveler. Bu tasarım ile alma hizmeti en yüksek alma hızı kısa süreler boyunca işleyebilir olması gerekir, ancak arka uç Hizmetleri yalnızca en fazla uzun süreli yük işlemeniz gereken.With this design, the Ingestion service must be able to handle the maximum ingestion rate over short periods, but the backend services only need to handle the maximum sustained load. Ön uçta arabelleğe alma büyük ani trafik işlemek arka uç Hizmetleri değişmeyecek.By buffering at the front end, the backend services shouldn't need to handle large spikes in traffic. İnsansız hava aracı ile teslimat uygulaması için gerekli olan ölçekte Azure Event Hubs Yük Dengeleme için iyi bir seçimdir.At the scale required for the Drone Delivery application, Azure Event Hubs is a good choice for load leveling. Event Hubs, düşük gecikme ve yüksek performans sunar ve yüksek alma birimleri en uygun maliyetli bir çözümdür.Event Hubs offers low latency and high throughput, and is a cost effective solution at high ingestion volumes.

Bizim test etmek için bir standart katman olay hub'ı üretilen iş birimleri 100 ve 32 bölümlü ile kullandık.For our testing, we used a Standard tier event hub with 32 partitions and 100 throughput units. Gözlemledik yaklaşık 32 bin olay / saniye alımı, 90ms geçici gecikme süresi.We observed about 32K events / second ingestion, with latency around 90ms. Şu anda varsayılan sınırı 20 üretilen iş birimleri, ancak Azure müşterileri, bir destek isteği göndererek ek üretilen iş birimi isteyebilirsiniz.Currently the default limit is 20 throughput units, but Azure customers can request additional throughput units by filing a support request. Bkz: Event Hubs kotaları daha fazla bilgi için.See Event Hubs quotas for more information. Bu nedenle bu numaraları ile tüm performans ölçümlerinin, performans, ileti yükü boyutu gibi birçok faktöre etkileyebilir olarak zamanlılık yorumlar yok.As with all performance metrics, many factors can affect performance, such as message payload size, so don't interpret these numbers as a benchmark. Daha fazla aktarım hızı gerekirse alma hizmetidir parça birden fazla olay hub'ı arasında olabilir.If more throughput is needed, the Ingestion service can shard across more than one event hub. Daha yüksek aktarım hızı ücretleri Event Hubs Dedicated giriş yapabilir tek kiracılı dağıtımları sunar saniye başına 2 milyon olay.For even higher throughput rates, Event Hubs Dedicated offers single-tenant deployments that can ingress over 2 million events per second.

Event hubs'ı nasıl gibi yüksek aktarım hızı elde edebilirsiniz, istemcinin Event hubs'dan iletilerin nasıl tüketmesi gereken etkilediği anlamak önemlidir.It's important to understand how Event Hubs can achieve such high throughput, because that affects how a client should consume messages from Event Hubs. Event hubs'ı uygulamıyor bir kuyruk.Event Hubs does not implement a queue. Bunun yerine, bunu uygulayan bir olay akışının.Rather, it implements an event stream.

Bir kuyruk aracılığıyla tek bir tüketici kuyruktan bir ileti kaldırabilir ve sonraki tüketici bu iletiyi görmezsiniz.With a queue, an individual consumer can remove a message from the queue, and the next consumer won't see that message. Kuyruklar bu nedenle izin kullanmak bir rakip tüketiciler düzeni paralel iletileri işlemek ve ölçeklenebilirliği geliştirmek için.Queues therefore allow you to use a Competing Consumers pattern to process messages in parallel and improve scalability. Daha fazla dayanıklılık için tüketici ileti üzerinde bir kilit tuttuğunda ve bu iletiyi işledikten sonra kilidi serbest bırakır.For greater resiliency, the consumer holds a lock on the message and releases the lock when it's done processing the message. Tüketici başarısız olursa — gibi düğüm çökmeler çalıştığı — kilidi zaman aşımına uğrar ve bir ileti kuyruğuna döner.If the consumer fails — for example, the node it's running on crashes — the lock times out and the message goes back onto the queue.

Kuyruk semantiği diyagramı

Event Hubs, diğer taraftan, akış semantiğini kullanır.Event Hubs, on the other hand, uses streaming semantics. Tüketiciler birbirinden bağımsız olarak kendi hızlarında akış okuyun.Consumers read the stream independently at their own pace. Her tüketici, akışın bulunduğu konumunda izlemek için sorumludur.Each consumer is responsible for keeping track of its current position in the stream. Bir tüketici geçerli konumuna kalıcı depolama için bazı önceden tanımlı aralıklarla yazmanız gerekir.A consumer should write its current position to persistent storage at some predefined interval. Tüketici (örneğin, tüketici kilitlenme veya konak başarısız) bir hata oluşursa, bu şekilde, daha sonra yeni bir örneğini son kaydedilen konumundan akışı okuma devam edebilir.That way, if the consumer experiences a fault (for example, the consumer crashes, or the host fails), then a new instance can resume reading the stream from the last recorded position. Bu işlem çağrılırken denetim noktası.This process is called checkpointing.

Performansla ilgili nedenlerden dolayı bir tüketici her ileti sonra denetim noktası genellikle değil.For performance reasons, a consumer generally doesn't checkpoint after each message. Bunun yerine, bu işleme sonra Örneğin bazı sabit aralık noktalarında n iletileri ya da her n saniye.Instead, it checkpoints at some fixed interval, for example after processing n messages, or every n seconds. Bir tüketici başarısız olursa, yeni bir örneği her zaman son denetim noktasından alır çünkü sonuç olarak, bazı olaylar iki kez işlenir.As a consequence, if a consumer fails, some events may get processed twice, because a new instance always picks up from the last checkpoint. Bir dengeleme vardır: Sık sık kontrol noktaları performansı olumsuz etkileyebilir, ancak bir hatadan sonra daha fazla olay tekrarlar seyrek kontrol noktaları anlamına gelir.There is a tradeoff: Frequent checkpoints can hurt performance, but sparse checkpoints mean you will replay more events after a failure.

Akış semantiği diyagramı

Event Hubs değil rakip Tüketiciler için tasarlanmıştır.Event Hubs is not designed for competing consumers. Bir akışa birden fazla tüketici okuyabilirsiniz, ancak her akış bağımsız olarak erişir.Although multiple consumers can read a stream, each traverses the stream independently. Bunun yerine, Event Hubs bölünmüş bir tüketici modeli kullanır.Instead, Event Hubs uses a partitioned consumer pattern. Bir olay hub'ı 32 adede kadar bölümü vardır.An event hub has up to 32 partitions. Yatay Ölçek, her bölüm için ayrı bir tüketici atanarak elde edilir.Horizontal scale is achieved by assigning a separate consumer to each partition.

Bu insansız hava aracı ile teslimat iş akışı için anlamı nedir?What does this mean for the drone delivery workflow? Event Hubs'ın tam faydalanmak için teslim Zamanlayıcı sonraki taşımadan önce işlenecek her ileti için sabırsızlanıyoruz.To get the full benefit of Event Hubs, the Delivery Scheduler cannot wait for each message to be processed before moving onto the next. Bunu yapar, çoğu ağ çağrıları için bekleyen, zaman geçirir.If it does that, it will spend most of its time waiting for network calls to complete. Bunun yerine, iletileri paralel arka uç Hizmetleri için zaman uyumsuz çağrıları kullanarak, toplu işlem gerekir.Instead, it needs to process batches of messages in parallel, using asynchronous calls to the backend services. Anlatıldığı gibi doğru bir denetim noktası oluşturma stratejisi seçme da önemlidir.As we'll see, choosing the right checkpointing strategy is also important.

İş akışıWorkflow

Okuma ve iletileri işlemek için üç seçeneği inceledik: Olay işleyicisi ana bilgisayarı, Service Bus kuyrukları ve Iothub React kitaplığı.We looked at three options for reading and processing the messages: Event Processor Host, Service Bus queues, and the IoTHub React library. Iothub React seçtik ancak nedenini anlamak için olay işlemcisi konağı ile başlamaya yardımcı olur.We chose IoTHub React, but to understand why, it helps to start with Event Processor Host.

Olay İşlemcisi KonağıEvent Processor Host

Olay işlemcisi konağı toplu ileti işleme için tasarlanmıştır.Event Processor Host is designed for message batching. Uygulama uygular IEventProcessor arabirimi ve işlemcisi konağı olay hub'ında her bölüm için bir olay işlemcisi örneği oluşturur.The application implements the IEventProcessor interface, and the Processor Host creates one event processor instance for each partition in the event hub. Olay işlemcisi konağı sonra her olay işlemcinin çağıran ProcessEventsAsync olay iletileri toplu yöntemiyle.The Event Processor Host then calls each event processor's ProcessEventsAsync method with batches of event messages. Uygulama Denetimleri denetim noktasına içinde olduğunda ProcessEventsAsync yöntemi ve Event Processor Host Azure depolamaya kontrol noktalarını yazar.The application controls when to checkpoint inside the ProcessEventsAsync method, and the Event Processor Host writes the checkpoints to Azure storage.

Olay işlemcisi konağı bir bölüm içinde bekler ProcessEventsAsync sonraki batch'le çağırmadan önce dönün.Within a partition, Event Processor Host waits for ProcessEventsAsync to return before calling again with the next batch. Olay işleme kodunuzu yeniden girilen olması gerekmez çünkü bu yaklaşım programlama modeli basitleştirir.This approach simplifies the programming model, because your event processing code doesn't need to be reentrant. Ancak, bu da olay işleyicisi, aynı anda tek bir toplu işler ve bu işlemcisi konağı iletileri pompa hız Gates'ten anlamına gelir.However, it also means that the event processor handles one batch at a time, and this gates the speed at which the Processor Host can pump messages.

Not

İşlemci konak gerçekten değil bekleyin anlamında bir iş parçacığını engelleme.The Processor Host doesn't actually wait in the sense of blocking a thread. ProcessEventsAsync Yöntemi olduğundan zaman uyumsuz yöntemi tamamladığını sırada işlemcisi konağı diğer işlerinizi yapabilirsiniz.The ProcessEventsAsync method is asynchronous, so the Processor Host can do other work while the method is completing. Ancak yöntem dönene kadar başka bir toplu iletiler bölümü için teslim olmaz.But it won't deliver another batch of messages for that partition until the method returns.

İnsansız hava aracı uygulamasında toplu iletiler paralel olarak işlenebilir.In the drone application, a batch of messages can be processed in parallel. Ancak tüm batch tamamlanması bekleniyor hala bir performans sorununa neden olabilir.But waiting for the whole batch to complete can still cause a bottleneck. İşleme yalnızca bir toplu iş içinde en yavaş iletisi olarak hızlı olabilir.Processing can only be as fast as the slowest message within a batch. Yanıt süreleri herhangi bir varyasyonu "Burada birkaç yavaş yanıtlar tüm sistemin çökmesine sürükleyin uzun bir kuyruğu," oluşturabilirsiniz.Any variation in response times can create a "long tail," where a few slow responses drag down the entire system. Biz bu yaklaşımı kullanarak bizim hedef performans sağlamak değil, performans testlerimizin gösterdi.Our performance tests showed that we did not achieve our target throughput using this approach. Bunu yapar değil ortalama olay işleyicisi ana bilgisayarı kullanmaktan kaçınmanız gerekir.This does not mean that you should avoid using Event Processor Host. Ancak yüksek aktarım hızı için herhangi bir uzun soluklu görevlerin içinde önlemek ProcesssEventsAsync yöntemi.But for high throughput, avoid doing any long-running tasks inside the ProcesssEventsAsync method. Her toplu işin hızlı bir şekilde işleyin.Process each batch quickly.

Iothub ReactIotHub React

Iothub React olayları olay Hub'ından okumak için bir Akka akış kitaplığı.IotHub React is an Akka Streams library for reading events from Event Hub. Akka akışları uygulayan bir akış tabanlı programlama çerçevesi olan reaktif akışları belirtimi.Akka Streams is a stream-based programming framework that implements the Reactive Streams specification. Burada tüm akış işlemler zaman uyumsuz olarak gerçekleştirilir ve işlem hattı backpressure düzgün bir şekilde işleme verimli akış işlem hatlarını oluşturmak için bir yol sunar.It provides a way to build efficient streaming pipelines, where all streaming operations are performed asynchronously, and the pipeline gracefully handles backpressure. Olay kaynağı olayları aşağı akış tüketiciler aldığınız daha hızlı bir oranda üretir backpressure oluşur — olduğu durum tam olarak insansız hava aracı ile teslimat sistem bir ani trafik sahip olduğunda.Backpressure occurs when an event source produces events at a faster rate than the downstream consumers can receive them — which is exactly the situation when the drone delivery system has a spike in traffic. Arka uç Hizmetleri daha yavaş giderseniz, React IoTHub yavaşlatır.If backend services go slower, IoTHub React will slow down. Kapasite artırılırsa IoTHub React #ardışık düzen aracılığıyla daha fazla ileti gönderir.If capacity is increased, IoTHub React will push more messages through the pipeline.

Ayrıca olayları Event hubs'dan akış için çok doğal bir programlama modeli Akka akışları olur.Akka Streams is also a very natural programming model for streaming events from Event Hubs. Olayların toplu işlem ile döngü yerine bir dizi, her olay için uygulanır ve akış işleme Akka akışları izin işlemlerini tanımlayın.Instead of looping through a batch of events, you define a set of operations that will be applied to each event, and let Akka Streams handle the streaming. Bir akış işlem hattının açısından Akka akışlar tanımlar kaynakları, akışları, ve havuzlarını.Akka Streams defines a streaming pipeline in terms of Sources, Flows, and Sinks. Bir çıkış akışına bir kaynak oluşturur, akış, bir giriş akışı işler ve bir çıkış akışı oluşturur ve herhangi bir çıktı üretmeden bir akışa bir havuz kullanır.A source generates an output stream, a flow processes an input stream and produces an output stream, and a sink consumes a stream without producing any output.

Akka akışları işlem hattı ayarlar Zamanlayıcı hizmeti kod şöyledir:Here is the code in the Scheduler service that sets up the Akka Streams pipeline:

IoTHub iotHub = new IoTHub();
Source<MessageFromDevice, NotUsed> messages = iotHub.source(options);

messages.map(msg -> DeliveryRequestEventProcessor.parseDeliveryRequest(msg))
        .filter(ad -> ad.getDelivery() != null).via(deliveryProcessor()).to(iotHub.checkpointSink())
        .run(streamMaterializer);

Bu kod, Event Hubs kaynağı olarak yapılandırır.This code configures Event Hubs as a source. map Deyimi bir teslim isteğini temsil eder bir Java sınıfı her olay iletisi çıkarır.The map statement deserializes each event message into a Java class that represents a delivery request. filter Deyimi kaldırır null nesneleri akışından; burada bir ileti seri durumdan çıkarılamaz durumda karşı bu cf.The filter statement removes any null objects from the stream; this guards against the case where a message can't be deserialized. via Deyimi her teslim isteği işleyen bir akış kaynağı birleştirir.The via statement joins the source to a flow that processes each delivery request. to Yöntemi IoTHub React yerleşik denetim noktası havuza akışı birleştirir.The to method joins the flow to the checkpoint sink, which is built into IoTHub React.

Iothub React bir olay ana bilgisayarı işlemcisi'dan farklı bir denetim noktası oluşturma stratejisi kullanır.IoTHub React uses a different checkpointing strategy than Event Host Processor. Kontrol noktaları, işlem hattı Sonlandırıcı aşamasında olan denetim noktası havuz tarafından yazılır.Checkpoints are written by the checkpoint sink, which is the terminating stage in the pipeline. Havuz denetim noktası yazarken veri akışı devam etmek işlem hattı tasarım Akka akışları sağlar.The design of Akka Streams allows the pipeline to continue streaming data while the sink is writing the checkpoint. Yukarı Akış işleme aşamalarını denetim noktası oluşturma gerçekleşecek beklemeniz gerekmez anlamına gelir.That means the upstream processing stages don't need to wait for checkpointing to happen. Denetim noktası oluşturma bir zaman aşımından sonra veya belirli sayıda ileti işlendikten sonra gerçekleşecek şekilde yapılandırabilirsiniz.You can configure checkpointing to occur after a timeout or after a certain number of messages have been processed.

deliveryProcessor Yöntemi Akka akışları akış oluşturur:The deliveryProcessor method creates the Akka Streams flow:

private static Flow<AkkaDelivery, MessageFromDevice, NotUsed> deliveryProcessor() {
    return Flow.of(AkkaDelivery.class).map(delivery -> {
        CompletableFuture<DeliverySchedule> completableSchedule = DeliveryRequestEventProcessor
                .processDeliveryRequestAsync(delivery.getDelivery(),
                        delivery.getMessageFromDevice().properties());

        completableSchedule.whenComplete((deliverySchedule,error) -> {
            if (error!=null){
                Log.info("failed delivery" + error.getStackTrace());
            }
            else{
                Log.info("Completed Delivery",deliverySchedule.toString());
            }

        });
        completableSchedule = null;
        return delivery.getMessageFromDevice();
    });
}

Statik bir akışı çağırır processDeliveryRequestAsync her ileti işleme asıl işi yapan yöntemi.The flow calls a static processDeliveryRequestAsync method that does the actual work of processing each message.

Iothub React ile ölçeklendirmeScaling with IoTHub React

Her kapsayıcı örneği tek bir bölümün dışında okunması Zamanlayıcı hizmeti tasarlanmıştır.The Scheduler service is designed so that each container instance reads from a single partition. Örneğin, olay hub'ı 32 bölümlü varsa, Zamanlayıcı hizmeti 32 çoğaltma ile dağıtılır.For example, if the Event Hub has 32 partitions, the Scheduler service is deployed with 32 replicas. Bu büyük bir yatay ölçeklendirme açısından esneklik sağlar.This allows for a lot of flexibility in terms of horizontal scaling.

Küme boyutuna bağlı olarak, kümedeki bir düğüm üzerinde çalışan birden fazla Zamanlayıcı hizmeti pod olabilir.Depending on the size of the cluster, a node in the cluster might have more than one Scheduler service pod running on it. Ancak, Zamanlayıcı hizmeti daha fazla kaynak gerektiriyorsa, küme, pod'ları arasında daha fazla düğüm dağıtılabilmesi için genişletilebilir.But if the Scheduler service needs more resources, the cluster can be scaled out, in order to distribute the pods across more nodes. Yaptığımız performans testleri, VM boyutunu ve düğüm başına pod'ların sayısını önemli ölçüde performans hazırlanması için bellek ve iş parçacığı-sınırlıdır, Zamanlayıcı hizmeti olduğunu gösterdi.Our performance tests showed that the Scheduler service is memory- and thread-bound, so performance depended greatly on the VM size and the number of pods per node.

Her örnek, hangi okumak için Event Hubs'ı bölüm bilmesi gerekir.Each instance needs to know which Event Hubs partition to read from. Avantajlarından attığımız bölüm numarası yapılandırmak için StatefulSet kubernetes kaynak türü.To configure the partition number, we took advantage of the StatefulSet resource type in Kubernetes. Bir StatefulSet pod'ların, sayısal dizin içeren kalıcı bir tanımlayıcıya sahip.Pods in a StatefulSet have a persistent identifier that includes a numeric index. Özellikle, pod addır <statefulset name>-<index>, ve bu değer Kubernetes ile kapsayıcı kullanılabilir aşağı API.Specifically, the pod name is <statefulset name>-<index>, and this value is available to the container through the Kubernetes Downward API. Çalışma zamanında, Zamanlayıcı hizmetleri pod adını okur ve pod dizini bölüm kimliğini kullanır.At run time, the Scheduler services reads the pod name and uses the pod index as the partition ID.

Daha da Zamanlayıcı hizmetin ölçeğini genişletin açmanız gerekiyorsa, birden çok podunuz her bölüm okuyorsanız, olay hub'ı bölüm başına birden fazla pod atayabilirsiniz.If you needed to scale out the Scheduler service even further, you could assign more than one pod per event hub partition, so that multiple pods are reading each partition. Ancak, bu durumda, her bir örnek atanmış bir bölüme olayların tümünü okumayı tercih ederim.However, in that case, each instance would read all of the events in the assigned partition. Böylece her örneği bir iletiler bölümü atlar yinelenen işleme engel olmak için bir karma algoritmasını kullanmanız gerekir.To avoid duplicate processing, you would need to use a hashing algorithm, so that each instance skips over a portion of the messages. Bu şekilde, birden fazla okuyucuyu kapsayacak akış kullanabilir, ancak her ileti yalnızca bir örneği tarafından işlenir.That way, multiple readers can consume the stream, but every message is processed by only one instance.

Olay hub'ı karma bir diyagramı

Service Bus kuyruklarıService Bus queues

Bir Service Bus kuyruğuna iletiler Event Hubs'dan kopyalamak dikkate üçüncü bir seçenek olan ve Zamanlayıcı hizmeti Service Bus iletileri okuyun sahip.A third option that we considered was to copy messages from Event Hubs into a Service Bus queue, and then have the Scheduler service read the messages from Service Bus. Yalnızca Service Bus kopyalamak için Event hubs'ta de gelen isteklerin yazmaya garip görünebilir.It might seem strange to writing the incoming requests into Event Hubs only to copy them in Service Bus. Ancak, her hizmet farklı güçlerini yararlanmak için fikir şöyleydi: Bir rakip tüketiciler düzeni ile bir iş yükünü işlemek için hizmet veri yolu kuyruğu semantiği avantajlarından çekerken yoğun trafik artışlarını devralarak için Event Hubs'ı kullanın.However, the idea was to leverage the different strengths of each service: Use Event Hubs to absorb spikes of heavy traffic, while taking advantage of the queue semantics in Service Bus to process the workload with a competing consumers pattern. Hedefimiz kesintisiz aktarım hızı için sunduğumuz beklenen en yüksek yük küçüktür, bu nedenle işlem Service Bus kuyruğuna İleti alımı ne kadar hızlı olmasını ihtiyaç duymaz unutmayın.Remember that our target for sustained throughput is less than our expected peak load, so processing the Service Bus queue would not need to be as fast the message ingestion.

Bu yaklaşımda, kavram kanıtı kararlılığımızın saniye başına işlem yaklaşık 4 K elde edebilirsiniz.With this approach, our proof-of-concept implementation achieved about 4K operations per second. Bu testler, herhangi bir gerçek iş değildir, ancak yalnızca hizmet başına gecikme süresi sabit bir miktarda eklenen sahte arka uç Hizmetleri kullanılır.These tests used mock backend services that did not do any real work, but simply added a fixed amount of latency per service. Performans rakamlarına ulaşmak bizim için hizmet veri Yolu'na teorik en çok küçüktür olduğunu unutmayın.Note that our performance numbers were much less than the theoretical maximum for Service Bus. Uyumsuzluk için olası nedenler şunlardır:Possible reasons for the discrepancy include:

  • Bağlantı havuzu sınırı, paralelleştirme, önceden getirme sayısı ve toplu iş boyutu derecesi gibi çeşitli istemci parametreleri için en iyi değerlerine sahip değil.Not having optimal values for various client parameters, such as the connection pool limit, the degree of parallelization, the prefetch count, and the batch size.

  • Ağ g/ç performans sorunları.Network I/O bottlenecks.

  • Kullanım PeekLock modu yerine ReceiveAndDelete, en az bir kez İleti teslimini sağlamak için gerekli olmuştur.Use of PeekLock mode rather than ReceiveAndDelete, which was needed to ensure at-least-once delivery of messages.

Daha fazla performans testleri kök nedenin bulunması ve bu sorunları çözmek bize izin.Further performance tests might have discovered the root cause and allowed us to resolve these issues. Ancak, IotHub tepki vermek için bu seçeneği seçtik performans Hedefimiz karşılaştı.However, IotHub React met our performance target, so we chose that option. Bu, Service Bus bu senaryo için uygun bir seçenek olduğunu belirtti.That said, Service Bus is a viable option for this scenario.

Hataları işlemeHandling failures

Dikkate alınması gereken hata genel üç sınıfı vardır.There are three general classes of failure to consider.

  1. Bir aşağı akış hizmetinin kendisi tarafından azalttıktan düşüktür herhangi bir hata olduğundan geçici olmayan bir hata olabilir.A downstream service may have a non-transient failure, which is any failure that's unlikely to go away by itself. Geçici olmayan hatalar gibi bir yöntem için geçersiz giriş normal hata koşulları içerir.Non-transient failures include normal error conditions, such as invalid input to a method. Ayrıca işlenmeyen özel durumlar uygulama kodu veya kilitlenme işlem içerirler.They also include unhandled exceptions in application code or a process crashing. Bu tür bir hata oluşursa, tüm iş işlem hata olarak işaretlenmesi gerekir.If this type of error occurs, the entire business transaction must be marked as a failure. Diğer adımları zaten başarılı oldu aynı işlemde geri alınması gerekli olabilir.It may be necessary to undo other steps in the same transaction that already succeeded. (Telafi işlemleri, aşağıya bakın.)(See Compensating Transactions, below.)

  2. Bir aşağı akış hizmeti, ağ zaman aşımı gibi geçici bir hatayla karşılaşabilir.A downstream service may experience a transient failure such as a network timeout. Bu hatalar genellikle çağrı denenerek çözülebilir.These errors can often be resolved simply by retrying the call. İşlem, belirli sayıda girişimden sonra yine başarısız olursa, geçici olmayan hata dikkate almıştır.If the operation still fails after a certain number of attempts, it's considered a non-transient failure.

  3. Zamanlayıcı hizmeti (örneğin, bir düğüm kilitleniyor çünkü) hata.The Scheduler service itself might fault (for example, because a node crashes). Bu durumda, Kubernetes hizmetini yeni bir örneğini çıkarır.In that case, Kubernetes will bring up a new instance of the service. Ancak, zaten sürmekte olan işlemler devam ettirildi gerekir.However, any transactions that were already in progress must be resumed.

Telafi işlemleriCompensating transactions

Geçici olmayan başarısız olursa, geçerli işlem olabilir. bir kısmen başarısız durumu, burada bir veya daha fazla adım zaten başarıyla tamamlandı.If a non-transient failure happens, the current transaction might be in a partially failed state, where one or more steps already completed successfully. Örneğin, insansız hava Aracı hizmeti zaten bir insansız hava aracı ile zamanladıysanız insansız hava aracı ile iptal edilmelidir.For example, if the Drone service already scheduled a drone, the drone must be canceled. Bu durumda, kullanarak başarılı adımları geri almak uygulaması gereken bir telafi işlemi.In that case, the application needs to undo the steps that succeeded, by using a Compensating Transaction. Bazı durumlarda, bu dış sisteme veya hatta el ile yapılmalıdır.In some cases, this must be done by an external system or even by a manual process.

Telafi işlemleri için mantığı karmaşıktır, bu işlem için ayrı bir hizmet oluşturma sorumludur göz önünde bulundurun.If the logic for compensating transactions is complex, consider creating a separate service that is responsible for this process. İnsansız hava aracı ile teslimat uygulaması içinde Zamanlayıcı hizmeti başarısız işlemler özel bir sıra üstüne yerleştirir.In the Drone Delivery application, the Scheduler service puts failed operations onto a dedicated queue. Gözetmen adlı ayrı bir mikro hizmet, bu kuyruktaki iletileri okur ve API iptal dengelemek için gereken hizmetleri üzerinde çağırır.A separate microservice, called the Supervisor, reads from this queue and calls a cancellation API on the services that need to compensate. Bu bir çeşididir Zamanlayıcı Aracısı Gözetmeni düzeni.This is a variation of the Scheduler Agent Supervisor pattern. Gözetmen hizmet başka işlemler de yapabilirsiniz, gibi metin ya da e-posta kullanıcıya bildir veya bir işlem panosu için bir uyarı gönderir.The Supervisor service might take other actions as well, such as notify the user by text or email, or send an alert to an operations dashboard.

Gözetmen mikro hizmet gösteren diyagram

Idempotent vs kez etkili olmayan işlemleriIdempotent vs non-idempotent operations

Tüm istekleri kaybetmemek için Zamanlayıcı hizmeti tüm iletileri en az bir kez işlenir etmeleri gerekir.To avoid losing any requests, the Scheduler service must guarantee that all messages are processed at least once. Olay hub'ları, en az bir kez teslim garanti istemci denetim noktaları doğru.Event Hubs can guarantee at-least-once delivery if the client checkpoints correctly.

Zamanlayıcı hizmetine çökerse, bir veya daha fazla istemci isteklerini işleme ortasında olabilir.If the Scheduler service crashes, it may be in the middle of processing one or more client requests. Bu ileti başka bir zamanlayıcı örneği tarafından teslim alındı ve işlenmiş.Those messages will be picked up by another instance of the Scheduler and reprocessed. Bir istek iki kez işlenir ne olur?What happens if a request is processed twice? Herhangi bir iş çoğaltılmasını önlemek önemlidir.It's important to avoid duplicating any work. Sonuçta, size iki dronlarla hayat kurtarma aynı paket göndermek için sistem istemezsiniz.After all, we don't want the system to send two drones for the same package.

Bir kez etkili olması için tüm işlemleri tasarlamak için bir yaklaşımdır.One approach is to design all operations to be idempotent. Bir işlem etkili ise, birden çok kez ilk çağrıdan sonra ek yan etkileri üretmeden volat pouze jednou.An operation is idempotent if it can be called multiple times without producing additional side-effects after the first call. Diğer bir deyişle, bir istemci bir kez, iki kez işlemi ya da birden çok kez çağırabilir ve sonucu aynı olacaktır.In other words, a client can invoke the operation once, twice, or many times, and the result will be the same. Esas olarak, hizmet, yinelenen çağrıları yok saymanız gerekir.Essentially, the service should ignore duplicate calls. Bir kere etkili olacak şekilde yan etkileri olan yöntem için hizmet yinelenen çağrıları algılayabilir olması gerekir.For a method with side effects to be idempotent, the service must be able to detect duplicate calls. Örneğin, arayanın atama kimliği olabilir yerine hizmeti olan yeni bir kimliği oluşturFor example, you can have the caller assign the ID, rather than having the service generate a new ID. Hizmet için yinelenen kimliklerin sonra kontrol edebilirsiniz.The service can then check for duplicate IDs.

Not

HTTP belirtimini GET, PUT ve DELETE metotları etkili olması gerektiğini belirtir.The HTTP specification states that GET, PUT, and DELETE methods must be idempotent. POST yöntemleri kez etkili olması garanti edilmez.POST methods are not guaranteed to be idempotent. POST yöntemi yeni bir kaynak oluşturursa, da genellikle bu işlemi etkilidir garantisi yoktur.If a POST method creates a new resource, there is generally no guarantee that this operation is idempotent.

Her zaman etkili yöntem yazmaktır basit değildir.It's not always straightforward to write idempotent method. Başka bir seçenek dayanıklı bir depoya her işlemin ilerlemesini izlemek Zamanlayıcı için kullanılabilir.Another option is for the Scheduler to track the progress of every transaction in a durable store. İletiyi işleyen olduğunda, dayanıklı depolama durumu görünür.Whenever it processes a message, it would look up the state in the durable store. Her adımdan sonra sonuç depoya yazmalısınız.After each step, it would write the result to the store. Bu yaklaşımın performans etkileri olabilir.There may be performance implications to this approach.

Örnek: Idempotent işlemleriExample: Idempotent operations

HTTP belirtimini bildiren PUT yöntemleri etkili olması gerekir.The HTTP specification states that PUT methods must be idempotent. Belirtimi ıdempotent bu şekilde tanımlar:The specification defines idempotent this way:

İstek yöntemi "etkili" değerlendirilir, bu hedeflenen etkisi, yöntemi ile birden çok aynı istek sunucusunda tek bir etkisi ile aynı olduğunda bu tür istek.A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. (RFC 7231)(RFC 7231)

Yeni bir varlık oluştururken, PUT ve POST semantiği arasındaki farkı anlamak önemlidir.It's important to understand the difference between PUT and POST semantics when creating a new entity. Her iki durumda da istemci istek gövdesinde bir temsili bir varlık gönderir.In both cases, the client sends a representation of an entity in the request body. Ancak URI anlamı da farklıdır.But the meaning of the URI is different.

  • POST yöntemi için yeni varlık, bir koleksiyon gibi bir üst Kaynak URI temsil eder.For a POST method, the URI represents a parent resource of the new entity, such as a collection. Örneğin, yeni teslimat oluşturmak için URI olabilir /api/deliveries.For example, to create a new delivery, the URI might be /api/deliveries. Sunucu varlığı oluşturur ve gibi yeni bir URI atar /api/deliveries/39660.The server creates the entity and assigns it a new URI, such as /api/deliveries/39660. Bu URI, yanıtın Location üst döndürülür.This URI is returned in the Location header of the response. İstemci bir istek gönderir. her zaman yeni bir URI'ya yeni bir varlık sunucusu oluşturun.Each time the client sends a request, the server will create a new entity with a new URI.

  • PUT yöntemi için varlığın URI tanımlar.For a PUT method, the URI identifies the entity. Bu URI'ye sahip bir varlık zaten mevcut değilse sunucu var olan bir varlığa isteğinde sürümüyle değiştirir.If there already exists an entity with that URI, the server replaces the existing entity with the version in the request. Varlık ile bu URI varsa, bir sunucu oluşturur.If no entity exists with that URI, the server creates one. Örneğin, istemci bir PUT İsteği varsayalım api/deliveries/39660.For example, suppose the client sends a PUT request to api/deliveries/39660. Hiçbir teslim bu URI'ye sahip olduğu varsayıldığında, yeni bir sunucu oluşturur.Assuming there is no delivery with that URI, the server creates a new one. Artık sunucu istemci yeniden aynı istek gönderirse, var olan bir varlığa yerini alır.Now if the client sends the same request again, the server will replace the existing entity.

PUT yöntemini teslim hizmetin uygulaması aşağıda verilmiştir.Here is the Delivery service's implementation of the PUT method.

[HttpPut("{id}")]
[ProducesResponseType(typeof(Delivery), 201)]
[ProducesResponseType(typeof(void), 204)]
public async Task<IActionResult> Put([FromBody]Delivery delivery, string id)
{
    logger.LogInformation("In Put action with delivery {Id}: {@DeliveryInfo}", id, delivery.ToLogInfo());
    try
    {
        var internalDelivery = delivery.ToInternal();

        // Create the new delivery entity.
        await deliveryRepository.CreateAsync(internalDelivery);

        // Create a delivery status event.
        var deliveryStatusEvent = new DeliveryStatusEvent { DeliveryId = delivery.Id, Stage = DeliveryEventType.Created };
        await deliveryStatusEventRepository.AddAsync(deliveryStatusEvent);

        // Return HTTP 201 (Created)
        return CreatedAtRoute("GetDelivery", new { id= delivery.Id }, delivery);
    }
    catch (DuplicateResourceException)
    {
        // This method is mainly used to create deliveries. If the delivery already exists then update it.
        logger.LogInformation("Updating resource with delivery id: {DeliveryId}", id);

        var internalDelivery = delivery.ToInternal();
        await deliveryRepository.UpdateAsync(id, internalDelivery);

        // Return HTTP 204 (No Content)
        return NoContent();
    }
}

En çok istekte açıklamayı kaçırmadığından yöntemi çağıran için yeni bir varlık oluşturur beklenir CreateAsync depo nesnesindeki ve ardından kaynak güncelleştirerek yinelenen kaynak özel durumları işler.It's expected that most requests will create a new entity, so the method optimistically calls CreateAsync on the repository object, and then handles any duplicate-resource exceptions by updating the resource instead.