使用 Amazon Neptune 的 AWS Lambda 功能 - Amazon Neptune

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 Amazon Neptune 的 AWS Lambda 功能

AWS Lambda 功能在 Amazon Neptune 應用中有很多用途。在這裡,我們提供將 Lambda 函數與任何常見的 Gemlin 驅動程式和語言變體搭配使用的一般指引,以及以 Java、和 Python 撰寫的 Lambda 函數的特定範例。 JavaScript

注意

使用 Lambda 函數搭配 Neptune 的最佳方式已隨著最新的引擎版本而變更。Neptune 曾經在 Lambda 執行內容回收之後讓閒置連線保持長時間的開啟狀態,這可能會導致伺服器上的資源洩漏。為了緩解這種情況,我們曾經建議在每次 Lambda 調用時開啟和關閉連線。不過,從引擎 1.0.3.0 版開始,閒置連線逾時已降低,以便在非作用中的 Lambda 執行內容回收之後,連線不再洩漏,因此我們建議您在執行內容期間使用單一連線。這應該包括一些錯誤處理和 back-off-and-retry 樣板代碼,以處理意外關閉的連接。

管理函數中的小鬼 WebSocket 連接 AWS Lambda

如果您使用 Gremlin 語言變體來查詢 Neptune,則驅動程式會使用連線連線到資料庫。 WebSocket WebSockets 旨在支持長期使用的客戶端-服務器連接方案。 AWS Lambda另一方面,旨在支持相對短暫和無狀態的執行。使用 Lambda 查詢 Neptune 時,這種在設計理念上的不相符可能會導致一些非預期的問題。

AWS Lambda 函數在執行上下文中運行,該上下文將函數與其他函數隔離。執行內容是在第一次調用函數時建立的,並且可在後續調用相同函數時重複使用。

不過,任何一個執行上下文永不會用來處理函數的多個並行調用。如果多個用戶端同時調用您的函數,Lambda 會為每個函數執行個體啟動額外的執行內容。所有這些新的執行內容可能轉而在後續的函數調用中重複使用。

在某些時候,Lambda 會回收執行上下文,特別是如果它們已經處於非活動狀態一段時間。 AWS Lambda 透過 Lambda 擴充功能公開執行內容生命週期,包括InvokeShutdown階段。Init使用這些延伸模組,您可以撰寫程式碼,在回收執行內容時清除外部資源,例如資料庫連線。

常見的最佳實務是在 Lambda 處理常式函數之外開啟資料庫連線,以便可在每次呼叫處理常式時重複使用。如果資料庫連線在某個時候中斷,您可以從處理常式內部重新連線。不過,使用此方法存在連線洩漏的危險。如果閒置連線在執行內容銷毀後長時間保持開啟狀態,則間歇性或突發性 Lambda 調用案例可能會逐漸洩漏連線並耗盡資料庫資源。

Neptune 連線限制和連線逾時已隨著較新的引擎版本而變更。以前,每個執行個體最多支援 60,000 個 WebSocket連線。現在,每個 Neptune 執行個體的最大並行 WebSocket 連線數目會隨執行個體類型而有所不同。

此外,從引擎 1.0.3.0 版開始,Neptune 會將連線的閒置逾時從一小時縮減至大約 20 分鐘。如果用戶端未關閉連線,連線會在 20 到 25 分鐘的閒置逾時後自動關閉。 AWS Lambda 不會記錄執行內容的生命週期,但實驗顯示新的 Neptune 連線逾時與非作用中的 Lambda 執行內容逾時一致。回收非作用中執行內容時,其連線很有可能已被 Neptune 關閉,或者之後很快就會關閉。

AWS Lambda 與 Amazon Neptune 小鬼一起使用的建議

現在,我們建議在 Lambda 執行內容的整個生命週期中使用單一連線和圖形周遊來源,而不是每個函數調用各有一個 (每個函數調用僅處理一個用戶端請求)。由於並行用戶端請求是由在個別執行內容中執行的不同函數執行個體處理的,因此不需要維護連線集區來處理函數執行個體內的並行請求。如果您使用的 Gemlin 驅動程式具有連線集區,請將其設定為只使用一個連線。

若要處理連線失敗,請對每個查詢使用重試邏輯。即使目標是在執行內容的生命週期內維護單一連線,但非預期的網路事件可能會導致該連線突然終止。這種連線失敗會顯示為不同的錯誤,取決於您使用的驅動程式。您應該編碼 Lambda 函數以處理這些連線問題,並在必要時嘗試重新連線。

