本文旨在深入解析micrometer與prometheus集成時常見的“所有同名度量指標(biāo)必須擁有相同的標(biāo)簽鍵集合”錯誤。我們將探討該錯誤產(chǎn)生的根本原因,即多個組件或自定義切面為同一指標(biāo)名注冊了不同標(biāo)簽鍵集合的計時器。文章將提供多種解決方案,包括確保標(biāo)簽鍵一致性、使用不同指標(biāo)名或精細(xì)控制切面應(yīng)用范圍,并強調(diào)高基數(shù)標(biāo)簽(如uri)的潛在危害及規(guī)避方法。
在使用Micrometer結(jié)合Prometheus進(jìn)行應(yīng)用監(jiān)控時,一個核心原則是:Prometheus要求所有具有相同名稱的度量指標(biāo)必須擁有相同的標(biāo)簽鍵集合。 這意味著,對于任何給定的度量指標(biāo)名稱(例如 http_requests_total),無論其標(biāo)簽值如何變化,其關(guān)聯(lián)的標(biāo)簽鍵(例如 method, path, status)必須是固定不變的。
為什么會有這個限制? Prometheus將一個度量指標(biāo)的名稱與它的一組標(biāo)簽鍵視為一個唯一的“時間序列”定義。當(dāng)Prometheus抓取數(shù)據(jù)時,它期望這些時間序列的結(jié)構(gòu)是穩(wěn)定的。如果同一個指標(biāo)名在不同的注冊點擁有不同的標(biāo)簽鍵集合,Prometheus將無法正確地將其識別為同一個邏輯度量,從而導(dǎo)致數(shù)據(jù)模型混亂,并可能引發(fā) IllegalArgumentException。
例如,如果您注冊了一個名為 my_timer 的計時器,帶有標(biāo)簽 [tagA, tagB],然后又嘗試注冊一個名為 my_timer 的計時器,帶有標(biāo)簽 [tagA, tagC],Prometheus就會拋出上述異常,因為它認(rèn)為這兩個 my_timer 具有不同的結(jié)構(gòu)。
在提供的案例中,用戶遇到了以下錯誤信息: java.lang.IllegalArgumentException: Prometheus requires that all meters with the same name have the same set of tag keys. There is already an existing meter named 'web_photos_gotten_list_seconds' containing tag keys [class, exception, method]. The meter you are attempting to register has keys [exception, method, outcome, status, uri].
這個錯誤清晰地指出了問題:
根本原因分析: 在Spring Boot應(yīng)用中,當(dāng)您自定義一個AOP切面來處理 @Timed 注解時,很可能與Spring Boot默認(rèn)提供的 TimedAspect 產(chǎn)生沖突。
當(dāng)一個方法(例如 webPhotosGottenList())同時滿足兩個切面的條件(例如,它是一個帶有 @Timed 注解的Web控制器方法),并且兩個切面都嘗試為它注冊一個名為 web_photos_gotten_list_seconds 的計時器時,就會發(fā)生標(biāo)簽鍵集合不一致的沖突。
Pointcut的作用: 用戶在問題中提到,通過修改 Pointcut,問題得到了解決。這并非偶然。最初的 @Around("timedAnnotatedPointcut()") 會使得自定義切面應(yīng)用于所有帶有 @Timed 注解的方法。如果其中一些方法也是Web請求處理器,那么它們就會被Spring Boot的默認(rèn)切面和用戶自定義切面同時處理。
修改后的 Pointcut: @Around("timedAnnotatedPointcut() && (asyncAnnotatedPointcut() || allowedMethodPointcut())") 這個修改限制了自定義切面的應(yīng)用范圍,使其僅作用于那些帶有 @Timed 且同時是 @StreamListener、@Scheduled 或特定服務(wù)方法的方法。如果 webPhotosGottenList() 方法不屬于這些類別,那么用戶自定義的切面將不再對其生效,從而避免了與Spring Boot默認(rèn)切面為該方法注冊的計時器發(fā)生標(biāo)簽鍵沖突。
解決此類標(biāo)簽鍵沖突問題有以下幾種策略:
這是最根本的解決方案。對于同一個度量指標(biāo)名稱,必須確保所有嘗試注冊它的代碼路徑都使用完全相同的標(biāo)簽鍵集合。
統(tǒng)一標(biāo)簽定義: 審查所有可能注冊 web_photos_gotten_list_seconds 的代碼。如果某些標(biāo)簽并非總是適用,可以為它們設(shè)置一個默認(rèn)值(例如 "none" 或 "N/A"),而不是完全省略這些標(biāo)簽。
示例: 如果一個計時器有時需要 outcome 和 status 標(biāo)簽,而有時不需要,那么在不需要的場景下,也必須添加這些標(biāo)簽,并賦予一個默認(rèn)值。
// 確保所有注冊點都有相同的標(biāo)簽鍵 Timer.Builder timerBuilder = Timer.builder(metricName) .tags(EXCEPTION_TAG, exceptionClass) .tags(tagsBasedOnJoinPoint.apply(pjp)); // 包含 class, method // 假設(shè) outcome, status, uri 也是需要統(tǒng)一的標(biāo)簽 // 如果當(dāng)前上下文沒有這些值,也要添加默認(rèn)值 timerBuilder.tag("outcome", "unknown"); timerBuilder.tag("status", "unknown"); timerBuilder.tag("uri", "unknown"); // 注意:URI標(biāo)簽應(yīng)謹(jǐn)慎使用,見下方最佳實踐 if (streamListener != null) { timerBuilder.tags(BINDING_TAG, streamListener.value().isEmpty() ? streamListener.target() : streamListener.value()); timerBuilder.tag(SCHEDULED_CRON_TAG, "none"); // 確保cron標(biāo)簽也存在 } else if (scheduled != null) { timerBuilder.tags(SCHEDULED_CRON_TAG, scheduled.cron()); timerBuilder.tag(BINDING_TAG, "none"); // 確保binding標(biāo)簽也存在 } else { timerBuilder.tag(BINDING_TAG, "none"); timerBuilder.tag(SCHEDULED_CRON_TAG, "none"); } sample.stop(timerBuilder.register(registry));
這種方法可能導(dǎo)致度量指標(biāo)的標(biāo)簽數(shù)量增多,但能保證一致性。
神卷標(biāo)書,專注于AI智能標(biāo)書制作、管理與咨詢服務(wù),提供高效、專業(yè)的招投標(biāo)解決方案。支持一站式標(biāo)書生成、模板下載,助力企業(yè)輕松投標(biāo),提升中標(biāo)率。
如果兩個具有相同名稱但不同標(biāo)簽集合的度量指標(biāo)實際上代表了不同的業(yè)務(wù)或技術(shù)含義,那么它們就不應(yīng)該共享同一個名稱。
如果沖突是由多個AOP切面(例如自定義切面與Spring Boot默認(rèn)切面)同時作用于同一方法引起的,可以通過調(diào)整切面配置來解決。
// 示例:僅對特定服務(wù)層方法或特定注解方法應(yīng)用自定義切面 @Around("timedAnnotatedPointcut() && (asyncAnnotatedPointcut() || allowedMethodPointcut())") public Object timedMethod(ProceedingJoinPoint pjp) throws Throwable { // ... 自定義計時邏輯 }
當(dāng)不確定是哪個代碼路徑注冊了沖突的度量指標(biāo)時,可以使用調(diào)試工具:
高基數(shù)標(biāo)簽的危害: 錯誤信息中出現(xiàn)的 uri 標(biāo)簽是一個需要特別注意的問題。URI通常具有非常高的基數(shù)(即可能的值非常多)。將高基數(shù)標(biāo)簽添加到Prometheus度量指標(biāo)會導(dǎo)致:
默認(rèn)行為與自定義: 在Spring Boot環(huán)境中,理解框架的默認(rèn)度量行為至關(guān)重要。當(dāng)您引入自定義度量邏輯時,要清楚它是否會與默認(rèn)行為重疊或沖突。
清晰的命名約定: 為您的度量指標(biāo)制定清晰的命名約定,使其能夠區(qū)分不同類型或來源的度量。
Prometheus對標(biāo)簽鍵一致性的要求是其數(shù)據(jù)模型的基礎(chǔ)。當(dāng)遇到“同名度量指標(biāo)必須擁有相同的標(biāo)簽鍵集合”錯誤時,核心任務(wù)是識別并解決不同代碼路徑為同一指標(biāo)名注冊了不同標(biāo)簽鍵集合的問題。通過確保標(biāo)簽鍵一致性、使用不同的指標(biāo)名稱、精細(xì)化AOP切面范圍或禁用沖突的度量注冊,可以有效地解決這類問題。同時,務(wù)必警惕高基數(shù)標(biāo)簽帶來的性能隱患,并采取適當(dāng)?shù)牟呗赃M(jìn)行規(guī)避。
以上就是Prometheus與Micrometer:解決度量指標(biāo)標(biāo)簽鍵沖突問題的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會占用資源并降低性能。幸運的是,許多工具可以讓 Windows 保持平穩(wěn)運行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號