Elasticsearch 的快照與恢復功能是 Elasticsearch 集群的重要組成部分。它的存在為數據可靠性提供了強有力的保障。在這篇文章中,讓我們一起看看 Elasticsearch 中官方幾個快照插件的相關信息。
在文章正式開始前,讓我們先大致地了解一下快照倉庫。Elasticsearch 的快照倉庫分為本地倉庫(local repository)和遠程倉庫(remote repository)兩種。本地倉庫主要作為測試使用(單元測試或者試用 Elasticsearch 時使用),在生產線上使用意義不大。生產線上主要使用遠程倉庫,因為它可以將集群數據放在集群以外的地方,以作為數據備份。官方遠程倉庫插件主要有:AWS、GCS、Azure、HDFS 四個插件。其中,AWS、GCS、Azure 是筆者這兩年經常使用的三個插件,也是這篇文章的討論主題。
閱讀本文後,你會明白:
事不宜遲,讓我們馬上開始吧!
插件的安裝與查詢插件可以通過命令行 elasticsearch-plugin 來安裝(官方文檔[1]):
sudo bin/elasticsearch-plugin install $plugin_namesudo bin/elasticsearch-plugin install repository-s3
sudo bin/elasticsearch-plugin install repository-gcs
sudo bin/elasticsearch-plugin install repository-azure
sudo bin/elasticsearch-plugin install repository-hdfs為了讓插件能夠正常使用,集群的每一個節點都要安裝插件。上述四個插件都是 Elasticsearch 的官方插件,無需額外下載,直接安裝即可。插件安裝成功以後,節點需要重啟才能使插件生效。
查詢插件的話,有至少兩種辦法。一是登錄節點後,通過命令行查詢。二是直接通過 API 查詢。
登錄節點並通過命令後 elasticsearch-plugin 查詢:
sudo bin/elasticsearch-plugin list無需登錄,直接通過 Node API[2] 查詢:
GET /_nodes/plugins
快照基本操作Elasticsearch 的快照操作包括快照倉庫管理 API(Snapshot repository management API)和快照管理 API(Snapshot management API)兩部分。絕大部分的 API 對於不同插件都是通用的。唯一的例外是創建快照倉庫的 API,創建時需要提供倉庫的類型。不同倉庫的參數也略有不同。這裡舉幾個簡單的例子,具體參數可以參考官方文檔。
創建 AWS S3 倉庫:
PUT _snapshot/my_s3_repository
{
"type": "s3",
"settings": {
"bucket": "my-bucket"
}
}創建 Google Cloud Storage 倉庫:
PUT _snapshot/my_gcs_repository
{
"type": "gcs",
"settings": {
"bucket": "my_bucket",
"client": "my_alternate_client"
}
}創建 Azure 倉庫:
PUT _snapshot/my_backup
{
"type": "azure",
"settings": {
"client": "secondary"
}
}
雲提供商依賴關係使用雲提供商相關的插件意味著你必須面對依賴關係的問題。這裡的依賴關係主要體現在兩部分:雲提供商的 SDK 和雲提供商的儲存系統兩方面。
在雲提供商的 SDK 方面,由於 Elasticsearch 需要通過雲提供商提供的客戶端去操作數據(上傳、列舉、刪除等),這裡必然存在兼容性的問題。當雲提供商的 SDK 版本不斷更新的時候,如果你的 Elasticsearch 集群版本保持不變,那麼很可能到某個時間點以後 SDK 版本就會過於陳舊無法再使用。使得集群受到無法備份數據的危險。所以及時升級 Elasticsearch 集群版本很重要。
在存儲方法,使用特定雲服務的儲存系統意味著你需要對相應的儲存進行配置和管理,比如創建和設置服務帳號(service account)等。
走進代碼上面我們主要看了一下比較概括性的信息。在接下來的段落裡,我想帶大家走進代碼,一起來閱讀一下幾個有代表性的類。
Blob Store Repository抽象類 BlobStoreRepository 是一個快照倉庫的基本實現,它被針對雲提供商的 BlobStore 實現所繼承。這個類只有兩個抽象方法:createBlobStore() 和 basePath()。方法 createBlobStore() 可以用於創建 blob store,而且推薦實現時,採用惰性初始化(lazy initialize)。Blob store 是關於雲提供商增刪改查在 Elasticsearch 的實現,我們在下文會進一步分析。另一個方法是 basePath,以獲得 Elasticsearch snapshot repository 在雲提供商儲存桶中的相對儲存路徑。如果是一個儲存桶對應一個 repo,那麼 base path 應該是 /。如果一個儲存桶對應多個 repos 或者一個儲存桶有多個用途(不僅用於 Elasticsearch),那麼就需要填充一個 Elasticsearch snapshot repo 所在的相對路徑。
public abstract class BlobStoreRepository extends AbstractLifecycleComponent implements Repository {
...
/**
* Creates new BlobStore to read and write data.
*/
protected abstract BlobStore createBlobStore() throws Exception;
/**
* Returns base path of the repository
*/
public abstract BlobPath basePath();
}BlobStoreRepository 是 Elasticsearch 中關於 snapshot 的事務接入點,它實現了 snapshot、restore、get info、delete、cleanup、verify、提取統計數據、更新 cluster state 等功能。
不同的雲提供商的 repository 就是繼承這個抽象類,並且加入雲提供商的 SDK 以實現對於 blob 的讀寫。從下面的命令行中我們可以看見,無論是只讀的 URL Repository,測試用的 Mock Repository,本地倉庫的 File System Repository,還是遠程倉庫 Azure、S3、GCS、HDFS,它們實現都繼承了這個類。
➜ elasticsearch git:(7.9 u=) rg "extends BlobStoreRepository"
modules/repository-url/src/main/java/org/elasticsearch/repositories/url/URLRepository.java
56:public class URLRepository extends BlobStoreRepository {
server/src/test/java/org/elasticsearch/snapshots/mockstore/MockEventuallyConsistentRepository.java
68:public class MockEventuallyConsistentRepository extends BlobStoreRepository {
server/src/main/java/org/elasticsearch/repositories/fs/FsRepository.java
53:public class FsRepository extends BlobStoreRepository {
plugins/repository-azure/src/main/java/org/elasticsearch/repositories/azure/AzureRepository.java
55:public class AzureRepository extends BlobStoreRepository {
plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3Repository.java
72:class S3Repository extends BlobStoreRepository {
plugins/repository-gcs/src/main/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageRepository.java
43:class GoogleCloudStorageRepository extends BlobStoreRepository {
plugins/repository-hdfs/src/main/java/org/elasticsearch/repositories/hdfs/HdfsRepository.java
54:public final class HdfsRepository extends BlobStoreRepository {
Blob StoreBlob store 主要是提供 blobs 相關的兩個功能:得到給定路徑的 blob container,以及獲取對於這個 store 實現的操作的個數統計。一個 snapshot repository 對應一個 blob store。某些雲提供商的插件關於 blob 增刪改查的邏輯也寫在 blob store 的實現裡面,比如 Azure 和 GCS 這兩個 blob stores 的實現。
/**
* An interface for storing blobs.
*/
public interface BlobStore extends Closeable {
/**
* Get a blob container instance for storing blobs at the given {@link BlobPath}.
*/
BlobContainer blobContainer(BlobPath path);
/**
* Returns statistics on the count of operations that have been performed on this blob store
*/
default Map<String, Long> stats() {
return Collections.emptyMap();
}
}
Blob ContainerBlob container 指的是在某路徑下的包含所有 blobs 的容器。它不具有 snapshots 相關的邏輯,更偏向底層或者說雲提供商那邊。它主要負責對於此路徑下 blobs 的增刪改查的邏輯處理。路徑由 BlobPath 表示。以下是它的一些方法:
BlobContainer如上文所說,某些雲提供商的插件關於 blob 增刪改查的邏輯不在此類直接處理,而是委託給 blob store 去處理,比如 Azure 和 GCS 這兩個 blob stores 的實現。但是 S3 的邏輯就直接寫在類 S3BlobContainer 。所以我感覺它與 Blob container 的界限不是特別清晰。但可以確定的是:一個 repo 裡面只有一個 blob store,但一個 repo 可以有好多個 blob containers。
創建快照下面我們看看,從 BlobStoreRepository 出發,快照是如何創建出來的。這個圖是在 IntelliJ IDEA 中,由第三方插件 Sequence Diagram 生成的。為了簡化描述,有些步驟被省略。微信中如果圖太小不好看,可以點擊【閱讀原文】轉到我的博客或者通過電腦版閱讀。
Sequence diagram在這個圖中我們可以看到,BlobStoreRepository 的方法 snapshotFile 先找到了需要被快照文件的文件名(1.1),然後校驗文件的正確性(1.2),然後對於文件的每一個部分(1.3)實現上傳。上傳時,Elasticsearch 使用了一個自定義的 input stream wrapper 來實現潛在的限流需求(rate limiting)。後面的部分 Sequence Diagram 插件好像凌亂了,它寫錯了序號。不過瑕不掩瑜,下一步就是寫入 blob 了,也就是圖中的藍色部分(1.4.1.1.4)。寫入 blob 轉交給 BlobContainer 實現。BlobContainer 是一個接口,對應不同的雲提供商有不同的實現。實現完成以後,BlobStoreRepository 檢查寫入數據的正確性。最後,將已經成功實現的快照加入到狀態 IndexShardSnapshotStatus 中,用於追蹤快照創建進度。
由於時間有限,這篇文章的文章的源碼分析大概就討論到這裡吧!
擴展如何從這篇文章中拓展出去?
如果想對插件有更多的了解,請查閱官方文檔 Elasticsearch Plugins and Integrations[3]如果想對 blob store 有更多的了解,可以在 GitHub[4] 閱讀這個 package 的文檔和原始碼結論在本文中,我們看到了如何通過 elasticsearch-plugin 來安裝針對不同雲提供商的插件;不同插件下,對於快照操作的影響;使用快照插件以後,Elasticsearch 集群與雲提供商的依賴關係;接下來,我們走進原始碼,簡易分析了三個類:Blob Store Repository / Blob Store / Blob Container 的邏輯,並使用創建快照為例子,明白了 Blob Store Repository 是如何和 Blob Container 溝通的。最後,我還和大家分享了一些讓從這篇文拓展出去的資源。希望這篇文章能夠給你帶來一些思考,讓你對 Elasticsearch 的快照功能有進一步的了解。如果你有興趣了解更多的資訊,歡迎關注我的 GitHub 帳號 mincong-h[5] 或者微信訂閱號【碼農小黃】。謝謝大家!
參考資料[1]安裝插件: https://www.elastic.co/guide/en/elasticsearch/plugins/7.x/installation.html
[2]Node API: https://www.elastic.co/guide/en/elasticsearch/reference/7.x/cluster-nodes-info.html
[3]Elasticsearch Plugins and Integrations: https://www.elastic.co/guide/en/elasticsearch/plugins/7.x/index.html
[4]org.elasticsearch.repositories.blobstore: https://github.com/elastic/elasticsearch/blob/7.x/server/src/main/java/org/elasticsearch/repositories/blobstore/package-info.java
[5]GitHub: https://github.com/mincong-h