一些 Gimlin 驅動程式會自動處理重新連線。例如,Java 驅動程式會自動嘗試代表您的用戶端程式碼重新建立與 Neptune 的連線。使用此驅動程式,您的函數程式碼只需要退避並重試查詢。相比之下, JavaScript 和 Python 驅動程序不會實現任何自動重新連接邏輯,因此使用這些驅動程序,您的函數代碼必須在備份後嘗試重新連接,並且僅在重新建立連接後重新嘗試查詢。

這裡的程式碼範例確實包含重新連線邏輯,而不是假設用戶端正在處理它。

在 Lambda 中使用 Gremlin 寫入請求的建議

如果您的 Lambda 函數修改圖形資料,請考慮採用 back-off-and-retry策略來處理下列例外狀況:

  • ConcurrentModificationException – Neptune 交易語義意味著寫入請求有時會由於 ConcurrentModificationException 而失敗。在這些情況下,請嘗試指數 back-off-based 重試機制。

  • ReadOnlyViolationException – 由於叢集拓撲隨時可能因計劃或非計劃的事件而變更,因此寫入責任可能會從叢集中的某個執行個體轉移到另一個執行個體。如果您的函數程式碼嘗試將寫入請求傳送至不再是主要 (寫入器) 執行個體的執行個體,則請求會因 ReadOnlyViolationException 而失敗。發生這種情況時,請關閉現有連線、重新連線至叢集端點,然後重試請求。

此外,如果您使用 back-off-and-retry 策略來處理寫入請求問題,請考慮為創建和更新請求實施冪等查詢(例如,使用 fold () .coalesce (). 展開/)。

在 Lambda 中使用 Gremlin 讀取請求的建議

如果您的叢集中有一或多個僅供讀取複本,平衡這些複本之間的讀取要求是好主意。一種選項是使用讀取器端點。讀取器端點會平衡複本之間的連線,即使叢集拓撲在您新增或移除複本時發生變更,或提升複本以變成新的主要執行個體時也一樣。

不過,在某些情況下,使用讀取器端點可能會導致叢集資源的使用不均。讀取器端點的運作方式是定期變更DNS入口所指向的主機。如果用戶端在DNS項目變更之前開啟了許多連線,則所有連線要求都會傳送至單一 Neptune 執行個體。在高輸送量 Lambda 案例中可能會發生這種情況,其中對 Lambda 函數的大量並行請求會導致建立多個執行內容,而每個內容都有自己的連線。如果這些連線幾乎全都同時建立,則連線很可能都指向叢集中的相同複本,並一直指向該複本,直到回收執行內容為止。

在執行個體之間分發請求的一種方式是,將 Lambda 函數設定為連線至執行個體端點 (從複本執行個體端點清單中隨機選擇),而不是讀取器端點。這種方法的缺點是它需要 Lambda 程式碼來處理叢集拓撲中的變更,方法是監控叢集,並且每當叢集的成員資格變更時就更新端點清單。

如果您正要編寫一個 Java Lambda 函數,其需要平衡叢集中執行個體之間的讀取請求,則您可以使用適用於 Amazon Neptune 的 Gremlin 用戶端,這是 Java Gemlin 用戶端,它了解叢集拓撲,並可跨 Neptune 叢集中的一組執行個體 公平地分發連線和請求。這篇部落格文章包含一個範例 Java Lambda 函數,此函數會使用適用於 Amazon Neptune 的 Gremlin 用戶端。

可能會減慢 Neptune Gremlin Lambda 函數冷啟動速度的因素

第一次呼叫 AWS Lambda 函數時稱為冷啟動。有幾個因素可能會增加冷啟動的延遲:

  • 務必將足夠的記憶體指派您的 Lambda 函數。  — 對於 Lambda 函數來說,冷啟動期間的編譯速度可能會比啟動的速度要慢得多,EC2因為按照指派給函數的記憶體成比例線性地 AWS Lambda 配置CPU週期。有了 1,769 MB 的記憶體,函數會接收相當於一個完整的 v CPU (每秒一 v CPU 秒的學分)。對於使用 Java 編寫的大型 Lambda 函數,未指派足夠的記憶體來接收適當CPU週期的影響特別明顯。

  • 請注意,啟用IAM資料庫驗證可能會減慢冷啟動 — AWS Identity and Access Management (IAM) 資料庫驗證的速度也會降低冷啟動速度,尤其是在 Lambda 函數必須產生新的簽署金鑰時。此延遲僅影響冷啟動,而不會影響後續請求,因為一旦 IAM DB 驗證建立了連接認證,Neptune 只會定期驗證它們是否仍然有效。