成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

張開濤:超時(shí)與重試機(jī)制(1)

開發(fā) 開發(fā)工具
本文主要從Web應(yīng)用/服務(wù)化應(yīng)用的角度出發(fā)介紹如何設(shè)置超時(shí)與重試。

在實(shí)際開發(fā)過程中,筆者見過太多故障是因?yàn)槌瑫r(shí)沒有設(shè)置或者設(shè)置的不對(duì)而造成的。而這些故障都是因?yàn)闆]有意識(shí)到超時(shí)設(shè)置的重要性而造成的。如果應(yīng)用不設(shè)置超時(shí),則可能會(huì)導(dǎo)致請(qǐng)求響應(yīng)慢,慢請(qǐng)求累積導(dǎo)致連鎖反應(yīng),甚至應(yīng)用雪崩。而有些中間件或者框架在超時(shí)后會(huì)進(jìn)行重試(如設(shè)置超時(shí)重試兩次),讀服務(wù)天然適合重試,但寫服務(wù)大多不能重試(如寫訂單,如果寫服務(wù)是冪等,則重試是允許的),重試次數(shù)太多會(huì)導(dǎo)致多倍請(qǐng)求流量,即模擬了DDoS攻擊,后果可能是災(zāi)難,因此,務(wù)必設(shè)置合理的重試機(jī)制,并且應(yīng)該和熔斷、快速失敗機(jī)制配合。在進(jìn)行代碼Review時(shí),一定記得Review超時(shí)與重試機(jī)制。

本文主要從Web應(yīng)用/服務(wù)化應(yīng)用的角度出發(fā)介紹如何設(shè)置超時(shí)與重試(系統(tǒng)層面的超時(shí)設(shè)置本文沒有涉及),而Web應(yīng)用需要在如下鏈條中設(shè)置超時(shí)與重試機(jī)制。

超時(shí)與重試機(jī)制

從上圖來看,在整個(gè)鏈條中的每一個(gè)點(diǎn)都要考慮設(shè)置超時(shí)與重試機(jī)制。而其中最重要的超時(shí)設(shè)置是網(wǎng)絡(luò)連接/讀/寫的超時(shí)時(shí)間設(shè)置。

本文將按照如下分類進(jìn)行超時(shí)與重試機(jī)制的講解。

  • 代理層超時(shí)與重試:如Haproxy、Nginx、Twemproxy,這些組件實(shí)現(xiàn)代理功能,如Haproxy和Nginx可以實(shí)現(xiàn)請(qǐng)求的負(fù)載均衡。而Twemproxy可以實(shí)現(xiàn)Redis的分片代理。需要設(shè)置代理與后端真實(shí)服務(wù)器之間的網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間。
  • Web容器超時(shí):如Tomcat、Jetty等,提供HTTP服務(wù)運(yùn)行環(huán)境的。需要設(shè)置客戶端與容器之間的網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間,和在此容器中默認(rèn)Socket網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間。
  • 中間件客戶端超時(shí)與重試:如JSF(京東SOA框架)、Dubbo、JMQ(京東消息中間件)、CXF、Httpclient等,需要設(shè)置客戶的網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間與失敗重試機(jī)制。
  • 數(shù)據(jù)庫客戶端超時(shí):如Mysql、Oracle,需要分別設(shè)置JDBC Connection、Statement的網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間。事務(wù)超時(shí)時(shí)間,獲取連接池連接等待時(shí)間。
  • NoSQL客戶端超時(shí):如Mongo、Redis,需要設(shè)置其網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間,獲取連接池連接等待時(shí)間。
  • 業(yè)務(wù)超時(shí):如訂單取消任務(wù)、超時(shí)活動(dòng)關(guān)閉。還有如通過Future#get(timeout,unit)限制某個(gè)接口的超時(shí)時(shí)間。
  • 前端Ajax超時(shí):瀏覽器通過Ajax訪問時(shí)的網(wǎng)絡(luò)連接/讀/寫超時(shí)時(shí)間。

從如上分類可以看出,其中最重要的超時(shí)設(shè)置是網(wǎng)絡(luò)相關(guān)的超時(shí)設(shè)置。

一、代理層超時(shí)與重試

對(duì)于代理層我們以Nginx和Twemproxy案例來講解。首先,看下Nginx的相關(guān)超時(shí)設(shè)置。

1. Nginx

