最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot Actuator潛在的OOM問題的解決

 更新時間:2021年11月30日 11:37:06   作者:glmapper  
本文主要介紹了SpringBoot Actuator潛在的OOM問題的解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

此問題背景產(chǎn)生于近期需要上線的一個功能的埋點;主要表現(xiàn)就是在應(yīng)用啟動之后的一段時間內(nèi),內(nèi)存使用一直呈現(xiàn)遞增趨勢。

下圖為場景復(fù)線后,本地通過 jconsole 查看到的內(nèi)部使用走勢圖。

實際環(huán)境受限于配置,內(nèi)存不會膨脹

背景&問題

應(yīng)用 a 使用 rest template 通過 http 方式調(diào)用 應(yīng)用 b,應(yīng)用項目中開啟了 actuator,api 使用的是 micrometer;在 client 調(diào)用時,actuator 會產(chǎn)生一個 name 為 http.client.requests 的 metrics,此 metric 的 tag 中包含點目標(biāo)的 uri。

應(yīng)用 b 提供的接口大致如下:

@RequestMapping("test_query_params")
public String test_query_params(@RequestParam String value) {
    return value;
}

@RequestMapping("test_path_params/{value}")
public String test_path_params(@PathVariable String value) {
    return value;
}

http://localhost:8080/api/test/test_query_params?value=

http://localhost:8080/api/test/test_path_params/{value}_

期望在 metric 的收集結(jié)果中應(yīng)該包括兩個 metrics,主要區(qū)別是 tag 中的 uri 不同,一個是 api/test/test_query_params, 另一個是 api/test/test_path_params/{value};實際上從拿到的 metrics 數(shù)據(jù)來看,差異很大,這里以 pathvariable 的 metric 為例,數(shù)據(jù)如下:

tag: "uri",
values: [
"/api/test/test_path_params/glmapper58",
"/api/test/test_path_params/glmapper59",
"/api/test/test_path_params/glmapper54",
"/api/test/test_path_params/glmapper55",
"/api/test/test_path_params/glmapper56",
"/api/test/test_path_params/glmapper57",
"/api/test/test_path_params/glmapper50",
"/api/test/test_path_params/glmapper51",
"/api/test/test_path_params/glmapper52",
"/api/test/test_path_params/glmapper53",
"/api/test/test_path_params/glmapper47",
"/api/test/test_path_params/glmapper48",
"/api/test/test_path_params/glmapper49",
"/api/test/test_path_params/glmapper43",
"/api/test/test_path_params/glmapper44",
"/api/test/test_path_params/glmapper45",
"/api/test/test_path_params/glmapper46",
"/api/test/test_path_params/glmapper40",
"/api/test/test_path_params/glmapper41",
"/api/test/test_path_params/glmapper42",
"/api/test/test_path_params/glmapper36",
"/api/test/test_path_params/glmapper37",
"/api/test/test_path_params/glmapper38",
"/api/test/test_path_params/glmapper39",
"/api/test/test_path_params/glmapper32",
"/api/test/test_path_params/glmapper33",
"/api/test/test_path_params/glmapper34",
"/api/test/test_path_params/glmapper35",
"/api/test/test_path_params/glmapper30",
"/api/test/test_path_params/glmapper31",
"/api/test/test_path_params/glmapper25",
"/api/test/test_path_params/glmapper26",
....
]

可以非常明顯的看到,這里將{value} 參數(shù)作為了 uri 組件部分,并且體現(xiàn)在 tag 中,并不是期望的 api/test/test_path_params/{value}。

問題原因及解決

兩個問題,1、這個埋點是怎么生效的,先搞清楚這個問題,才能順藤摸瓜。2、怎么解決。

默認(rèn)埋點是如何生效的

因為是通過 resttemplate 進(jìn)行調(diào)用訪問,那么埋點肯定也是基于對 resttemplate 的代理;按照這個思路,筆者找到了 org.springframework.boot.actuate.metrics.web.client.MetricsRestTemplateCustomizer 這個類。RestTemplateCustomizer 就是對 resttemplate 進(jìn)行定制的,MetricsRestTemplateCustomizer 通過名字也能得知期作用是為了給 resttemplate 增加 metric 能力。

再來討論 RestTemplateCustomizer,當(dāng)使用RestTemplateBuilder構(gòu)建RestTemplate時,可以通過RestTemplateCustomizer進(jìn)行更高級的定制,所有RestTemplateCustomizer beans 將自動添加到自動配置的RestTemplateBuilder。也就是說如果 想 MetricsRestTemplateCustomizer 生效,那么構(gòu)建 resttemplate 必須通過 RestTemplateBuilder 方式構(gòu)建,而不是直接 new。

