作者:來自 Elastic?David Turner, Dianna Hohensee
Elasticsearch 使用官方的 AWS Java SDK 集成了某些 Amazon Web Services (AWS) 功能。這些集成最早在近 10 年前發布的 Elasticsearch 2.0 版本中引入。
最近,AWS 宣布 Elasticsearch 過去十年使用的 SDK 將于 2025 年 12 月 31 日停止支持。作為 Elastic,我們有責任只依賴受支持的組件,因此必須在此日期前遷移到新版 AWS Java SDK v2。
新版 SDK 不是舊版的直接替代品,且在多方面表現不同。本文講述了遷移到新版 SDK 的項目過程,我們采取的步驟以保護 Elasticsearch 用戶免受行為差異影響,以及你可能需要采取的適應新版 SDK 的操作。
所有 8.19 小版本系列的 Elasticsearch 版本,以及 9.1.0 及之后的版本,都將使用新的 AWS Java SDK v2。
什么是 SDK?
像 AWS 這樣的網絡服務提供商通過其暴露的應用程序編程接口(API)來描述其服務。API 文檔說明如何構造請求以實現特定結果,以及如何解釋對這些請求的響應(無論成功與否)。例如,AWS S3 的 API 文檔詳細說明了如何構造上傳對象的請求,然后再下載該對象。
大多數服務提供商還為常用編程語言提供 SDK,允許開發者在不需要了解 API 低層細節的情況下與服務交互。每個 SDK 實現了與服務交互所需的通用行為和約定,并將其適配到開發者所用的編程環境中。開發者無需構造請求和解釋響應,只需調用 SDK 中的函數,具體實現細節由網絡服務提供商的 API 專家處理。
AWS 提供了一個 Java SDK,封裝了 AWS 各服務如何協同工作及其運行環境的知識,并將所有功能映射到 Java 開發者熟悉的特性上。例如,它會自動將 API 錯誤轉換為 Java 異常,簡化編程體驗。此外,運行在 AWS EC2 實例上的進程,使用 AWS Java SDK 與 AWS S3 交互時,默認可以自動確定大部分配置,簡化最終用戶體驗。
自 2.0.0 版本以來,Elasticsearch 在兩個主要方面使用 AWS Java SDK:在 AWS S3 中存儲和檢索快照,以及使用 EC2 的 DescribeInstances API發現其他集群成員。
為什么 AWS 創建了第二個 Java SDK?
AWS 最初的 Java SDK 于 2010 年 3 月發布,Elasticsearch 第一個使用該 SDK 的版本是在 2015 年 10 月發布。隨著時間推移,發現原來 SDKv1 的一些設計決策經不起時間考驗,且無法修復而不破壞現有客戶端代碼的兼容性。2018 年 11 月,AWS 發布了全新的 Java SDK,稱為 SDKv2。新 SDK 更靈活,支持異步請求執行、可選的 HTTP 客戶端,以及跨 SDK 客戶端實例共享 HTTP 客戶端以提高連接重用效率。新 SDK 也更嚴格,例如要求開發者明確指定服務所在的 AWS 區域,而 SDKv1 在未指定時會盡量猜測區域。
當時,Elasticsearch 開發團隊評估了 SDKv2,認為新功能對 Elasticsearch 的需求并不關鍵,且部分與 SDKv1 的差異會導致用戶可見的破壞性變更,因此為了用戶利益決定繼續使用 SDKv1。
為什么 Elasticsearch 要遷移到 SDKv2?
這一切在 2024 年改變,亞馬遜宣布 SDKv1 支持將在 2025 年 12 月 31 日終止。雖然該 SDK 在此后仍可使用,但若發現關鍵漏洞或安全問題將不會再發布新版本。
安全和質量對 Elastic 非常重要,我們不能接受依賴的 SDK 出現未修補的安全漏洞或其他缺陷的風險,因此決定盡管遷移會帶來用戶可見的影響,仍必須遷移到 SDKv2。
不幸的是,SDKv1 的終止支持是在 Elasticsearch 8.x 系列發布過程中宣布的,該系列會維護至 2027 年中。我們面臨艱難選擇:要么在 8.x 小版本中切換到 SDKv2,可能帶來破壞性變更;要么在 8.x 繼續用 SDKv1,9.x 系列才用 SDKv2,這意味著在 SDKv1 維護結束后 8.x 會有 18 個月風險期,需依賴繞過新發現的安全問題。
我們找到了一條折中方案,允許在 8.x 小版本中遷移到 SDKv2,同時引入兼容性邏輯來處理行為差異。得益于兼容邏輯,大部分用戶升級到基于 SDKv2 的 Elasticsearch 版本時無需采取任何操作。
Elasticsearch 是如何遷移到 SDKv2 的?
看似遷移很簡單:移除對 SDKv1 的依賴,添加 SDKv2 依賴,修復編譯錯誤,確認測試通過,即完成。
但事情從來不那么簡單。Elasticsearch 有大量詳盡測試代碼與 AWS 服務交互。部分測試緊密依賴 SDKv1 的特性,而 SDKv2 并無對應部分。例如,我們通過檢查 com.amazonaws.ClientConfiguration 對象確認客戶端配置,但 SDKv2 沒有對應對象。還有驗證 SDK 指標采集的測試,而 SDKv2 的指標收集機制大不相同。
我們可以一邊改生產代碼一邊修測試,但這樣風險是可能同時引入生產和測試代碼缺陷,導致測試掩蓋生產問題。為降低風險,我們先重構測試,使其盡量獨立于 SDK 版本。
我們已有部分測試通過模擬 AWS API 的 HTTP 服務器運行,驗證 Elasticsearch 在 AWS API 失敗、超時或限流時的行為。這些端到端測試獨立于 SDK 版本,因為兩個 SDK 發送相同網絡請求。
我們重點將更多測試轉為此類端到端測試,減少對 SDK 內部實現的依賴。即便如此,我們還是發現 SDKv1 與 SDKv2 行為間存在不一致,測試工具需做相應調整。
接著我們開啟長期功能分支,團隊可并行工作,避免影響生產代碼。
當所有代碼編譯并通過測試后,我們回顧了改動,提取了幾部分與 SDK 無關的改動先合入主代碼庫,減小升級改動范圍,專注升級到 SDKv2。
開發過程中,我們持續追蹤 SDKv1 與 SDKv2 間不兼容之處。端到端測試特別有效地發現這些問題,減少了測試改動也讓我們有信心沒有遺漏。合入后內部發布,一下游系統發現 SDKv2 更嚴格的另一個場景,測試未覆蓋,我們快速修復和緩解了該問題。
發生了什么變化?
我們預計大多數集群升級到基于 SDKv2 的版本后,因 Elasticsearch 添加了兼容機制,不需要修改配置就能繼續正常工作。
雖然你可能不需要立即調整配置,我們也修改了一些關于如何配置 Elasticsearch 集群的最佳實踐建議,特別是關于 s3.client.${CLIENT_NAME}.region、s3.client.${CLIENT_NAME}.endpoint 和 s3.client.${CLIENT_NAME}.protocol 設置。未來版本可能會強制要求這些配置。以下部分介紹升級到基于 SDKv2 的 Elasticsearch 后你可能需要注意的區別。
區域自動檢測
AWS 分為 30 多個獨立區域。客戶端通常向特定區域的 HTTPS 端點發送 API 請求,請求中包含依賴區域名的認證簽名。
SDKv1 通過環境和配置的端點地址,使用啟發式方法自動選擇合適的區域名。SDKv2 去除了大部分啟發式,要求調用代碼明確指定區域。
作為遷移的一部分,Elasticsearch 引入了類似 SDKv1 的啟發式方法,所以升級集群時一般不必調整配置來指定區域。特別是使用 AWS S3 存儲快照時,Elasticsearch 會繼續從指定的 S3 端點啟發式判斷區域(至少對于本文撰寫時已知的所有區域)。
不過我們建議你為每個 S3 客戶端配置 s3.client.${CLIENT_NAME}.region,而不是依賴啟發式。新啟發式可能與 SDKv1 不完全相同,遇到差異時需要明確配置正確的區域。
如果你使用 s3 倉庫類型將快照存儲在自己的 S3 兼容存儲中,存儲管理員會告訴你正確的區域名,許多此類存儲會使用 us-east-1 作為區域名。
IMDSv1 支持
AWS EC2 實例可通過實例元數據服務(Instance Metadata Service?- IMDS)訪問自身元數據,包括實例所在區域和可用區信息,以及綁定的 IAM 角色憑證。
IMDS 有兩個協議版本:IMDSv1 和更安全的 IMDSv2。SDKv2 不支持 IMDSv1,因此新版 Elasticsearch 只使用 IMDSv2。所有 EC2 實例均支持 IMDSv2,所以在 AWS 基礎設施上運行不會有問題。但如果你在其他環境運行 Elasticsearch 并使用兼容 EC2 IMDS 的獨立 IMDS,必須確保其支持 IMDSv2。
協議選擇
SDKv1 允許你設置類似 ”hostname.domain.com” 或 ”hostname.domain.com:port” 的端點地址,然后單獨選擇使用不安全的 HTTP 還是安全的 HTTPS 協議,Elasticsearch 舊版本通過 discovery.ec2.protocol 和 s3.client.${CLIENT_NAME}.protocol 設置暴露了該選項。
SDKv2 要求端點地址為完整的絕對 URL,必須以 http:// 或 https:// 開頭。作為臨時兼容措施,Elasticsearch 仍根據 s3.client.${CLIENT_NAME}.protocol 設置(默認 HTTPS)為裸 S3 端點加前綴。但該行為已棄用,下一個主版本將強制 S3 端點必須是以 http:// 或 https:// 開頭的絕對 URL。
系統屬性移除
SDKv1 可能讀取 aws.secretKey 和 com.amazonaws.sdk.ec2MetadataServiceEndpointOverride 這兩個系統屬性,SDKv2 不支持。Elasticsearch 安裝中很少會設置這些屬性,提及它們僅為完整性。
功能移除
SDKv2 不允許控制重試時的限流策略,s3.client.${CLIENT_NAME}.use_throttle_retries 設置被棄用且無效。生產集群中極少使用該設置。SDKv2 默認應用 AWS 推薦的限流策略。
SDKv2 要求使用 V4 簽名算法,不支持更舊算法,s3.client.${CLIENT_NAME}.signer_override 設置被棄用且無效,生產集群中也極少使用。
SDKv2 不支持用于 S3 對象的 log-delivery-write 預設 ACL。該 ACL 僅適用于桶,不適用于對象,即使舊版 Elasticsearch 用 SDKv1 也無法生效,極少有人使用該 ACL。
指標報告
Elasticsearch 使用 SDK 內建功能收集對 S3 端點的 API 調用指標,這些指標主要用于內部,有時在部分 API 中可見。SDKv1 將部分 4xx 狀態碼響應視為未收到響應,SDKv2 則與其他錯誤響應同等計數,可能導致指標上出現細微差異。
STS 端點選擇
SDKv1 可使用區域端點或全局 https://sts.amazonaws.com 端點獲取短期會話憑證,SDKv2 僅使用區域端點。
其他差異
AWS SDK 文檔列出了許多 SDKv1 和 SDKv2 的其他差異。本文未提及的差異均已由 Elasticsearch 處理,對最終用戶不相關。但鑒于兩 SDK 差異眾多及 Elasticsearch 運行環境多樣,升級時可能需要調整部分配置。
立即升級
Elasticsearch 8.19.x 及 9.1.0 及以后版本使用新版 AWS Java SDK v2。請在 2025 年底前升級到這些版本,避免繼續使用已停止支持的舊版 SDKv1。
請注意新版 SDK 存在一些行為差異,某些特殊情況下可能需要小幅調整配置。升級前務必先升級測試集群并驗證正常,再升級生產集群。
本文中描述的任何功能或特性發布及時間安排均由 Elastic 全權決定。當前不可用的功能可能不會按時或根本不會發布。
原文:Upgrading Elasticsearch to a new AWS Java SDK | Elastic Blog