Nginx主要有四類超時(shí)設(shè)置:客戶端超時(shí)設(shè)置、DNS解析超時(shí)設(shè)置、代理超時(shí)設(shè)置,如果使用ngx_lua,則還有l(wèi)ua相關(guān)的超時(shí)設(shè)置。

(1) 客戶端超時(shí)設(shè)置

對(duì)于客戶端超時(shí)主要設(shè)置有讀取請(qǐng)求頭超時(shí)時(shí)間、讀取請(qǐng)求體超時(shí)時(shí)間、發(fā)送響應(yīng)超時(shí)時(shí)間、長連接超時(shí)時(shí)間。通過客戶端超時(shí)設(shè)置避免客戶端惡意或者網(wǎng)絡(luò)狀況不佳造成連接長期占用,影響服務(wù)端的可處理的能力。

  • client_header_timeout time:設(shè)置讀取客戶端請(qǐng)求頭超時(shí)時(shí)間,默認(rèn)為60s,如果在此超時(shí)時(shí)間內(nèi)客戶端沒有發(fā)送完請(qǐng)求頭,則響應(yīng)408(RequestTime-out)狀態(tài)碼給客戶端。
  • client_body_timeout time:設(shè)置讀取客戶端內(nèi)容體超時(shí)時(shí)間,默認(rèn)為60s,此超時(shí)時(shí)間指的是兩次成功讀操作間隔時(shí)間,而不是發(fā)送整個(gè)請(qǐng)求體的超時(shí)時(shí)間,如果在此超時(shí)時(shí)間內(nèi)客戶端沒有發(fā)送任何請(qǐng)求體,則響應(yīng)408(RequestTime-out)狀態(tài)碼給客戶端。
  • send_timeout time:設(shè)置發(fā)送響應(yīng)到客戶端的超時(shí)時(shí)間,默認(rèn)為60s,此超時(shí)時(shí)間指的也是兩次成功寫操作間隔時(shí)間,而不是發(fā)送整個(gè)響應(yīng)的超時(shí)時(shí)間。如果在此超時(shí)時(shí)間內(nèi)客戶端沒有接收任何響應(yīng),則Nginx關(guān)閉此連接。
  • keepalive_timeout timeout [header_timeout]:設(shè)置HTTP長連接超時(shí)時(shí)間,其中,第一個(gè)參數(shù)timeout是告訴Nginx長連接超時(shí)時(shí)間是多少,默認(rèn)為75s。第二個(gè)參數(shù)header_timeout是用于設(shè)置響應(yīng)頭“Keep-Alive: timeout=time”,即告知客戶端長連接超時(shí)時(shí)間。兩個(gè)參數(shù)可以不一樣,“Keep-Alive:timeout=time”響應(yīng)頭可以在Mozilla和Konqueror系列瀏覽器起作用,而MSIE長連接默認(rèn)大約為60s,而不會(huì)使用“Keep-Alive: timeout=time”。如Httpclient框架會(huì)使用“Keep-Alive: timeout=time”響應(yīng)頭的超時(shí)(如果不設(shè)置默認(rèn),則認(rèn)為是永久)。如果timeout設(shè)置為0,則表示禁用長連接。

此參數(shù)要配合keepalive_disable 和keepalive_requests一起使用。keepalive_disable 表示禁用哪些瀏覽器的長連接,默認(rèn)值為msie6,即禁用一些老版本的MSIE的長連接支持。keepalive_requests參數(shù)作用是一個(gè)客戶端可以通過此長連接的請(qǐng)求次數(shù),默認(rèn)為100。

首先,瀏覽器在請(qǐng)求時(shí)會(huì)通過如下請(qǐng)求頭告知服務(wù)器是否支持長連接。

http/1.0默認(rèn)是關(guān)閉長連接的,需要添加HTTP請(qǐng)求頭“Connection:Keep-Alive”才能啟用。而http/1.1默認(rèn)啟用長連接,需要添加HTTP請(qǐng)求頭“Connection: close”才關(guān)閉。

接著,如果Nginx設(shè)置keepalive_timeout 5s,則瀏覽器會(huì)收到如下響應(yīng)頭。

下圖是wireshark抓包,可以看到后兩次請(qǐng)求沒有三次握手。

wireshark抓包

如果Nginx設(shè)置keepalive_timeout 10s 10s,則瀏覽器會(huì)收到如下響應(yīng)頭。

