程序中如何設計backup request功能


Retry

集群中有client、server1, server2三台機器,client需要向server請求數據,如果server1響應超時,則請求server2。server1、server2互為備份,包含同樣的數據。

client:

for (id = 0; id < 2; id++)
{
   if (TIMEOUT == do_request(server[id], timeout, req) )
   {
          continue; // retry next server
   }
}

timeout是外部傳給client的總超時數。上面的代碼有一個問題:當網絡阻塞或者server十分繁忙的時候,do_request會超時,一旦超時,則總超時時間都被耗盡,根本沒有剩余時間去重試下一個server。

因此,正確的retry設計需要考慮到“網絡阻塞或者server十分繁忙”的情況,分給每個server的timeout時間只能是總timeout的一部分,代碼改寫如下:

for (id = 0; id < 2; id++)
{
   if (TIMEOUT == do_request(server[id], timeout * get_timeout_percent(), req) )
   {
          continue; // retry next server
   }
}

不過,對於server掛掉的情況(socket層面無法連接)do_request請求這個server會立即失敗,可以不設置timeout_percent。

Backup Request

Jeff Dean的一篇論文中介紹了Google利用backup request來大幅度降低響應延遲的問題,在論文中他將這種請求成為Tied Request。他在Achieving Rapid Response Times in Large Online Services這篇ppt中對此進行了專門的論述。

其原理很簡單,用一個例子來簡單闡述:

集群中有client、server1, server2三台機器,client需要向server請求數據,如果server1響應超時,則請求server2。server1、server2互為備份,包含同樣的數據。client收到任意響應數據后立即通知其他請求過的server取消操作。

有兩種設計方案:

方案一:

  1. client向server1發出req請求,req在server1任務隊列中排隊
  2. server1開始執行req,在執行前給client發一個quick response
  3. client如果在超時時間內收到quick response則不發起backup task,否則client一旦超時,就立即發起backup task
  4. client收到任意server的結果時,立即給其它所有發給過請求的server發cancel request
  5. client先行退出
  6. 對於執行任務的server,它如果及時收到了cancel request,則直接取消任務,如果收到不及時,任務已經開始,則還是老老實實做任務。任務做完后丟棄結果。
  7. client收到過期的結果直接丟棄

方案二:

  1. client向server1發出req請求
  2. client等待超時,則立即向server2發req請求
  3. 任意server返回了req結果,則發cancel request給其它相關server
  4. client收到過期的結果直接丟棄

note:無論方案1還是方案二,實現這樣的異步系統的時候都要很小心,一要防止內存泄露,一要方式提前析構導致野指針。

超時如何選擇

建議選擇p99或者p95,因為backup request操作是用來實現消除長尾的,並不是提升性能的。如果將該值設置過低,則會由於backup request的請求量過大而導致集群壓力增大(假設選擇p50作為其延時,這樣便會有50%的請求向server2發送請求,系統負載便會增大50%)。

如果超時設置的是p999時間,大約1000個請求里只有1個請求會發送backup request,因此額外請求量(也就是開啟backup request的額外開銷)比例在0.1%左右。依此類推,若想要降低P99時延,則可以將超時設置為P99延遲,由此會增加1%的額外讀流量。

設計要點

設計Backup request的關鍵是要防止服務器繁忙時期的請求風暴。在服務器繁忙時期client容易發生等待超時,傾向於發送backup request。大量的backup request會進一步讓服務器更繁忙,於是請求風暴誕生了。防止請求風暴的要點是區分普通超時和風暴期超時。

從統計的角度看,普通超時的模式與風暴期超時的模式肯定有很大區別,這是一個入手點。

從使用方式上,區分scan和get也可以一定程度防止請求風暴。在OceanBase中,get請求是對延遲敏感的,scan請求則要求低一些。而恰好get請求對系統的壓力也小很多。所以,在OceanBase中可以只對get請求使用backup request。

對於非冪等性操作慎用backup request!!!

小結

retry和backup request之前的區別在於retry不會給server發送cancel request,也不會等待多次請求使用最先返回的響應。

轉載CSDN且有完善和修改


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM