貝殼 Go 實現的多雲對接存儲網關建設

1、功能介紹

貝殼存儲服務通過 S3 協議向業務方提供文件、圖片、音視頻的存儲及下載。S3 協議由 AWS 推出,在對象存儲行業已經成爲事實標準。騰訊雲對象存儲 COS、阿里雲對象存儲 OSS 均兼容 S3 協議。

S3 協議可以簡單理解爲一套 webapi 接口。通過調用接口,業務方可以進行對象數據的存取。每一個對象數據稱爲一個 object, 以一個唯一的 ID 來標識,object 可以組織到一個 bucket 中,便於區分不同的業務場景。總結來說, S3 就是一個用 bucket 組織數據,可以存儲近似無限數量 object 的 key-value(其中 key 爲 object 的標識,value 爲存儲的數據內容)存儲系統。

從業務角度來說,數據需要做一些處理之後纔會使用。以圖片爲例,業務方存儲一張原圖之後,實際使用時可能並不需要原圖,而是根據場景進行縮放或者打水印或者格式轉換之後下載使用,而且 C 端場景需要提高下載速度,就近下載。因此貝殼存儲服務也提供了多媒體預處理以及通過 CDN 就近下載的功能。

貝殼存儲服務穩定性可以達到 4 個 9,存儲近百億數據,總數據量十 PB 級。

2、背景

存儲網關作爲一個底層服務,牽一髮而動全身,其穩定性至關重要,初始存儲網關架構如下圖所示:

圖片

業務方通過 S3 協議上傳數據到存儲網關,存儲網關進行驗籤、鑑權、文件大小及黑白名單檢測之後轉發到後端使用的雲平臺對象存儲服務。作爲一個存儲網關,有如下兩種關於大小的設置:

  1. 單對象最大大小,如果超出該限制,則拒絕傳輸。類似 nginx client_max_body_size 配置項

  2. 單對象允許使用的最大內存大小,超出該限制則將數據放置到一個臨時磁盤文件後再進行轉發。類似 nginx client_body_buffer_size 配置項

這些配置可以避免某個業務方上傳文件過大影響存儲網關穩定性。

任何一種架構都有其優劣勢,貝殼存儲網關作爲一個存儲統一入口,便於管理和控制,並且可屏蔽後端實際使用的雲平臺。因此如果有云平臺遷移需求,可以做到業務方無感知,例如貝殼後端存儲曾經從 AWS 遷移到騰訊雲。

但其劣勢也十分明顯,任何集中式的服務都需要做好穩定性建設,防止爆炸半徑過大,大面積影響服務。其次由於是統一入口,不在入口部署地域的公網上傳會受限於公網網絡質量,導致延時或者錯誤率增加。

存儲網關穩定性建設涉及如下三個方面:

  1. 入口處:如果一個業務方持續上傳大量的文件,佔用存儲網關資源或者業務方出 bug,則直接影響其他業務方的使用;

  2. 驗籤鑑權:存儲網關使用 OpenIAM 進行驗籤和鑑權,如果 OpenIAM 出現故障,則影響業務方使用;

  3. 後端雲平臺:如果後端雲平臺的對象存儲服務出現故障,會直接影響業務方使用

也就是上圖中標黃的三個部分。很不幸,2021 年貝殼存儲網關在如上三個方面都出現過故障。因此本文會重點介紹存儲網關在穩定性方面的建設。

3、入口建設

入口處需要配置各個業務方的資源配額,防止業務方之間互相影響。除此之外,需要根據存儲網關通過壓測得出的最大容量做整體限制和報警,防止突增流量壓垮整個系統。貝殼存儲網關除了常規的 QPS 限制之外還增加了帶寬限制。

3.1 限流

流量限制通過使用開源組件 Sentinel 實現,增加限流之後流程圖如下:

圖片

一個請求首先是否觸發 bucket 維度的限流,如果沒有,則判斷是否超過全侷限流,兩個限流都沒有觸發的話可以放行。Go 語言十幾行代碼就可以實現一個限流方案,具體實現方法在此不再敘述,大家可參考 Sentinel 的實現或者網絡上其他的一些案例。

3.2 限帶寬

存儲網關只有常規的限流並不能滿足需求,大家可以想想 nginx,作爲一個 http 網關,nginx 除了實現 limit_req 用來限制流量,還提供了 limit_rate 進行帶寬限制。設想一個業務方流量限制爲 100qps,但每個請求都傳輸大小爲 10G 的文件,則會將存儲網關的帶寬打滿。

Go 語言中,數據讀取和寫入通過 Reader 和 Writer 接口實現,其定義如下:

type Reader interface {
        Read([]byte) (n int, err error)
}
type Writer interface {
        Write([]byte) (n int, err error)
}

因此能夠通過做一層封裝,實現 Reader 和 Writer 接口,每次讀取或者寫入時先判斷是否超過了帶寬配額,如果沒有觸發限制,纔會進行真正的上傳和下載。其原理圖如下:

圖片

Reader 接口實現如下:

type UploadBandWidtLimitReadCloser struct {
        Bucket     string
        Payload    io.ReadCloser
        qpsLimiter *limit.Limiter
}


func (this *UploadBandWidtLimitReadCloser) Read([]byte) (n int, err error) {


    // bucket維度配額檢查...
    // 全局配額檢查...
    // 如果檢查不通過,則使用sentinel的勻速排隊方式等待,最多等待2min...
   //實際讀取
    return this.Payload.Read(p)
}

帶寬限制也按 bucket 和全局維度進行了配額配置,除此之外,還區分了上傳和下載的維度,畢竟數據首先需要保證上傳成功才能夠下載使用。

流量和帶寬的所有限制都保存在了配置中心 Apollo 中,可以動態調整。其中全局維度按存儲網關的容量進行常態化開啓,bucket 維度按業務方平時使用量的 3 倍常態化開啓。

4、依賴降級

貝殼參考 aws 的 IAM 建設了自己的驗籤鑑權系統,存儲網關使用該套系統進行業務方的驗籤和鑑權。但 IAM 系統也會出現故障,因此存儲網關需要設計降級方案。簡單來說,可以直接通過設置降級開關,放行全部請求,如下配置:

openiamDegradeSwitch = false
openiamDegradeConfig = {"__default__""allow_all"}

但這樣有一定的風險,本來驗籤和鑑權就是爲了安全,不能因爲穩定性完全放棄安全性,尤其是存儲網關可以通過公網訪問,完全放行可能導致惡意上傳,損耗成本並且增加合規危險。因此我們增加了如下的一些切換策略:

  1. 可以按公網和內網分別配置降級策略,例如內網完全放行,公網只有最近 12 小時有成功訪問記錄的 AK 纔會放行;

  2. 按 bucket 維度進行降級,例如只放行某些指定的 bucket

5、多雲切換

多雲時代,如果能夠對接多個雲平臺,不僅有利於可用性,防止單點故障,還可以通過多個供應商的引入,通過競爭降低成本。隨着公司的發展或者合規性的要求,有些數據需要保存在公司自己的 IDC,此時多雲對接利於引入自建對象存儲服務,並且數據遷移可以做到業務方無感知。

受利於 S3 協議成爲事實上的標準,我們可以直接對接阿里雲、騰訊雲或者開源方案 chubaofs,甚至通過協議轉換可以對接其他一些分佈式對象存儲服務。多個雲平臺只需要實現下列接口就可以通過配置後切換:

type StoreRepository interface {

        Initiate(ctx context.Context, config *StoreConfig) (_ context.Context, err error)

        // Bucket相關方法...

        // Object相關方法...

        CopyObject(ctx context.Context, input *s3.CopyObjectInput) (output *s3.CopyObjectOutput, err error)

        DeleteObject(ctx context.Context, input *s3.DeleteObjectInput) (output *s3.DeleteObjectOutput, err error)

        GetObject(ctx context.Context, input *s3.GetObjectInput) (output *s3.GetObjectOutput, err error)

        HeadObject(ctx context.Context, input *s3.HeadObjectInput) (output *s3.HeadObjectOutput, err error)

        ListObjects(ctx context.Context, input *s3.ListObjectsInput) (output *s3.ListObjectsOutput, err error)

        ListObjectsV2(ctx context.Context, input *s3.ListObjectsV2Input) (output *s3.ListObjectsV2Output, err error)

        PutObject(ctx context.Context, input *s3.PutObjectInput) (output *s3.PutObjectOutput, err error)

       // 分片上傳相關方法…

}

貝殼存儲網關通過在 Apollo 配置中心設置開關,可以按 bucket 維度選擇後端使用的對象存儲服務。通過數據同步,還可以將關鍵 bucket 保存在多個對象存儲,從而進行災備切換。示意圖如下:

圖片

雲平臺 A 故障時,可以進行讀寫切換。

6、監控報警

增加限流、限帶寬以及依賴降級、多雲切換之後,配置中心多了十幾個開關。但開關還需要人來執行,因此需要相應的增加監控報警提前發現故障,並做好對應的預案。報警指標包括如下方面:

通過報警可以提前發現問題,發現之後有相應的處理手段,提高存儲網關的可用性

7、新架構整體概覽

存儲網關整體架構圖如下所示:

圖片

各部分介紹如下:

  1. 業務方通過 S3 協議上傳下載文件、圖片或者音視頻;

  2. 存儲服務入口處爲限頻模塊,通過配置中心獲取對應業務方的流量配額和帶寬配額,配額之內的放行;

  3. 存儲服務對業務方進行驗籤和鑑權,該模塊可降級,降級策略通過配置中心控制;

  4. 協議轉換模塊首先通過配置中心獲取該業務方對應的後端雲平臺存儲,然後將 S3 協議和後端雲平臺協議進行轉換和上傳下載;

  5. 對象文件存儲之後會通過消息中間件發送信息,觸發多平臺的同步以及多媒體處理

8、未來規劃

存儲網關後續會圍繞着如下幾個方面做建設:

  1. 平臺化建設:對業務方友好,通過 web 平臺可以進行 bucket 申請、bucket 授權、資源轉移、歷史趨勢觀察、成本展現、流量和帶寬配額展現、後端存儲服務展現。也可以進行上傳下載、文件分享。

  2. 邊緣接入:上文介紹架構劣勢時提過統一入口導致的上傳侷限性,跨地域上傳一是會大量佔用公網帶寬,二是會有延遲和失敗率高的問題。通過引入邊緣代理節點可以加速上傳。

  3.  降本增效:一是管理對象的生命週期,不常使用的可以存儲到低成本服務器,二是探索多媒體處理的 FAAS 化,多媒體處理比較耗資源,並且高低峯明顯,通過引入 FAAS,不只可以滿足高峯期的快速擴容,而且可以在低峯期極端縮容到 0 資源佔用。貝殼正在進行服務的容器化建設,引入了 K8S,基於此,探索多媒體處理的降本。

  4. 多媒體功能建設:圖片的裁剪、縮放、水印、格式轉換,音視頻轉碼、變聲、裁剪合併、縮略圖,文件預覽等等

9、總結

本文主要介紹了貝殼存儲網關的使用場景、架構設計以及穩定性建設,其中穩定性建設是基礎。除了穩定性,後續還會在易用性、功能擴充以及降本增效方面持續建設。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/m2d4GRIB9uR2T3zidiTdHw