OpenFeign(9.5.0)性能優(yōu)化嘗試

一蟆沫、為什么需要優(yōu)化澳迫?

    微服務(wù)之間的RPC調(diào)用使用的OpenFeign組件,并且完全使用的默認設(shè)置澈段,**默認的設(shè)置**包括:

1.1 HTTP客戶端

默認使用的HttpURLConnection悠菜,這是java自帶的發(fā)送http請求的API,優(yōu)點就是java自帶的败富,調(diào)用的時候方便悔醋,缺點就是性能和安全方面

缺點

  • HttpURLConnection每次請求都會打開一個新的TCP連接,不復(fù)用TCP連接兽叮,這會導(dǎo)致在高并發(fā)場景下HTTP請求和響應(yīng)的速度變慢

  • 比較繁瑣芬骄,需要手動進行請求的創(chuàng)建猾愿、連接、讀取和關(guān)閉等操作账阻;

  • 線程安全性不如其他并發(fā)包蒂秘,需要在多線程環(huán)境中進行適當(dāng)?shù)耐剑?/p>

  • 對響應(yīng)數(shù)據(jù)的讀取需要手動進行,需要調(diào)用IO流API進行讀取淘太。

現(xiàn)狀

目前使用的默認的HttpURLConnection

1.2 重試策略

默認的重試策略

@Configuration
public class FeignClientsConfiguration {
@Bean
@ConditionalOnMissingBean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }
}

默認是永不重試姻僧,請求五秒超時后就拋異常結(jié)束

現(xiàn)狀

目前重試策略由第三方組件Guava手動實現(xiàn)重試,需要重試的接口自己實現(xiàn)重試機制琴儿。

1.3 日志打印策略

 public enum Level {
    /**
     * No logging.
     */
    NONE,
    /**
     * Log only the request method and URL and the response status code and execution time.
     */
    BASIC,
    /**
     * Log the basic information along with request and response headers.
     */
    HEADERS,
    /**
     * Log the headers, body, and metadata for both requests and responses.
     */
    FULL
  }

默認是NONE,不打印feign的請求響應(yīng)日志

現(xiàn)狀

目前是默認的不打印feign的請求響應(yīng)日志

1.4 編碼解碼策略

@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
   return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
}

@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
   return new SpringEncoder(this.messageConverters);
}

默認使用是是SpringEncoder和SpringDecoder(它們共同作用于HTTP消息轉(zhuǎn)換嘁捷,其中SpringEncoder用于將Java對象轉(zhuǎn)換為請求的HTTP消息體造成,SpringDecoder將響應(yīng)的HTTP消息體轉(zhuǎn)換為相應(yīng)的Java對象)

以下是一個HTTP消息體的例子:

POST /api/books HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "title": "The Hitchhiker's Guide to the Galaxy",
    "author": "Douglas Adams",
    "year": 1979,
    "publisher": "Pan Books",
    "isbn": "978-0330508537",
    "language": "English",
    "format": "paperback",
    "pages": 224
}

現(xiàn)狀

目前是默認配置

二、目前可以優(yōu)化那些方面

目前我們主要想提升的是feign接口的性能雄嚣,因為平時總會有一些feign接口超時晒屎,但是具體去排查,并不是數(shù)據(jù)庫響應(yīng)的問題缓升,所以我們需要對feign本身的請求性能進行優(yōu)化鼓鲁。

重試策略我們可以不做改動,需要重試的地方就自己實現(xiàn)港谊。

feign請求響應(yīng)日志打印這一塊骇吭,我們也為了性能使用默認不打印(好像也沒有這種需要)歧寺。

編碼解碼策略也可以使用默認燥狰,性能提升不在這。

所以優(yōu)化重點放在了Feign的HTTP客戶端斜筐。

三龙致、Feign-HTTP客戶端替換

3.1 我們該如何配置

不做特殊配置的話,在pom文件里面加上http客戶端顷链,SpringBoot應(yīng)用就可以識別并使用到目代。但是需要做特殊配置的話就不行。

<dependency>
   <groupId>io.github.openfeign</groupId>
   <artifactId>feign-httpclient</artifactId>
</dependency>

9.5.0版本的OpenFeign是不支持在yaml文件或者properties文件中配置的嗤练。在高版本的OpenFeign可以直接在ymal或者properties配置

### Feign 配置
feign:
  httpclient:
    # 開啟 Http Client
    enabled: true
    # 最大連接數(shù)榛了,默認:200
    max-connections: 200
    # 最大路由,默認:50
    max-connections-per-route: 50
    # 連接超時煞抬,默認:2000/毫秒
    connection-timeout: 2000
    # 生存時間忽冻,默認:900L
    time-to-live: 900
    # 響應(yīng)超時的時間單位,默認:TimeUnit.SECONDS
