可觀察性

Spring 透過 Micrometer 提供可觀察性支援,該庫定義了一個 Observation (觀測) 概念,它同時支援 Metrics (指標) 和 Traces (追蹤)

Spring Cloud Stream 在 Spring Cloud Function 層面集成了此支援,它透過提供幾個抽象中的一個 ObservationFunctionAroundWrapper,該包裝器封裝了函式,從而開箱即用地處理觀測。

所需依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
	<groupId>io.projectreactor</groupId>
	<artifactId>reactor-core-micrometer</artifactId>
</dependency>

以及一個可用的追蹤器橋接器。例如 Zipkin Brave

<dependency>
	<groupId>io.micrometer</groupId>
	<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>

命令式函式

命令式函式被觀測包裝器 ObservationFunctionAroundWrapper 封裝,該包裝器提供了處理與 Observation 登錄檔互動所需的基礎設施。此類互動在函式的每次呼叫時發生,這意味著觀測被附加到函式的每次呼叫 (即每條訊息一次觀測)。換句話說,對於命令式函式,如果前面提到的所需依賴存在,可觀察性將直接生效。

響應式函式

響應式函式與命令式函式本質上不同,因此不會被 ObservationFunctionAroundWrapper 封裝。

命令式函式 是一個訊息處理函式,框架在每條訊息到來時都會呼叫它,類似於典型的事件處理器,N 條訊息會觸發 N 次此類函式的呼叫。這允許我們封裝此類函式,為其新增額外功能,例如 錯誤處理重試,當然還有 可觀察性

響應式函式 是初始化函式。它的作用是將使用者提供的流處理程式碼 (Flux) 與 Binder 提供的源和目標流連線起來。它只在應用啟動期間呼叫一次。一旦流程式碼與源/目標流連線,我們就無法看到或控制實際的流處理過程。這完全取決於響應式 API。響應式函式還帶來了一個額外的變數。考慮到函式提供的是對整個流鏈 (而非單個事件) 的可見性,預設的觀測單位應該是什麼?是流鏈中的單個項嗎?是一個項範圍嗎?如果在一段時間後沒有訊息怎麼辦?等等... 我們想要強調的是,對於響應式函式,我們不能假定任何事情。(有關響應式函式和命令式函式之間差異的更多資訊,請參閱 響應式函式)。

因此,就像 重試錯誤處理 一樣,你需要手動處理觀測。

幸運的是,你可以透過使用響應式 API 的 tap 操作來輕鬆做到這一點,同時提供一個 ObservationRegistry 例項。這樣的片段定義了一個觀測單位,它可以是 Flux 中的單個項、一個範圍,或者你希望在流中觀測的任何其他內容。

@SpringBootApplication
public class DemoStreamApplication {

	Logger logger = LoggerFactory.getLogger(DemoStreamApplication.class);

	public static void main(String[] args) {
		Hooks.enableAutomaticContextPropagation();
		SpringApplication.run(DemoStreamApplication.class, args);
	}

	@Bean
	public Function<Flux<String>, Flux<String>> uppercase(ObservationRegistry registry) {
		return flux -> flux.flatMap(item -> {
			return Mono.just(item)
                             .map(value -> value.toUpperCase())
                             .doOnNext(v -> logger.info(v))
                             .tap(Micrometer.observation(registry));
		});
	}
}

上面的例子模擬了將一個 Observation (觀測) 附加到單個訊息處理 (即命令式函式) 的過程,因為在這種情況下,觀測單位始於 Mono.just(..),並且最後一個操作將 ObservationRegistry 附加到訂閱者。

如果訂閱者已經附加了一個觀測,它將用於為 tap 上游的鏈/片段建立一個子 Observation,但是,正如我們之前所述,預設情況下,框架不會為您返回的流鏈附加任何 Observation。