reactive streams與觀察者模式

go4it發表於2018-01-12

本文主要研究下java裡頭的reactive streams與觀察者模式。

reactive streams

reactive程式設計正規化是一個非同步程式設計正規化,主要涉及資料流及變化的傳播,可以看做是觀察者設計模式的擴充套件。

java裡頭的iterator是以pull模型,即訂閱者使用next去拉取下一個資料;而reactive streams則是以push模型為主,訂閱者呼叫subscribe方法訂閱,釋出者呼叫訂閱者的onNext通知訂閱者新訊息。

reactive streams java api

reactive streams定義了4個java api,如下

Processor<T,R>

processor既是Subscriber也是Publisher,代表二者的處理階段

Publisher

publisher是資料的提供者, 將資料釋出給訂閱者

Subscriber

在呼叫Publisher.subscribe(Subscriber)之後,Subscriber.onSubscribe(Subscription)將會被呼叫

Subscription

Subscription代表訂閱者與釋出者的一次訂閱週期,一旦呼叫cancel去掉訂閱,則釋出者不會再推送訊息。

觀察者模式

reactive streams與觀察者模式

觀察者模式的實現有推模型和拉模型

  • 拉模型

即釋出者通知訂閱有新訊息,訂閱者再去找釋出者拉取

  • 推模型

即釋出者通知訂閱者有訊息,通知的時候已經帶上了一個新訊息

reactor例項

maven

		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-core</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>
複製程式碼

reactor 3 是java裡頭reactive streams的一個實現,基於reactive streams的java api,是spring 5反應式程式設計的基礎。

Flux例項

    @Test
    public void testBackpressure(){
        Flux.just(1, 2, 3, 4)
                .log()
                .subscribe(new Subscriber<Integer>() {
                    private Subscription s;
                    int onNextAmount;

                    @Override
                    public void onSubscribe(Subscription s) {
                        this.s = s;
                        s.request(2);
                    }

                    @Override
                    public void onNext(Integer integer) {
                        System.out.println(integer);
                        onNextAmount++;
                        if (onNextAmount % 2 == 0) {
                            s.request(2);
                        }
                    }

                    @Override
                    public void onError(Throwable t) {}

                    @Override
                    public void onComplete() {}
                });

        try {
            Thread.sleep(10*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
複製程式碼

小結

從上面的程式碼看,reactive streams實際上是推拉結合的模式的結合。為什麼還要拉呢?

rabbitmq vs kafka

rabbitmq是以推為主的,如果消費者消費能力跟不上,則訊息會堆積在記憶體佇列中(必要時可能寫磁碟)

kafka則是以拉為主的,生產者推送訊息到broker,消費者自己根據自己的能力從broker拉取訊息,由於訊息是持久化的,因此無需關心生產消費速率的不平衡

backpressure

backpressure這個是為處理生產速率與消費速率不平衡這個問題而衍生出來的,訂閱者可以在next方法裡頭根據自己的情況,使用request方法告訴釋出者要取N個資料,釋出者則向訂閱者推送N個資料。通過request達到訂閱者對釋出者的反饋。而對於釋出者而言,為了實現backpressure,則需要有一個快取佇列來緩衝訂閱者沒來得及消費的資料。涉及到緩衝,就涉及容量是有界還是無界,如果是有界則在緩衝慢的時候,處理策略是怎樣等等。

doc

相關文章