我們如何在 x10 工作負載遠程增加的情況下倖存下來,我們得出了什麼結論

嘿哈布爾! 在過去的幾個月裡,我們生活在一個非常有趣的情況下,我想分享我們關於基礎設施擴展的故事。 在此期間,SberMarket 的訂單量翻了兩番,並在 4 個新城市推出了這項服務。 雜貨配送需求的爆炸式增長要求我們擴展基礎設施。 閱讀剪輯下最有趣和最有用的結論。

我們如何在 x10 工作負載遠程增加的情況下倖存下來,我們得出了什麼結論

我叫 Dima Bobylev,我是 SberMarket 的技術總監。 由於這是我們博客上的第一篇文章,我將簡單介紹一下我自己和公司。 去年秋天,我參加了 Runet 的青年領袖競賽。 對於比賽我 寫了一個小故事 關於我們在 SberMarket 如何看待服務開發的內部文化和方法。 雖然我沒有贏得比賽,但我為自己制定了 IT 生態系統發展的基本原則。

在管理團隊時,重要的是要了解業務需求和每個開發人員的需求之間的平衡。 現在 SberMarket 每年增長 13 倍,這會影響產品,需要不斷增加數量和開發速度。 儘管如此,我們還是給開發者分配了足夠的時間進行初步分析和高質量的編碼。 形成的方法不僅有助於創建工作產品,而且有助於其進一步擴展和開發。 由於這種增長,SberMarket 已經成為雜貨配送服務中的領導者:我們每天交付約 18 個訂單,而 3500 月初只有約 XNUMX 個。

我們如何在 x10 工作負載遠程增加的情況下倖存下來,我們得出了什麼結論
一天,一位客戶要求 SberMarket 快遞員以非接觸方式將雜貨遞送給他——就在陽台上。

但是,讓我們談談細節。 在過去的幾個月裡,我們一直在積極擴展我們公司的基礎設施。 這種需要是由外部和內部因素解釋的。 在擴大客戶群的同時,聯網商店的數量從年初的 90 家增加到 200 月中旬的 XNUMX 多家。 當然,我們做好了準備,保留了主要的基礎設施,並指望在 Yandex 雲中託管的所有虛擬機都可以進行縱向和橫向擴展。 然而,實踐證明:“能出錯的都會出錯”。 今天我想分享這幾週發生的最奇怪的情況。 希望我們的經驗對你有用。

奴隸處於全面戰備狀態

甚至在大流行開始之前,我們就面臨著對後端服務器的請求數量增加的問題。 通過送貨上門訂購雜貨的趨勢開始流行起來,隨著​​與 COVID-19 相關的第一批自我隔離措施的出台,一整天的工作量在我們眼前急劇增加。 需要快速卸載主數據庫的主服務器並將一些讀取請求傳輸到副本服務器(從服務器)。

我們提前準備了這一步,為了這樣的操作,已經有 2 個從服務器在運行。 他們主要從事批處理任務,以生成用於與合作夥伴交換數據的信息提要。 這些過程產生了額外的負擔,並且在幾個月前就被正確地從括號中刪除了。 

由於復制發生在 Slave 上,我們堅持應用程序只能以只讀模式與它們一起工作的概念。 災難恢復計劃假設在發生災難時,我們可以簡單地掛載 Slave 代替 Master,並將所有寫入和讀取請求切換到 Slave。 但是我們也想用副本來滿足分析部門的需要,所以服務器並沒有完全設置為只讀狀態,每個主機都有自己的一組用戶,有些有寫入權限來保存中間計算結果。

達到一定的負載水平,我們在處理 http 請求時有足夠的 master 進行寫入和讀取。 XNUMX 月中旬,就在 Sbermarket 決定完全轉向遠程工作時,我們開始倍增 RPS 增長。 越來越多的客戶進入自我隔離或在家工作,這反映在負載指標上。

“主”的性能已經不夠用了,所以我們開始將一些最重的讀請求轉移到副本上。 為了透明地將寫入請求定向到 master,將讀取請求定向到 slave,我們使用了 ruby​​ gem”章魚”。 我們創建了一個特殊用戶,後綴為 _readonly,沒有寫權限。 但是由於其中一台主機的配置錯誤,部分寫請求代表具有適當權限的用戶去了從服務器。

問題並沒有立即顯現出來,因為。 增加的負載增加了奴隸的積壓。 早上發現數據不一致,當時在夜間導入之後,奴隸沒有“趕上”主人。 我們將此歸因於服務本身的高負載以及與新店開業相關的進口。 但是延遲數小時提供數據是不可接受的,我們將流程切換到第二個分析從站,因為它有о更大的資源並且沒有加載讀取請求(這就是我們向自己解釋缺乏複製滯後的方式)。

當我們弄清楚主從“蔓延”的原因時,分析已經因為同樣的原因失敗了。 儘管存在兩台額外的服務器,我們計劃在主機崩潰時將負載轉移到這台服務器上,但由於不幸的錯誤,結果在關鍵時刻沒有一台。