#    timeToLiveUnit: SECONDS

### Feign 配置
feign:
  httpclient:
    # 是否開啟 Http Client
    enabled: false
#    # 最大連接數(shù)此疹,默認:200
#    max-connections: 200
#    # 最大路由僧诚,默認:50
#    max-connections-per-route: 50
#    # 連接超時遮婶,默認:2000/毫秒
#    connection-timeout: 2000
#    # 生存時間,默認:900L
#    time-to-live: 900
#    # 響應(yīng)超時的時間單位湖笨,默認:TimeUnit.SECONDS
##    timeToLiveUnit: SECONDS
  okhttp:
    enabled: true


那么在9.5.0該如何配置我們的最大連接數(shù)旗扑、連接超時時間等參數(shù)呢?

肯定只能自己寫配置文件來處理了

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignConfig {
  @Bean
  public OkHttpClient okHttpClient() {
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
    clientBuilder.readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(5, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .connectionPool(new ConnectionPool(255, 5, TimeUnit.MINUTES));
        //.addInterceptor(okHttpInterceptor);
    return clientBuilder.build();
  }
}

發(fā)起一個Http請求慈省,可以看到我們的配置是生效的

image.png

3.2 Feign(9.5.0)自動配置源碼

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignAutoConfiguration {
    @Configuration
    @ConditionalOnClass(OkHttpClient.class)
    @ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
    @ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
    protected static class OkHttpFeignConfiguration {

        @Autowired(required = false)
        private okhttp3.OkHttpClient okHttpClient;

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient() {
            if (this.okHttpClient != null) {
                return new OkHttpClient(this.okHttpClient);
            }
            return new OkHttpClient();
        }
    }
}
//OkHttpClient是Client的實現(xiàn)類
public final class OkHttpClient implements Client {
  
}

當(dāng)Springboot應(yīng)用啟動的時候臀防,檢測到類路徑中Feign類,并且沒有com.netflix.loadbalancer.ILoadBalancer類時边败,才會加載這個配置袱衷,通俗講,就是如果用到了Spring-Cloud的Ribbon負載均衡組件笑窜,F(xiàn)eignAutoConfiguration就不會加載OkHttpFeignConfiguration致燥。

那什么時候初始化Feign的Client呢?

@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@Configuration
@AutoConfigureBefore(FeignAutoConfiguration.class)
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
      OkHttpFeignLoadBalancedConfiguration.class,
      DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
  
}
@Configuration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty(value = "feign.okhttp.enabled", matchIfMissing = true)
class OkHttpFeignLoadBalancedConfiguration {

    @Autowired(required = false)
    private okhttp3.OkHttpClient okHttpClient;

    @Bean
    @ConditionalOnMissingBean(Client.class)
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                              SpringClientFactory clientFactory) {
        OkHttpClient delegate;
        if (this.okHttpClient != null) {
            delegate = new OkHttpClient(this.okHttpClient);
        } else {
            delegate = new OkHttpClient();
        }
        return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
    }
}

OK排截,我們看到在FeignRibbonClientAutoConfiguration類里面嫌蚤,主動使用@Import導(dǎo)入了OkHttpFeignLoadBalancedConfiguration配置類,配置類里面加載了OkHttpClient并委托給LoadBalancerFeignClient断傲,供之后Feign的http調(diào)用時使用脱吱。

