建築釺


連接內容和Slashdot效應(或我如何學會縮放api)

紮克麥考密克 通過紮克麥考密克2019年6月20日

我們的客戶與我們的產品集成的最酷的方式之一是通過一個我們manbetx万博全站客户端稱之為“連接內容”的功能。通過利用定製的HTTP端點—由客戶擁有或通過其合作夥伴擁有—我們的客戶可以在消息發送之前將定製的、按需的內容注入到消息中。manbetx万博全站客户端manbetx万博全站客户端客戶將其用於各種各樣的用例,例如個性化推薦、天氣信息和自動語言翻譯。然而,一個常見的問題是,為了讓Braze快速發送消息,這些端點必須能夠吸收巨大的流量峰值。

在21世紀初,網絡服務由於巨大的流量峰值而不可用的現象被稱為Slashdot效應.由Slashdot上的熱門文章鏈接的站點會很快看到大量的流量,幾乎立即變得不可用——這就是在廉價、易於部署的自動擴展和負載平衡服務出現之前的情況。即使在今天,這個問題仍然存在,就Connected Content而言,我們已經看到了類似的“Braze效應”,由於Braze的發送速度,原本為低流量、持續的流量設計的端點會受到一個巨大的流量峰值的衝擊,從而將Connected Content注入消息中。

構建一些能夠吸收大量但不頻繁的流量峰值的東西可能是棘手的。圍繞應用服務器調優、策略性數據庫選擇和明智的負載測試,可以采取各種策略,以便構建符合該概要文件的內容,即使成本相對較低。

在這篇文章中,我們將使用我最喜歡的構建簡單web服務的框架——Django來深入探討這個問題。它支持多數據庫、緩存後端、排隊係統等開箱即用。我們將逐步介紹使用Django開發和迭代高性能API的過程,該API能夠吸收巨大的流量峰值。我們將使用Heroku托管我們的服務flood.io用於負載測試。

我提供了關於如何在MacOS的最新版本上做這個的說明家釀,這是一個命令行包管理器,但您可以根據自己選擇的平台進行調整。

安裝和初始化

要開始,你需要Postgres而且複述,安裝。

然後,克隆示例存儲庫並簽出第一步。

克隆了示例存儲庫之後,您將希望安裝需求並啟動服務器。

這將使您在本地運行,以便您可以測試端點是否工作。要通過CLI工具開始使用Heroku,創建一個新的應用程序,並通過git將你的代碼推送到它。

一旦你在Heroku上設置好了,當你訪問你的新應用程序時,你應該會看到如下內容:

進入你的應用程序的Heroku儀表板,你會看到如下的屏幕:

點擊“Configure Dynos”,選擇1x標準Dyno作為默認選項。對於我們現在的測試用例來說,這應該足夠強大了。

一旦你完成了這些,你也會想要修改你的Heroku Postgres實例。我們將繼續使用Standard-0大小的實例。它應該允許足夠的連接,並且足夠快,不會過多地限製我們的響應時間。

你將有兩個實例的Heroku Postgres一段時間。您需要使用類似於下麵的命令將新實例提升為默認實例(注意:HEROKU_POSTGRESQL_IVORY可能不是您特定實例的環境變量/名稱)。

遷移到較大的數據庫實例後,可以刪除較小的舊數據庫實例。當您完成後,您的儀表板應該看起來像這樣。

最後,我們想要關閉調試模式,所以繼續,將djjango_debug環境變量設置為false。

我們的第一個測試:基本設置

我喜歡使用flood.io對於負載測試—使用相對較少的配置生成大量負載相對簡單。我們的第一個測試將在500名用戶的5分鍾內擊中我們的端點。您需要將測試配置為如下截圖所示。注意:您可能需要購買洪水信用。IO用於一些更密集的測試

接下來,啟動測試!

當你的網格正在啟動,你的測試即將啟動時,回到Heroku儀表板,這樣我們就可以從你的應用程序的角度看到發生了什麼。

我們會輪流發洪水。IO和應用程序的指標指示板。以下是測試結束時的大致情況。

我們從來沒有建立一個頁麵,所以所有的錯誤都是400。平均響應時間約600ms,最大約4秒。下一個什麼?

讓我們創建一個數據庫模型,生成一些假數據,然後創建一個頁麵來呈現數據庫中的內容。為了節省一些時間,隻需簽出並在示例項目中推進下一步。

從這裏開始,在本地執行以下步驟來確認一切正常。

訪問http://127.0.0.1:8000/並確認返回給您的是一個140個字符的字符串。這是我們的“數據”,用來模擬您可能希望Connected Content端點為每個用戶返回的內容。

在Heroku端,我們還需要生成種子數據。為此,使用Run Console選項並運行以下命令。

訪問您的應用程序,並確認它的工作方式與本地相同。

我們的第二個測試:服務真實數據

在這次測試中,我們將使用同樣大小的洪水。

一旦啟動測試,您將看到不同的(更好的)結果!

在Heroku方麵,我們可以看到我們現在成功地處理了請求。太棒了!

我們現在建了一個頁麵,所以這次應該能拿到200塊。我們的平均響應時間約為47毫秒,最大約為150毫秒——太棒了!我們可能每次在數據庫中都要訪問表緩存,所以我們有一些選項來推送我們的係統:

  • 我們可以添加更多的並發請求
  • 我們可以添加更多的種子數據,這樣所有的數據都不會緩存到數據庫中

讓我們添加更多的請求!

我們的第三次測試:10倍的用戶數量

這次我們將使用5000個用戶來模擬10倍的負載。