http.client.requests 中的 uri

塞 tag 的代碼在org.springframework.boot.actuate.metrics.web.client.RestTemplateExchangeTags 類中,作用時機(jī)是在 MetricsClientHttpRequestInterceptor 攔截器中。當(dāng)調(diào)用執(zhí)行完成后,會將當(dāng)次請求 metric 記錄下來,在這里就會使用到 RestTemplateExchangeTags 來填充 tags。 下面僅給出 uri 的部分代碼

	/**
	 * Creates a {@code uri} {@code Tag} for the URI of the given {@code request}.
	 * @param request the request
	 * @return the uri tag
	 */
	public static Tag uri(HttpRequest request) {
		return Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().toString())));
	}

	/**
	 * Creates a {@code uri} {@code Tag} from the given {@code uriTemplate}.
	 * @param uriTemplate the template
	 * @return the uri tag
	 */
	public static Tag uri(String uriTemplate) {
		String uri = (StringUtils.hasText(uriTemplate) ? uriTemplate : "none");
		return Tag.of("uri", ensureLeadingSlash(stripUri(uri)));

其余的還有 status 和 clientName 等 tag name。

通過斷點,可以看到,這里 request.getURI() 拿到的是帶有參數(shù)的完整請求鏈接。

這些 tag 的組裝最終在 DefaultRestTemplateExchangeTagsProvider 中完成,并返回一個 列表。

private Timer.Builder getTimeBuilder(HttpRequest request, ClientHttpResponse response) {
    return this.autoTimer.builder(this.metricName)
                // tagProvider 為 DefaultRestTemplateExchangeTagsProvider
				.tags(this.tagProvider.getTags(urlTemplate.get().poll(), request, response))
				.description("Timer of RestTemplate operation");
}

解決

這里先來看下官方對于 request.getURI? 的解釋

	/**
	 * Return the URI of the request (including a query string if any,
	 * but only if it is well-formed for a URI representation).
	 * @return the URI of the request (never {@code null})
	 */
	URI getURI();

返回請求的 URI,這里包括了任何的查詢參數(shù)。那么是不是拿到不用參數(shù)的 path 就行呢?

這里嘗試通過 request.getURI().getPath() 拿到了預(yù)期的 path(@pathvariable 拿到的是模板)。

再回到 DefaultRestTemplateExchangeTagsProvider,所有的 tag 都是在這里完成組裝,這個類明顯是一個默認(rèn)的實現(xiàn)(Spring 體系下基本只要是Defaultxxx 的,一般都能擴(kuò)展 ),查看它的接口類 RestTemplateExchangeTagsProvider 如下:

/**
 * Provides {@link Tag Tags} for an exchange performed by a {@link RestTemplate}.
 *
 * @author Jon Schneider
 * @author Andy Wilkinson
 * @since 2.0.0
 */
@FunctionalInterface
public interface RestTemplateExchangeTagsProvider {

	/**
	 * Provides the tags to be associated with metrics that are recorded for the given
	 * {@code request} and {@code response} exchange.
	 * @param urlTemplate the source URl template, if available
	 * @param request the request
	 * @param response the response (may be {@code null} if the exchange failed)
	 * @return the tags
	 */
	Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response);

}

RestTemplateExchangeTagsProvider 的作用就是為 resttemplate 提供 tag 的,所以這里通過自定義一個 RestTemplateExchangeTagsProvider,來替換DefaultRestTemplateExchangeTagsProvider,以達(dá)到我們的目標(biāo),大致代碼如下:

@Override
 public Iterable<Tag> getTags(String urlTemplate, HttpRequest request, ClientHttpResponse response) {
    Tag uriTag;
    // 取 request.getURI().getPath() 作為 uri 的 value
    if (StringUtils.hasText(request.getURI().getPath())) {
      uriTag = Tag.of("uri", ensureLeadingSlash(stripUri(request.getURI().getPath())));
    } else {
      uriTag = (StringUtils.hasText(urlTemplate) ? RestTemplateExchangeTags.uri(urlTemplate)
                    : RestTemplateExchangeTags.uri(request));
    }
    return Arrays.asList(RestTemplateExchangeTags.method(request), uriTag,
                RestTemplateExchangeTags.status(response), RestTemplateExchangeTags.clientName(request));
    }

會不會 OOM

理論上,應(yīng)該參數(shù)不同,在使用默認(rèn) DefaultRestTemplateExchangeTagsProvider 的情況下,meter 會隨著 tags 的不同迅速膨脹,在 micrometer 中,這些數(shù)據(jù)是存在 map 中的