但由於我們不僅轉儲了數據庫(當時恢復大約 5 小時),而且還對主服務器進行了快照,因此我們設法在 2 小時內啟動了副本。 沒錯,在那之後,我們預計會滾動複製日誌很長時間(因為進程處於單線程模式,但那是完全不同的故事)。

結論: 在發生這樣的事件之後,很明顯應該放棄限制用戶寫入的做法,並且應該將整個服務器聲明為只讀。 使用這種方法,您可以確保副本在關鍵時刻可用。

即使優化一個繁重的查詢也能使數據庫起死回生

雖然我們不斷更新網站上的目錄,但我們對從服務器的請求允許稍微落後於主服務器。 我們發現並排除“突然跑偏”slave問題的時間超過了“心理關卡”(這段時間可以更新價格,客戶會看到過時的數據),被迫切換對主數據庫服務器的所有查詢。 結果,該站點速度很慢……但至少可以正常工作。 當 Slave 正在恢復時,除了優化,我們別無選擇。 

當從服務器正在恢復時,時間慢慢拖延,主服務器仍然過載,我們根據帕累託法則將所有努力用於優化活動任務:我們選擇了提供大部分負載的 TOP 查詢並開始調優。 這是即時完成的。

一個有趣的效果是,加載到眼球中的 MySQL 會對流程中的微小改進做出響應。 優化僅佔總負載 5% 的幾個查詢已經顯示出明顯的 CPU 卸載。 因此,我們能夠為 Master 提供可接受的資源儲備來處理數據庫,並獲得必要的時間來恢復副本。 

結論: 即使是很小的優化也可以讓您“承受”過載數小時。 這足以讓我們用副本恢復服務器。 順便說一句,我們將在以下帖子之一中討論查詢優化的技術方面。 如果對您有用,請訂閱我們的博客。

組織對合作夥伴服務健康狀況的監控

我們處理來自客戶的訂單,因此我們的服務不斷與第三方 API 交互——這些是發送 SMS 的網關、支付平台、路由系統、地理編碼器、聯邦稅務局和許多其他系統。 當負載開始快速增長時,我們開始遇到合作夥伴服務 API 的局限性,這是我們以前甚至沒有想過的。

意外超出合作夥伴服務配額可能會導致您自己停機。 許多 API 會阻止超過限制的客戶端,在某些情況下,過多的請求會使合作夥伴的生產超載。 

例如,在派送數量增長的時候,伴隨的服務無法應對其配送和路線確定的任務。 結果發現訂單是下了,但是創建路由的服務不工作了。 我必須說,我們的後勤人員在這些條件下完成了幾乎不可能完成的任務,而團隊的明確互動有助於彌補暫時的服務失敗。 但是一直手動處理如此大量的應用程序是不現實的,一段時間後我們會遇到訂單和執行之間無法接受的差距。 

在我們就新條件達成一致並等待一些合作夥伴提供現代化服務的過程中,我們採取了多項組織措施,團隊協調良好的工作幫助爭取了時間。 在高流量的情況下,還有其他 API 可以提供高耐久性和超高速率。 例如,一開始,我們使用一個眾所周知的映射 API 來確定交付點的地址。 但是在月底,他們收到了將近 2 萬盧布的圓形賬單。 在那之後,我們決定迅速更換它。 我不會做廣告,但我會說我們的開支已經大大減少了。
我們如何在 x10 工作負載遠程增加的情況下倖存下來,我們得出了什麼結論

結論: 必須監控所有合作夥伴服務的工作條件並將其牢記在心。 即使今天看起來它們對您來說“有很大優勢”,但這並不意味著明天它們不會成為增長的障礙。 當然,最好提前就增加服務請求的財務條款達成一致。 

有時事實證明需要更多的黃金“(c)沒有幫助

我們習慣於在主數據庫或應用服務器上“堵嘴”,但在擴展時,會在意想不到的地方出現問題,站點全文搜索,我們使用Apache Solr引擎。 隨著負載增加,我們注意到響應時間減少,服務器 CPU 負載達到 100%。 可以更簡單的是 - 為 Solr 容器提供更多資源。

服務器沒有預期的性能提升,而是簡單地“死了”。 它立即加載 100%,響應更慢。 最初,我們有 2 個內核和 2 GB 的 RAM。 我們決定做通常有用的事情——我們給服務器 8 個內核和 32 GB。 一切都變得更糟了(我們將在另一篇文章中詳細告訴您具體情況和原因)。 

幾天后,我們弄清楚了這個問題的複雜性,並在 8 核和 32 GB 的情況下實現了最佳性能。 這種配置使我們能夠在今天繼續增加負載,這非常重要,因為增長不僅體現在客戶方面,還體現在連接的商店數量上——在 2 個月內,它們的數量翻了一番。 

結論: “添加更多鐵”等標準方法並不總是有效。 因此,在擴展任何服務時,您需要很好地了解它如何使用資源並提前測試它在新條件下的工作。 

無狀態是簡單水平擴展的關鍵