服務(wù)器端會(huì)在10s后發(fā)送FIN主動(dòng)關(guān)閉連接。

如果Nginx設(shè)置keepalive_timeout為75s 30s。

如下是Chrome瀏覽器的Wireshark抓包,在45秒時(shí),Chrome發(fā)送了TCPKeep-Alive來保活TCP連接,在第57秒時(shí),瀏覽器又發(fā)出了一次請(qǐng)求。而132秒時(shí),Nginx發(fā)出了FIN來關(guān)閉連接(75秒連接沒活躍了)。

Chrome瀏覽器的Wireshark抓包

如下是IE瀏覽器抓包數(shù)據(jù),在請(qǐng)求后第65秒左右時(shí),瀏覽器重置了連接。

IE瀏覽器抓包數(shù)據(jù)

可以看出不同瀏覽器超時(shí)處理方式不一樣,而HTTP響應(yīng)頭“Keep-Alive: timeout=30”對(duì)Chrome和IE都沒有起作用。

接著,如果keepalive_timeout 0,則瀏覽器會(huì)收到如下響應(yīng)頭。

對(duì)于客戶端超時(shí)設(shè)置,要根據(jù)實(shí)際場景來決定,如果是短連接服務(wù),則可以考慮設(shè)置的短一些,如果是文件上傳,則需要考慮設(shè)置的時(shí)間長一些。另外,筆者見過很多人長連接并沒有配置正確,建議配置完成后通過抓包查看長連接是否起作用了。keepalive_timeout和keepalive_requests是控制長連接的兩個(gè)維度,只要其中一個(gè)到達(dá)設(shè)置的閾值連接就會(huì)被關(guān)閉。

(2) DNS解析超時(shí)設(shè)置

resolver_timeout 30s:設(shè)置DNS解析超時(shí)時(shí)間,默認(rèn)為30s。其配合resolver address ... [valid=time]進(jìn)行DNS域名解析。當(dāng)在Nginx中使用域名時(shí),就需要考慮設(shè)置這兩個(gè)參數(shù)。在社區(qū)版Nginx中采用如下配置。

  1. upstream backend { 
  2.     server c0.3.cn; 
  3.     server c1.3.cn; 

如上兩個(gè)域名會(huì)在Nginx解析配置文件的階段被解析成IP地址并記錄到upstream上,當(dāng)這兩個(gè)域名對(duì)應(yīng)的IP地址發(fā)生變化時(shí),該upstream不會(huì)更新。Nginx商業(yè)版是支持動(dòng)態(tài)更新的。

一種簡單辦法是使用如下方式,每次都會(huì)動(dòng)態(tài)解析域名,這種情況在多域名情況下比較麻煩,實(shí)現(xiàn)就不優(yōu)雅了。

  1. location /test { 
  2.    proxy_pass http://c0.3.cn; 

如果使用Openresty,則可以通過Lua庫lua-resty-dns進(jìn)行DNS解析。

  1. localresolver = require "resty.dns.resolver" 
  2.   local r, err = resolver:new{ 
  3.       nameservers = {"8.8.8.8",{"8.8.4.4", 53} }, 
  4.       retrans = 5,  -- 5 retransmissions on receive timeout 
  5.       timeout = 2000,  -- 2 sec 
  6.   } 

當(dāng)使用Nginx 1.5.8、1.7.4及遇到

  1. could not be resolved(110:Operation timed out); 

或者

  1. wrong ident 37278 response for ***.jd.local, expected 33517 
  2. unexpected response for ***.jd.local 

可能是遇到了如下BUG(http://nginx.org/en/CHANGES-1.6、http://nginx.org/ en/CHANGES-1.8)。

  1. Bugfix: requests might hang if resolver was usedand a timeout 
  2.       occurred during a DNS request. 

請(qǐng)考慮升級(jí)到Nginx 1.6.2、1.7.5或者在Nginx本機(jī)部署dnsmasq提升DNS解析性能。

(3) 代理超時(shí)設(shè)置

Nginx配置如下所示。

  1. upstream backend_server { 
  2.     server 192.168.61.1:9080 max_fails=2 fail_timeout=10s weight=1
  3.     server 192.168.61.1:9090 max_fails=2 fail_timeout=10s weight=1
  4. server { 
  5.     …… 
  6.     location /test { 
  7.        proxy_connect_timeout 5s; 
  8.        proxy_read_timeout 5s; 
  9.        proxy_send_timeout 5s; 
  10.   
  11.        proxy_next_upstream error timeout; 
  12.        proxy_next_upstream_timeout 0; 
  13.        proxy_next_upstream_tries 0; 
  14.   
  15.        proxy_pass http://backend_server; 
  16.        add_header upstream_addr $upstream_addr; 
  17.     } 

backend_server定義了兩個(gè)上游服務(wù)器192.168.61.1:9080(返回hello)和192.168.61.1:9090(返回hello2)。

如上指令主要有三組配置:網(wǎng)絡(luò)連接/讀/寫超時(shí)設(shè)置、失敗重試機(jī)制設(shè)置、upstream存活超時(shí)設(shè)置。

網(wǎng)絡(luò)連接/讀/寫超時(shí)設(shè)置。

  • proxy_connect_timeout time:與后端/上游服務(wù)器建立連接的超時(shí)時(shí)間,默認(rèn)為60s,此時(shí)間不超過75s。
  • proxy_read_timeout time:設(shè)置從后端/上游服務(wù)器讀取響應(yīng)的超時(shí)時(shí)間,默認(rèn)為60s,此超時(shí)時(shí)間指的是兩次成功讀操作間隔時(shí)間,而不是讀取整個(gè)響應(yīng)體的超時(shí)時(shí)間,如果在此超時(shí)時(shí)間內(nèi)上游服務(wù)器沒有發(fā)送任何響應(yīng),則Nginx關(guān)閉此連接。
  • proxy_send_timeout time:設(shè)置往后端/上游服務(wù)器發(fā)送請(qǐng)求的超時(shí)時(shí)間,默認(rèn)為60s,此超時(shí)時(shí)間指的是兩次成功寫操作間隔時(shí)間,而不是發(fā)送整個(gè)請(qǐng)求的超時(shí)時(shí)間,如果在此超時(shí)時(shí)間內(nèi)上游服務(wù)器沒有接收任何響應(yīng),則Nginx關(guān)閉此連接。

對(duì)于內(nèi)網(wǎng)高并發(fā)服務(wù),請(qǐng)根據(jù)需要調(diào)整這幾個(gè)參數(shù),比如內(nèi)網(wǎng)服務(wù)TP999為1s,可以將連接超時(shí)設(shè)置為100~500毫秒,而讀超時(shí)可以為1.5~3秒左右。

失敗重試機(jī)制設(shè)置。

  1. proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_403 | http_404 | non_idempotent | off ...: 

配置什么情況下需要請(qǐng)求下一臺(tái)上游服務(wù)器進(jìn)行重試。默認(rèn)為“errortimeout”。error表示與上游服務(wù)器建立連接、寫請(qǐng)求或者讀響應(yīng)頭出錯(cuò)。timeout表示與上游服務(wù)器建立連接、寫請(qǐng)求或者讀響應(yīng)頭超時(shí)。invalid_header表示上游服務(wù)器返回空的或錯(cuò)誤的響應(yīng)頭。http_XXX表示上游服務(wù)器返回特定的狀態(tài)碼。non_idempotent表示RFC-2616定義的非冪等HTTP方法(POST、LOCK、PATCH),也可以在失敗后重試下一臺(tái)上游服務(wù)器(即默認(rèn)冪等方法GET、HEAD、PUT、DELETE、OPTIONS、TRACE才可以重試)。off表示禁用重試。

重試不能無限制進(jìn)行,因此,需要如下兩個(gè)指令控制重試次數(shù)和重試超時(shí)時(shí)間。

  • proxy_next_upstream_tries number:設(shè)置重試次數(shù),默認(rèn)0表示不限制,注意此重試次數(shù)指的是所有請(qǐng)求次數(shù)(包括第一次和之后的重試次數(shù)之和)。
  • proxy_next_upstream_timeout time:設(shè)置重試最大超時(shí)時(shí)間,默認(rèn)0表示不限制。

即在proxy_next_upstream_timeout時(shí)間內(nèi)允許proxy_next_upstream_tries次重試。如果超過了其中一個(gè)設(shè)置,則Nginx也會(huì)結(jié)束重試并返回客戶端響應(yīng)(可能是錯(cuò)誤碼)。

如下配置表示當(dāng)error/timeout時(shí)重試upstream中的下一臺(tái)上游服務(wù)器,如果重試的總時(shí)間超出了6s或者重試了1次,則表示重試失敗(因?yàn)橹耙呀?jīng)請(qǐng)求一次了,所以還能重試一次),Nginx結(jié)束重試并返回客戶端響應(yīng)。

  1. proxy_next_upstream error timeout; 
  2. proxy_next_upstream_timeout 6s; 
  3. proxy_next_upstream_tries 2; 

(4) upstream存活超時(shí)設(shè)置

max_fails和fail_timeout:配置什么時(shí)候Nginx將上游服務(wù)器認(rèn)定為不可用/不存活。當(dāng)上游服務(wù)器在fail_timeout時(shí)間內(nèi)失敗了max_fails次,則認(rèn)為該上游服務(wù)器不可用/不存活。并在接下來的fail_timeout時(shí)間內(nèi)從upstream摘掉該節(jié)點(diǎn)(即請(qǐng)求不會(huì)轉(zhuǎn)發(fā)到該上游服務(wù)器)。

什么情況下被認(rèn)定為失敗呢?其由 proxy_next_upstream定義,不過,不管 proxy_next_upstream如何配置,error, timeout and invalid_header 都將被認(rèn)為是失敗。

如server 192.168.61.1:9090max_fails=2 fail_timeout=10s;表示在10s內(nèi)如果失敗了2次,則在接下來的10s內(nèi)認(rèn)定該節(jié)點(diǎn)不可用/不存活。這種存活檢測機(jī)制是只有當(dāng)訪問該上游服務(wù)器時(shí),采取惰性檢查,可以使用ngx_http_upstream_check_module配置主動(dòng)檢查。

max_fails設(shè)置為0表示不檢查服務(wù)器是否可用(即認(rèn)為一直可用),如果upstream中僅剩一臺(tái)上游服務(wù)器時(shí),則該服務(wù)器是不會(huì)被摘除的,將從不被認(rèn)為不可用。

(5) ngx_lua超時(shí)設(shè)置

當(dāng)我們使用ngx_lua時(shí),也請(qǐng)考慮設(shè)置如下網(wǎng)絡(luò)連接/讀/寫超時(shí)。

  1. lua_socket_connect_timeout  100ms; 
  2. lua_socket_send_timeout    200ms; 
  3. lua_socket_read_timeout    500ms; 

在使用lua時(shí),我們會(huì)按照如下策略進(jìn)行重試。

  1. if (status == 502 or status == 503 or status ==504) and request_time < 200 then 
  2.     resp =capture(proxy_uri) 
  3.     status =resp.status 
  4.     body =resp.body 
  5.    request_timerequest_time = request_time + tonumber(var.request_time) * 1000 
  6. end 

即如果狀態(tài)碼是500/502/503/504時(shí),并且該次請(qǐng)求耗時(shí)在200毫秒以內(nèi),則我們進(jìn)行一次重試。

2. Twemproxy

Twemproxy是Twitter開源的Redis和Memcache代理中間件,其目的是減少與后端緩存服務(wù)器的連接數(shù)。

  • timeout:表示與后端服務(wù)器建立連接、接收響應(yīng)的超時(shí)時(shí)間,默認(rèn)永不超時(shí)。
  • server_retry_timeout和server_failure_limit:當(dāng)開啟auto_eject_hosts,即當(dāng)后端服務(wù)器不可用時(shí)自動(dòng)摘除這些節(jié)點(diǎn)并在一定時(shí)間后進(jìn)行重試。server_failure_limit設(shè)置連續(xù)失敗多少次后將節(jié)點(diǎn)臨時(shí)摘除,server_retry_timeout設(shè)置摘除節(jié)點(diǎn)后等待多久進(jìn)行重試,從而保證不永久性的將節(jié)點(diǎn)摘除。

二、Web容器超時(shí)

筆者生產(chǎn)環(huán)境用的Java Web容器是Tomcat,本部分將以Tomcat8.5作為例子進(jìn)行講解。

  • connectionTimeout:配置與客戶端建立連接超時(shí)時(shí)間,從接收到連接后在配置的時(shí)間內(nèi)還沒有接收到客戶端請(qǐng)求行時(shí),將被認(rèn)定為連接超時(shí),默認(rèn)為60000(60s)。
  • socket.soTimeout:從客戶端讀取請(qǐng)求數(shù)據(jù)的超時(shí)時(shí)間,默認(rèn)同connectionTimeout,NIO and NIO2 支持該配置。
  • asyncTimeout:Servlet 3異步請(qǐng)求的超時(shí)時(shí)間,默認(rèn)為30000(30s)。
  • disableUploadTimeout 和connectionUploadTimeout:當(dāng)配置disableUploadTimeout為false時(shí)(默認(rèn)為true,和connectionTimeout一樣),文件上傳將使用connectionUploadTimeout作為超時(shí)時(shí)間。
  • keepAliveTimeout和maxKeepAliveRequests:和Nginx配置類似。keepAliveTimeout默認(rèn)為connectionTimeout,配置-1表示永不超時(shí)。maxKeepAliveRequests默認(rèn)為100。

三、中間件客戶端超時(shí)與重試

JSF是京東自研的SOA框架,主要有三個(gè)組件:注冊(cè)中心、服務(wù)提供端、服務(wù)消費(fèi)端。

  • 首先是服務(wù)提供端/消費(fèi)端與注冊(cè)中心之間的進(jìn)行服務(wù)注冊(cè)/發(fā)現(xiàn)時(shí)可以配置timeout(調(diào)用注冊(cè)中心超時(shí)時(shí)間,默認(rèn)為5s)和connectTimeout(連接注冊(cè)中心的超時(shí)時(shí)間,默認(rèn)為20s)。
  • 服務(wù)提供端可以配置timeout(服務(wù)端調(diào)用超時(shí),默認(rèn)為5s)。
  • 服務(wù)消費(fèi)端可以配置timeout(調(diào)用端調(diào)用超時(shí)時(shí)間,默認(rèn)為5s),connectTimeout(建立連接超時(shí)時(shí)間,默認(rèn)為5s),disconnectTimeout(斷開連接/等待結(jié)果超時(shí)時(shí)間,默認(rèn)為10s),reconnect(調(diào)用端重連死亡服務(wù)端的間隔,配置小于0表示不重連,默認(rèn)為10s),heartbeat(調(diào)用端往服務(wù)端發(fā)心跳包間隔,配置小于0代表不發(fā)送,默認(rèn)為30s),retries(失敗后重試次數(shù),默認(rèn)0不重試)。

Dubbo也有類似的配置,在此就不闡述了。

JMQ是京東消息中間件,主要有四個(gè)組件:注冊(cè)中心、Broker(JMQ的服務(wù)端實(shí)例,生產(chǎn)和消費(fèi)消息都跟它交互)、生產(chǎn)者、消費(fèi)者。

  • 首先是生產(chǎn)者/消費(fèi)者與Broker進(jìn)行發(fā)送/接收消息時(shí)可以配置connectionTimeout(連接超時(shí))、sendTimeout(發(fā)送超時(shí))、soTimeout(讀超時(shí))。
  • 生產(chǎn)者可以配置retryTimes(發(fā)送失敗后的重試次數(shù),默認(rèn)為2次)。
  • 消費(fèi)者可以配置pullTimeout(長輪詢超時(shí)時(shí)間,即拉取消息超時(shí)時(shí)間)、maxRetrys(最大重試次數(shù),對(duì)于消費(fèi)者要允許無限制重試,即一直拉取消息)、retryDelay(重試延遲,通過exponential配置延遲增加倍數(shù)一直增加到maxRetryDelay)、maxRetryDelay(最大重試延遲)。消費(fèi)者還需要配置應(yīng)答超時(shí)時(shí)間(服務(wù)端需要等待客戶端返回應(yīng)答才能移除消息,如果沒有應(yīng)答返回,則會(huì)等待應(yīng)答超時(shí),在這段時(shí)間內(nèi)鎖定的消息不能被消費(fèi),必須等待超時(shí)后才能被消費(fèi))。

對(duì)于消息中間件我們實(shí)際應(yīng)用中關(guān)注超時(shí)配置會(huì)少一些,因?yàn)樯a(chǎn)者默認(rèn)配置了重試次數(shù),可能會(huì)存在重復(fù)消息,消費(fèi)者需要進(jìn)行去重處理。

CXF可以通過如下方式配置CXF客戶端連接超時(shí)、等待響應(yīng)超時(shí)和長連接。

  1. HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); 
  2. httpClientPolicy.setConnectionTimeout(30000);//默認(rèn)為30s 
  3. httpClientPolicy.setReceiveTimeout(60000); //默認(rèn)為60s 
  4. httpClientPolicy.setConnection(ConnectionType.KEEP_ALIVE);//默認(rèn)為Keep- Alive 
  5. ((HTTPConduit)client.getConduit()).setClient(httpClientPolicy); 

Httpclient 4.2.x可以通過如下代碼配置網(wǎng)絡(luò)連接、等待數(shù)據(jù)超時(shí)時(shí)間。

  1. HttpParams params = new BasicHttpParams(); 
  2. //設(shè)置連接超時(shí)時(shí)間 
  3. Integer CONNECTION_TIMEOUT = 2 * 1000;    //設(shè)置請(qǐng)求超時(shí)2秒鐘 
  4. Integer SO_TIMEOUT = 2 * 1000;        //設(shè)置等待數(shù)據(jù)超時(shí)時(shí)間2秒鐘 
  5. Long CONN_MANAGER_TIMEOUT = 1L * 1000;        //定義了當(dāng)從ClientConnectionManager中檢索ManagedClientConnection實(shí)例時(shí)使用的毫秒級(jí)的超時(shí)時(shí)間 
  6. params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,CONNECTION_TIMEOUT); 
  7. params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT,SO_TIMEOUT); 
  8. //在提交請(qǐng)求之前,測試連接是否可用 
  9. params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK,true); 
  10. //這個(gè)參數(shù)期望得到一個(gè)java.lang.Long類型的值。如果這個(gè)參數(shù)沒有被設(shè)置,則連接請(qǐng)求就不會(huì)超時(shí)(無限大的超時(shí)時(shí)間) 
  11. params.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT,CONN_MANAGER_TIMEOUT); 
  12. PoolingClientConnectionManager conMgr = new PoolingClientConnectionManager(); 
  13. conMgr.setMaxTotal(200);//設(shè)置最大連接數(shù) 
  14. //是路由的默認(rèn)最大連接(該值默認(rèn)為2),限制數(shù)量實(shí)際使用DefaultMaxPerRoute并非MaxTotal 
  15. //設(shè)置過小,無法支持大并發(fā)(ConnectionPoolTimeoutException: Timeout waiting for connection frompool),路由是對(duì)maxTotal的細(xì)分 
  16. conMgr.setDefaultMaxPerRoute(conMgr.getMaxTotal());//(目前只有一個(gè)路由,因此讓他等于最大值) 
  17.   
  18. //設(shè)置訪問協(xié)議 
  19. conMgr.getSchemeRegistry().register(new Scheme("http",80, PlainSocketFactory. getSocketFactory())); 
  20. conMgr.getSchemeRegistry().register(new Scheme("https",443, SSLSocketFactory. getSocketFactory())); 
  21. httpClient = newDefaultHttpClient(conMgr, params); 
  22. httpClient.setHttpRequestRetryHandler(newDefaultHttpRequestRetryHandler(0, false)); 

因?yàn)槲覀兪褂胔ttp connection連接池,所以需要配置CONN_MANAGER_TIMEOUT,表示從連接池獲取http connection的超時(shí)時(shí)間。

此處還通過httpClient.setHttpRequestRetryHandler(newDefaultHttpRequestRetry Handler(0, false))配置了請(qǐng)求重試策略(默認(rèn)重試3次)。當(dāng)執(zhí)行請(qǐng)求時(shí)遇到異常時(shí)會(huì)調(diào)用retryRequest來判斷是否進(jìn)行重試,而retryRequest在以下情況不會(huì)進(jìn)行重試:達(dá)到重試次數(shù)、服務(wù)器不可達(dá)、連接被拒絕、連接終止、請(qǐng)求已發(fā)送。而冪等HTTP方法的請(qǐng)求、requestSentRetryEnabled=true且請(qǐng)求還未成功發(fā)送時(shí)可以重試。

如果響應(yīng)是503錯(cuò)誤狀態(tài)碼時(shí),如上重試機(jī)制是不可用的,則可以考慮使用AutoRetryHttpClient客戶端,其可以配置ServiceUnavailableRetryStrategy,默認(rèn)實(shí)現(xiàn)為DefaultServiceUnavailableRetryStrategy,可以配置重試次數(shù)maxRetries和重試間隔retryInterval。每次重試之前都會(huì)等待retryInterval毫秒時(shí)間。