這次我們有5分鍾的時間,每分鍾大約有9k個請求,平均響應時間為14秒。我們也開始看到一些失敗的請求。這不是很好,讓我們想想如何更好地擴展我們的係統。我們現在有兩種方法可以擴大規模:

  • 我們可以添加額外的dynos
  • 我們可以更改服務器應用程序

我們將使用第二種選擇。

注意:gunicorn,使用幼稚的設置,將使用一個工作者池,並不能很好地處理並發請求。讓我們安裝gevent並告訴我們的服務器進程使用greenlet而不是同步工作器。

您可以隻檢查下一步並部署到Heroku,而不是自己做這些。

訪問您的應用程序並確認它仍然可以工作。

我們的第四個測試:調優應用服務器

哇,發生了什麼事?我們嚐試了相同的5000個用戶,但我們的應用程序無法跟上!錯誤率幾乎是90%。什麼是錯的。我們來查一下Heroku的日誌。

我會解釋這是什麼意思,這樣你就不用去穀歌了!在gunicorn上使用異步工作器的一個警告是,每個工作器將打開自己的數據庫連接。在日誌中,我們可以看到由於連接太多而拋出異常。

查看Heroku儀表板上的Postgres指標頁麵,我們可以看到我們比第一次打開了多得多的連接(我們第一次使用的是一位數的連接)。

我們試試別的吧。女服務員是一個純python的WSGI服務器,它將請求緩衝到一個固定的工作池,但仍然以異步方式處理傳入的HTTP連接。讓我們安裝它,並相應地更改我們的Procfile。像往常一樣,你可以檢查這一步。

和往常一樣,訪問您的應用程序以確認它是否正常工作。

注意:在部署以釋放數據庫連接之前,可能需要重新啟動dynos。

我們的第五個測試:更好的應用服務器

這一次我們很容易能夠在5分鍾內處理5000個並發用戶,錯誤率為0%,平均響應時間為178ms。太棒了!讓我們添加更多的並發請求—我們根本沒有在這方麵增加負擔!

我們的第六次測試:2倍多的用戶

對於5分鍾內的10k個並發用戶,我們提供了大約108k個請求。我們可能會在這個範圍內達到並發性高峰:錯誤增加,響應時間增加到平均大約9秒。

讓我們嚐試通過添加額外的動態來擴大規模。

我們的第七項測試:雙倍Dynos

這次我們也使用了10k並發用戶,但能夠處理接近180k的請求。我們的平均響應時間下降到215毫秒。太棒了!讓我們試著再增加一點負荷。

第八次測試:15k用戶

這次我們在5分鍾內處理了15k個並發用戶,處理了大約150k個請求,響應時間增加到了11秒。在某種程度上,我們又達到了並發高峰。不過,下一次我們將嚐試一種新的策略—不訪問數據庫,而是訪問數據庫複述,代替。Redis是內存中的鍵值存儲,所以我們存儲數據的方式和使用關係數據庫的方式有點不同。對於關係數據庫,我們可能會將規範化表連接在一起,以將所需的一切放在一起。有了Redis,我們需要改變對存儲的看法。

在git中查看下一步並查看新代碼。

要在本地測試這個,你需要運行下麵的程序來給我們的Redis實例添加數據。

在本地訪問你的應用程序,確認它工作正常,然後通過運行控製台再次在Heroku上複製它。你需要添加一個Redis實例到你的應用程序。我使用Premium-0,因為它可以處理我們的兩個dynos所需的傳入連接數量。

我們的第九次測試:Redis超過Postgres

再次使用10k並發用戶(我們將其與我們的第7次測試進行比較),我們可以看到我們的應用程序在5分鍾內處理了大約190k請求,響應時間下降到了34ms。哇!讓我們看看我們能否用Redis處理這15000個用戶!

我們的最終測試:擁有15k用戶的Redis

在5分鍾內,有15k個並發用戶,我們能夠處理255k個請求。響應時間恢複了,但隻有1.4秒,並且我們仍然很少有失敗的請求。

在這一點上,通過查看Heroku指標頁麵,我們可能在dynos上達到了高峰並發(注意,它們的負載非常高)。這表明,我們可以用一個Redis實例和兩個標準的dynos每秒處理近1000個請求。對於一個廉價的Heroku部署來說,這是一個非常好的規模!

總結

當您設置高可用性、低延遲的api(例如Connected Content端點)時,請考慮模擬此模型。用事務係統中的相關數據填充Redis數據庫的一種方法是使用保存後鉤子(如果你使用的是類似於Django中內置的ORM)來保存相關信息到Redis,以類似於Connected Content端點的URL方案的方式鍵入。這意味著如果你在擊球https://my-application.com/data?user_id=1234,您可以將1234用戶的數據存儲在密鑰1234中HSET.這將非常快的查詢,並允許您以最少的額外基礎設施獲得最高的速度。

如果你對這種規模的工作感興趣,可以查看我們的招聘網站https://grnh.se/94ab43241.如果你想聊聊規模,發郵件給(電子郵件保護).我想聽聽你的想法!

對在Braze工作感興趣?看看我們目前的職位空缺!


紮克麥考密克

紮克麥考密克

紮克是紐約市的一名軟件工程師。他的熱情包括解決大型分布式係統的bug,然後寫博客,彈電吉他,慢慢地學習匈牙利語。

相關內容

《黑客日的故事:勇敢的產品工程經理德裏克·舒爾茨如何解決抄襲挑戰

閱讀更多

Braze如何擁抱國際化

閱讀更多

開發人員

來自黑客日的故事:Braze高級軟件工程師Hal Anil計算了行使期權的稅收影響

閱讀更多

開發人員

黑客日的故事:膽大的高級軟件工程師約翰·帕森斯如何在他的第一個黑客日幫助建造了火炬感恩節機器人

閱讀更多