總的來說,我們的團隊堅持一個眾所周知的方法:服務不應該有內部狀態(stateless),並且應該獨立於運行時環境。 這使我們能夠通過簡單的水平縮放來承受負載的增加。 但是我們有一個服務異常 - 一個用於長時間後台任務的處理程序。 他參與了發送電子郵件和短信、處理事件、生成提要、導入價格和股票以及處理圖像。 正好依賴本地文件存儲,而且是單份的。 

當處理器隊列中的任務數量增加時(這自然會隨著訂單數量的增加而發生),承載處理器和文件存儲的主機的性能成為一個限制因素。 結果,更新範圍和價格、向用戶發送通知以及許多其他卡在隊列中的關鍵功能停止了。 Ops 團隊迅速將文件存儲遷移到類似 S3 的網絡存儲,這使我們能夠籌集到幾台功能強大的機器來擴展後台任務處理程序。

結論: 所有組件都必須無一例​​外地遵守無狀態規則,即使看起來“我們絕對不會在這裡休息”。 最好花一點時間正確組織所有系統的工作,而不是匆忙重寫代碼並修復過載的服務。

集約化發展的 7 條原則

儘管有額外的產能可用,但在增長的過程中,我們踩了一些耙子。 在此期間,訂單數量增長了4倍多。 現在我們已經在 17 個城市每天交付超過 000 個訂單,併計劃進一步擴大地域——62 年上半年,該服務有望在整個俄羅斯推出。 為了應對不斷增長的工作量,考慮到已經充滿的顛簸,我們為自己推導出了在不斷增長的環境中工作的 2020 條基本原則:

  1. 事件管理. 我們在 Jira 中創建了一個看板,其中每個事件都以工單的形式反映出來。 這將幫助您真正確定優先級並完成與事件相關的任務。 的確,從本質上講,犯錯誤並不可怕——可怕的是在同一場合犯兩次錯誤。 對於那些在糾正原因之前事件再次發生的情況,應準備好操作說明,因為在重負載期間,以閃電般的速度做出反應很重要。
  2. 監控 所有基礎設施元素都需要,無一例外。 多虧了他,我們才能夠預測負載的增長,並正確選擇優先消除的“瓶頸”。 最有可能的是,在高負載下,您甚至沒有想到的一切都會崩潰或開始減速。 因此,最好在第一批事件發生後立即創建新警報,以便對其進行監控和預測。
  3. 正確的警報 剛好需要負載急劇增加。 首先,他們必須準確報告損壞的內容。 其次,不應該有很多警報,因為大量的非關鍵警報通常會導致忽略所有警報。
  4. 應用程序必須是無狀態的。 我們已確保這條規則沒有例外。 您需要完全獨立於運行時環境。 為此,您可以將共享數據存儲在數據庫中,或者直接存儲在 S3 中。 更好的是,遵守規則。 https://12factor.net. 時間劇增時,根本沒有辦法優化代碼,只能通過直接增加計算資源和橫向擴展來應對負載。
  5. 外部服務的配額和性能。 隨著快速增長,問題可能不僅出現在您的基礎設施中,也可能出現在外部服務中。 最煩人的事情是發生這種情況不是因為失敗,而是因為達到配額或限制。 因此,外部服務應該像您自己一樣擴展。 
  6. 分離進程和隊列。 當其中一個網關發生堵塞時,這會有很大幫助。 如果發送 SMS 的隊列滿了不會干擾信息系統之間的通知交換,我們就不會遇到數據傳輸延遲。 如果他們分開工作,增加工人的數量會更容易。
  7. 財務現實。 當數據流量出現爆炸式增長時,沒有時間考慮資費和訂閱。 但必須記住它們,特別是如果您是一家小公司。 任何 API 的所有者以及您的託管服務提供商都可以設置大額賬單。 所以仔細閱讀合同。

結論

並非沒有損失,但我們挺過了這個階段,今天我們嘗試堅持發現的所有原則,每台機器都有能力輕鬆提高 x4 性能以應對一些意外情況。 

在接下來的帖子中,我們將分享我們調查 Apache Solr 性能下降的經驗,並討論查詢優化以及與聯邦稅務局的互動如何幫助公司節省資金。 訂閱我們的博客,以免錯過任何內容,如果您在流量增長過程中遇到過類似的麻煩,請在評論中告訴我們。

我們如何在 x10 工作負載遠程增加的情況下倖存下來,我們得出了什麼結論

只有註冊用戶才能參與調查。 登入, 請。

您是否曾經因為以下原因導致負載急劇增加而導致服務速度減慢/下降:

  • 企業排放佔全球 55,6%無法快速添加計算資源10

  • 企業排放佔全球 16,7%託管服務提供商基礎設施限制3

  • 企業排放佔全球 33,3%第三方 API6 限制

  • 企業排放佔全球 27,8%違反無狀態原則的應用程序5

  • 企業排放佔全球 88,9%自身服務的非最優代碼16

18 位用戶投票。 6 名用戶棄權。

來源: www.habr.com

添加評論