// Even though writes are guarded by meterMapLock, iterators across value space are supported
// Hence, we use CHM to support that iteration without ConcurrentModificationException risk
private final Map<Id, Meter> meterMap = new ConcurrentHashMap<>();

一般情況下不會,這里是因為 spring boot actuator 自己提供了保護(hù)機(jī)制,對于默認(rèn)情況,tags 在同一個 metric 下,最多只有 100 個

/**
* Maximum number of unique URI tag values allowed. After the max number of
* tag values is reached, metrics with additional tag values are denied by
* filter.
*/
private int maxUriTags = 100;

如果你想使得這個數(shù)更大一些,可以通過如下配置配置

management.metrics.web.client.max-uri-tags=10000

如果配置值過大,會存在潛在的 oom 風(fēng)險。

到此這篇關(guān)于SpringBoot Actuator潛在的OOM問題的解決的文章就介紹到這了,更多相關(guān)SpringBoot Actuator OOM內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!?

相關(guān)文章

  • SpringBoot?如何將項目打包成?jar?包

    SpringBoot?如何將項目打包成?jar?包

    這篇文章主要介紹了SpringBoot如何將項目打包成jar包,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • java中的匿名內(nèi)部類詳細(xì)總結(jié)

    java中的匿名內(nèi)部類詳細(xì)總結(jié)

    以下是對java中的匿名內(nèi)部類進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-10-10
  • Java中關(guān)于http請求獲取FlexManager某設(shè)備分組監(jiān)控點

    Java中關(guān)于http請求獲取FlexManager某設(shè)備分組監(jiān)控點

    這篇文章主要介紹了Java中關(guān)于http請求獲取FlexManager某設(shè)備分組監(jiān)控點,本文僅僅介紹了使用http請求獲取FlexManager平臺某個FBox盒子即某設(shè)備的監(jiān)控點分組的分組下的所有監(jiān)控點信息,需要的朋友可以參考下
    2022-10-10
  • Java Swing仿QQ登錄界面效果

    Java Swing仿QQ登錄界面效果

    這篇文章主要為大家詳細(xì)介紹了Java Swing仿QQ登錄界面效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 基于redis setIfAbsent的使用說明

    基于redis setIfAbsent的使用說明

    這篇文章主要介紹了基于redis setIfAbsent的使用說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 解決SpringBoot的@DeleteMapping注解的方法不被調(diào)用問題

    解決SpringBoot的@DeleteMapping注解的方法不被調(diào)用問題

    這篇文章主要介紹了解決SpringBoot的@DeleteMapping注解的方法不被調(diào)用問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • spring監(jiān)視器actuator配置應(yīng)用

    spring監(jiān)視器actuator配置應(yīng)用

    這篇文章主要介紹了spring監(jiān)視器actuator配置應(yīng)用,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Spring Cloud 整合Apache-SkyWalking實現(xiàn)鏈路跟蹤的方法

    Spring Cloud 整合Apache-SkyWalking實現(xiàn)鏈路跟蹤的方法

    這篇文章主要介紹了Spring Cloud 整合Apache-SkyWalking鏈路跟蹤的示例代碼,代碼簡單易懂,通過圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Java方法重載的使用實戰(zhàn)案例

    Java方法重載的使用實戰(zhàn)案例

    這篇文章主要介紹了Java方法重載的使用,結(jié)合具體實例形式分析了java方法重載的基本使用技巧與相關(guān)操作注意事項,需要的朋友可以參考下
    2019-09-09
  • Java8中的LocalDateTime你會使用了嗎

    Java8中的LocalDateTime你會使用了嗎

    LocalDateTime?是?Java?8?中日期時間?API?提供的一個類,在日期和時間的表示上提供了更加豐富和靈活的支持,本文就來講講LocalDateTime的一些具體使用方法吧
    2023-05-05

最新評論

依兰县| 肇源县| 永吉县| 英山县| 临沂市| 合江县| 济源市| 全州县| 松阳县| 清镇市| 武陟县| 射阳县| 怀柔区| 马公市| 龙门县| 珠海市| 林口县| 贵定县| 应城市| 平塘县| 龙州县| 怀来县| 石狮市| 富川| 福贡县| 原阳县| 阿拉善左旗| 饶平县| 大港区| 河津市| 舞阳县| 长垣县| 遂宁市| 晋州市| 邹平县| 仁寿县| 苍溪县| 陇川县| 平南县| 筠连县| 东兴市|