11 Kasım 2020 Çarşamba

Back Pressure (BackPressure) Nedir

Giriş
Back Pressure karışık bir konu.

1. Aynı Bellekte Çalışıyorsak
Aynı bellekte çalışıyorsak Back Pressure için kullanılan çözümlerle ilgili notlarım şöyle

1.1 Blocking Back Pressure Nedir - Yazan Tarafın Kuyrukta Bloke Olması
Bu yöntemde Producer bekler. Asenkron çalışmada Producer'ı bekletme şansımız yok. Dolayısıyla "Non-blocking back-pressure" yöntemi kullanılıyor.

1.2. Non-Blocking Back Pressure Nedir - Okuyan Taraf Veriyi Çeker
ReactiveX ise Reactive Manifesto ile ilgili. Reactive Manifesto'nun bir amacı şunu sunmak.
"a standard for asynchronous stream processing with non-blocking back pressure"
Açıklaması şöyle.
If we have a producer which is emitting events to a consumer faster than it can process them, then eventually the consumer will be overwhelmed with events, running out of system resources. Backpressure means that our consumer should be able to tell the producer how much data to send in order to prevent this, and this is what is laid out in the specification.
Producer'ın hızına yetişemeyen Consumer, bir şekilde Producer'a yavaşlaması gerektiğini bildirir. Yani Consumer hazır olduğunda Producer'a kaç tane nesne istediğini söyler. Yani push yöntemi yerine pull yöntemi kullanılır. Producer da elindekileri gönderir.

1.2.1 Back Pressure vs Flow Control
Okuyan tarafın veriyi çekmesi yönteminde haberleşme protokollerindeki "flow control" kavramı ile aynı şeymiş gibi düşünmek başlamayı kolaylaştırıyor.

2. Farklı Bellekte Çalışıyorsak
Back Pressure'ın kötü ele alındığı bir örnek burada. Bu örnekteki normal akış şöyle
Read : 
- The eventloop threads read requests coming off of netty channels and enqueue them into a bounded inbound queue in the Cassandra node.
Process : 
- A thread pool dequeues requests from the inbound queue, processes them asynchronously and enqueues the response into an outbound queue. There exist multiple outbound queues, one for each eventloop thread to avoid races.
Send:
- The same eventloop threads that are responsible for enqueuing incoming requests into the inbound queue, are also responsible for dequeuing responses off from the outbound queue and shipping responses back to the client.
- Yani bir eventloop başına bir Netty Channel ve bir de Outbound kuyruk var. Outbound üst sınıra sahip değil
- Inbound queue tek bir tane ve üst sınıra sahip, yani tüm eventloop'lar için ortak

Sıkıntı şöyle
Eğer Process'in threadler yavaşlarsa eventloop üst sınırı belli (bounded) Inbound kuyruğa yazmak için çok fazla bloke oluyor ve Outbound kuyruğu boşaltmıyor. Açıklaması şöyle
Let us take a scenario where there is a spike in operations from the client. The eventloop threads are now enqueuing requests at a much higher rate than the rate at which the requests are being processed by the native transport thread pool. Eventually, the inbound queue reaches its limit and says it cannot store any more requests in the queue.

Consequently, the eventloop threads get into a blocked state as they try to enqueue more requests into an already full inbound queue. They wait until they can successfully enqueue the request in hand, into the queue.

As noted earlier, these blocked eventloop threads are also supposed to dequeue responses from the outbound queue. Given they are in blocked state, the outbound queue (which is unbounded) grows endlessly, with all the responses, eventually resulting in C* going out of memory. This is a vicious cycle because, since the eventloop threads are blocked, there is no one to ship responses back to the client; eventually client side timeout triggers, and clients may send more requests due to retries. This is an unfortunate situation to be in,...
Çözüm
Inbound kuyruk sınırsız hale getiriliyor ancak bir eşik değer konuluyor. Bu eşik değeri aşınca, sunucu konfigürasyon ayarına göre şu iki seçenekten birini uyguluyor
1. Okuma işlemini bırakır. Burada istemciyi yavaşlatma işi TCP protokolüne bıraklıyor. Açıklaması şöyle
Consequently, the kernel socket inbound buffer becomes full since no bytes are being read off of it by netty eventloop.
Once the Kernel Socket Inbound Buffer is full on the server side, things start getting piled up in the Kernel Socket Outbound Buffer on the client side, and once this buffer gets full, client will start experiencing backpressure.
2. İstemciye bir mesaj gönderir. Açıklaması şöyle
If the inbound queue is full (i.e. the thresholds are met), eventloop threads do not enqueue the request into the Inbound Queue. Instead, the eventloop thread creates an OverloadedException response message and enqueues it into the flusher queue, which will then be shipped back to the client.

Hiç yorum yok:

Yorum Gönder