四、OkHttpClient參數(shù)的制定

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignConfig {
  @Bean
  public OkHttpClient okHttpClient() {
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
    clientBuilder.readTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .connectTimeout(5, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .connectionPool(new ConnectionPool(255, 5, TimeUnit.MINUTES));
        //.addInterceptor(okHttpInterceptor);
    return clientBuilder.build();
  }
}

4.1 maxIdleConnections

maxIdleConnections 連接池大小认罩,指單個okhttpclient實例所有連接的連接池箱蝠。

如果設(shè)置的過大?

maxIdleConnections 設(shè)置得過大可能會占用過多的系統(tǒng)資源垦垂,導(dǎo)致系統(tǒng)性能下降抡锈。因為連接池中的每個空閑連接都需要占據(jù)一定的內(nèi)存谐腰,如果連接池中的連接數(shù)量過多读串,就會占用過多的內(nèi)存資源惯悠。此外躁锡,連接池中的連接也會占用操作系統(tǒng)資源据过,例如文件句柄孝宗、線程等。

另外找蜜,將 maxIdleConnections 設(shè)置得過大也可能會影響網(wǎng)絡(luò)請求的響應(yīng)速度洗做。因為連接池中的連接數(shù)量越多,每個連接就會得到更少的使用機會撰筷,導(dǎo)致連接空閑時間變長毕籽,從而增加網(wǎng)絡(luò)請求的響應(yīng)時間关筒。

因此杯缺,應(yīng)該根據(jù)應(yīng)用的實際情況合理設(shè)置 maxIdleConnections 的值,以平衡資源利用和網(wǎng)絡(luò)請求響應(yīng)速度廉赔。

如果設(shè)置的過小勿负?

maxIdleConnections 設(shè)置得過小可能會導(dǎo)致連接池中的連接不足奴愉,從而影響網(wǎng)絡(luò)請求的響應(yīng)速度锭硼。因為當(dāng)連接數(shù)不足時檀头,新的請求需要等待現(xiàn)有的連接釋放岖沛,才能夠得到響應(yīng)婴削。如果請求量很大唉俗,等待連接釋放的時間就會變長,從而導(dǎo)致網(wǎng)絡(luò)請求的響應(yīng)時間變長颂郎。

此外乓序,將 maxIdleConnections 設(shè)置得過小也可能會導(dǎo)致連接頻繁地被創(chuàng)建和關(guān)閉替劈,從而降低連接的重用率得滤,從而增加了系統(tǒng)負擔(dān)和網(wǎng)絡(luò)請求的響應(yīng)時間懂更。

因此沮协,應(yīng)該根據(jù)應(yīng)用的實際情況合理設(shè)置 maxIdleConnections 的值慷暂,以確保連接池中的連接數(shù)量能夠滿足并發(fā)請求的需求行瑞,同時避免連接數(shù)量過多導(dǎo)致資源浪費血久。

到底設(shè)置多少合適?

確定最優(yōu)值需要考慮以下幾個因素:

  1. 并發(fā)請求的數(shù)量讹蘑。如果同時有很多請求衔肢,那么連接池中就需要有足夠多的空閑連接角骤,以便快速響應(yīng)請求邦尊。
  2. 服務(wù)器的響應(yīng)速度蝉揍。如果服務(wù)器響應(yīng)速度很快又沾,那么連接池中的連接就會很快被釋放杖刷,可以減少連接池中的空閑連接數(shù)滑燃。
  3. 應(yīng)用的網(wǎng)絡(luò)環(huán)境表窘。如果網(wǎng)絡(luò)延遲較高乐严,那么連接池中的連接可能需要等待很長時間才能收到響應(yīng)麦备,因此需要更多的空閑連接凛篙。

一般來說呛梆,可以根據(jù)應(yīng)用的實際情況進行調(diào)整填物≈突牵可以嘗試不同的值击困,觀察連接池中的空閑連接數(shù)和請求的響應(yīng)時間阅茶,選擇一個能夠平衡資源利用和響應(yīng)速度的值作為最終的配置蹦浦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盲镶,一起剝皮案震驚了整個濱河市蝌诡,隨后出現(xiàn)的幾起案子送漠,更是在濱河造成了極大的恐慌闽寡,老刑警劉巖爷狈,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件思币,死亡現(xiàn)場離奇詭異,居然都是意外死亡博投,警方通過查閱死者的電腦和手機毅哗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門闽烙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酥艳,你說我怎么就攤上這事≈枇澹” “怎么了惰爬?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵狞尔,是天一觀的道長偏序。 經(jīng)常有香客問我豫缨,道長,這世上最難降的妖魔是什么栓撞? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任恩尾,我火速辦了婚禮翰意,結(jié)果婚禮上醒第,老公的妹妹穿的比我還像新娘。我一直安慰自己霞幅,他們只是感情好司恳,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布铅鲤。 她就那樣靜靜地躺著邢享,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上插爹,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天气嫁,我揣著相機與錄音崖面,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼脂矫,長吁一口氣:“原來是場噩夢啊……” “哼枣耀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起庭再,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤捞奕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拄轻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颅围,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年恨搓,在試婚紗的時候發(fā)現(xiàn)自己被綠了院促。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡斧抱,死狀恐怖常拓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夺姑,我是刑警寧澤墩邀,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站盏浙,受9級特大地震影響眉睹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜废膘,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一竹海、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丐黄,春花似錦斋配、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至桂对,卻和暖如春甩卓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蕉斜。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工逾柿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宅此。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓机错,卻偏偏與公主長得像,于是被迫代替她去往敵國和親父腕。 傳聞我的和親對象是個殘疾皇子弱匪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容