假設(shè)我們服務(wù)有多個(gè)機(jī)房提供,其中一個(gè)機(jī)房服務(wù)出現(xiàn)問題時(shí)應(yīng)該自動(dòng)切到另一個(gè)機(jī)房,可以考慮使用如下方法。

  1. public static String get(List<String> apis, Object[] args, String encoding,Header[] headers, Integer timeout) throws Exception { 
  2.     Stringresponse = null
  3.     for(String api : apis) { 
  4.         String uri =UriComponentsBuilder.fromHttpUrl(api).buildAndExpand(args). toUriString(); 
  5.        response = HttpClientUtils.getDataFromUri(uri, encoding, headers,timeout); 
  6.         //如果失敗了,重試一次 
  7.         if(Objects.equal(response, HTTP_ERROR)){ 
  8.             continue; 
  9.         } 
  10.         //如果域名解析失敗重試 
  11.         if(Objects.equal(response,HTTP_UNKNOWN_HOST_ERROR)) { 
  12.            response = HTTP_ERROR; //掉用方根據(jù)這個(gè)判斷是否有問題 
  13.             continue; 
  14.         } 
  15.         if(Objects.equal(response,HTTP_SOCKET_TIMEOUT_ERROR)) { 
  16.            response = HTTP_ERROR; //調(diào)用方根據(jù)這個(gè)判斷是否有問題 
  17.             continue; 
  18.         } 
  19.         return response; 
  20.     } 
  21.     return response; 

參數(shù)傳入不同機(jī)房的API即可,當(dāng)其中一個(gè)不可用自動(dòng)重試另一個(gè)機(jī)房的API。

【本文是51CTO專欄作者“張開濤”的原創(chuàng)文章,作者微信公眾號(hào):開濤的博客( kaitao-1234567)】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2017-07-02 16:50:21

2017-06-04 16:24:27

線程線程池中斷

2017-05-18 16:07:23

回滾數(shù)據(jù)庫代碼

2024-09-25 08:32:05

2022-11-14 08:19:59

重試機(jī)制Kafka

2022-05-06 07:44:10

微服務(wù)系統(tǒng)設(shè)計(jì)重試機(jī)制

2017-05-10 11:40:29

緩存Nginx HTTP

2017-05-01 17:03:01

Java緩存分布式

2020-07-19 15:39:37

Python開發(fā)工具

2025-02-26 10:49:14

2021-02-20 10:02:22

Spring重試機(jī)制Java

2017-04-18 14:49:38

應(yīng)用層API代碼

2023-11-27 07:44:59

RabbitMQ機(jī)制

2025-01-03 08:44:37

kafka消息發(fā)送策略

2023-10-27 08:20:12

springboot微服務(wù)

2017-04-21 08:51:42

API緩存分布式

2025-05-28 01:15:00

Golang重試機(jī)制

2023-11-06 08:00:38

接口高可用機(jī)制

2017-05-05 10:13:03

應(yīng)用級(jí)緩存緩存代碼

2012-12-13 17:38:48

2012年度IT博客大IT博客大賽博客
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 九九综合九九 | 国产亚洲精品美女久久久久久久久久 | www.操com| 成人精品一区二区三区中文字幕 | 日韩精品一 | 日韩伦理一区二区 | 99国内精品久久久久久久 | 欧美日韩一区在线观看 | 四虎影院在线免费观看 | 国产乱码一二三区精品 | 综合久久久 | 国产成人精品久久 | 国产精品久久9 | 一区二区三区视频在线观看 | 久久久久国产成人精品亚洲午夜 | 在线看亚洲 | 精品视频网 | 在线观看视频一区 | 国产视频福利一区 | 成人亚洲视频 | 亚洲成人精品一区 | 成人福利视频网站 | 青春草在线 | www精品美女久久久tv | 亚洲精品一区二区三区四区高清 | 一区二区av| 日韩久久综合 | 国产精品自在线 | 精品国产乱码久久久久久蜜柚 | 天堂资源最新在线 | 国产精品欧美一区二区三区不卡 | 羞羞的视频免费看 | 成人天堂 | 久久97精品 | 精品国产一二三区 | 成人国产在线视频 | 欧美一区二区三区国产 | 男女免费观看在线爽爽爽视频 | 黑人中文字幕一区二区三区 | 97国产成人 | 亚洲香蕉在线视频 |