背景
傳統Web應用中所有的功能部署在一起,圖片、檔案也在一臺伺服器;應用微服務架構後,服務之間的圖片共享通過FTP+Nginx靜態資源的方式進行訪問,檔案共享通過nfs磁碟掛載的方式進行訪問,無論是單體架構還是微服務架構下的應用都存在大量圖片、檔案讀寫操作,但是昂貴的磁碟空間、高效能伺服器無疑增加了運營成本。
所以我們希望檔案服務也能微服務、獨立化,這樣既能降低運營成本,又能對檔案進行統一的管理和維護,所以搭建獨立的檔案服務是解決檔案共享、釋放業務系統壓力的最優選擇。於是便誕生了隨行付分散式檔案系統簡稱OSS(Object Storage Service),提供的海量、安全、低成本、高可靠的雲端儲存服務。它具有與平臺無關的RESTful API介面,能夠提供資料可靠性和服務可用性。
檔案服務的意義
隨著網際網路圖片、視訊時代的到來,對檔案的處理成為各個業務系統面臨的巨大挑戰,沒有檔案伺服器之前,系統之間處理圖片的方式大相徑庭:FTP、NFS、資料庫儲存等等,雖然都實現了對檔案的儲存、訪問,但是系統之間很難達到檔案共享,所以檔案服務可以形成一個統一的訪問標準,降低各個系統之間的互相依賴,提高開發效率、釋放業務系統壓力,所以檔案服務的意義如下:
-
降低WEB伺服器壓力
分擔業務伺服器的I0、流程負載,將耗費資源的檔案訪問、讀寫操作分離到檔案伺服器,可以提高伺服器的效能和穩定性,降低WEB伺服器成本。
-
獨立服務易擴充套件
檔案服務像微服務架構獨立化,可以有針對性的進行配置提高效能;獨立域名讓圖片管理、CDN快取檔案更方便,隨時擴充套件檔案伺服器數量,即不影響業務又能增加檔案伺服器併發訪問。
-
統一訪問格式
開發者無需關心儲存路徑、儲存介質、檔案備份等,豐富的API幫助系統快速儲存、共享檔案,提高專案開發速度。
-
安全認證
檔案服務對資源訪問可以增加認證、許可權等安全措施,防止伺服器資源被盜用,有效的隔離了資料訪問。
檔案服務基本概念
為便於更好的理解物件儲存OSS,需要了解物件儲存中的幾個概念。
-
物件/檔案(Object) 物件是OSS儲存資料的基本單元,也被稱為OSS的檔案。物件由元資訊(Object Meta),使用者資料(Data)和檔名(Key)組成。物件由儲存空間內部唯一的Key來標識。物件元資訊是一個鍵值對,表示了物件的一些屬性,比如最後修改時間、大小等資訊,同時使用者也可以在元資訊中儲存一些自定義的資訊。物件的生命週期是從上傳成功到被刪除為止。在整個生命週期內,物件資訊不可變更。重複上傳同名的物件會覆蓋之前的物件,因此,OSS 不支援修改檔案的部分內容等操作。
-
儲存空間(Bucket) 儲存空間是用於儲存物件(Object)的容器,所有的物件都必須隸屬於某個儲存空間。可以設定和修改儲存空間屬性用來控制地域、訪問許可權、生命週期等,這些屬性設定直接作用於該儲存空間內所有物件,因此可以通過靈活建立不同的儲存空間來完成不同的管理功能。
- 同一個儲存空間的內部是扁平的,沒有檔案系統的目錄等概念,所有的物件都直接隸屬於其對應的儲存空間。
- 每個使用者可以擁有多個儲存空間。
- 儲存空間的名稱在 OSS 範圍內必須是全域性唯一的,一旦建立之後無法修改名稱。
- 儲存空間內部的物件數目沒有限制。
-
訪問金鑰(AppKey & AppSecret) AppKey代表應用身份,AppSecret即應用金鑰,用於生成簽名認證,請求檔案服務時必須要傳遞appkey和簽名生產的token,閘道器根據請求驗證請求的合法性性和時效性。
檔案服務的功能
應用場景 | 功能描述 |
---|---|
上傳檔案 | 建立儲存空間後,您可以上傳任意檔案到該儲存空間 |
搜尋檔案 | 可以在儲存空間中搜尋檔案或資料夾 |
檢視或下載檔案 | 通過檔案 URL 檢視或者下載檔案 |
刪除檔案或資料夾 | 刪除單個或者多個檔案/資料夾,還可以刪除分片上傳產生的碎片,節省儲存空間 |
訪問許可權 | 可以通過應用授權和桶授權的方式,授予儲存空間和物件訪問許可權的訪問策略 |
訪問資訊 | 自動記錄對OSS資源的詳細訪問資訊 |
防盜鏈 | 防止OSS上的資料被其他人盜用,設定防盜鏈 |
監控服務 | 預警OSS服務使用情況的實時資訊,如基本的系統執行狀態和效能 |
API和SDK | OSS 提供 RESTful API和各種語言的SDK開發包方便您快速進行二次開發 |
架構設計
OSS以分散式檔案系統ceph作為底層儲存,支援SDK或者瀏覽器以http的形式上傳和下載檔案,閘道器負責路由訪問請求到檔案服務叢集ossWork,ossWork生成檔案唯一儲存路徑後儲存檔案到ceph,並返回加密後訪問地址給使用者。 架構圖如下:
原理介紹:- 1.OSS採用OpenResty作為閘道器處理請求轉發和校驗,OpenResty匯聚了nginx的核心功能模組,還支援lua指令碼方便對nginx功能的擴充套件,而且nginx多路複用機制和非阻塞的IO非常適合耗時短、業務簡單的校驗操作:許可權驗證、防盜鏈、黑白名單等,不僅如此nginx還能作為閘道器的快取,這些特性極大提升了閘道器效能和併發訪問。
- 2.ossWork作為檔案服務,處理圖片水印、縮放、url加密、解密等,還封裝與底層儲存的互動。
- 3.ossKeeper作為檔案管理後臺,負責許可權接入註冊、申請、監控報表展示。
- 4.ossMonitor日誌收集、計算彙總、資料儲存。
- 5.ossBackup負責檔案非同步備份。
oss子系統相關流程圖如下:
核心實現
OSS主要為隨行付各個業務系統提供檔案共享和訪問服務,並且可以按應用統計流量、命中率、空間等指標。下面將介紹OSS核心功能以及實現。主要包括:快取、使用者認證、許可權管理、url加密解密、監控統計等。
快取
提升效能的關鍵是快取,OSS採用二級快取:瀏覽器快取、閘道器層快取提升響應速度,具體如下:
- 第一次請求檔案時,OSS返回檔案給瀏覽器http的狀態碼是200
- 第二次請求時同一個檔案時,伺服器根據請求中HTTP協議中的max-age/Expires,判斷檔案未修改,返回狀態碼403,告訴瀏覽器可以繼續使用本地快取
- 第三次請求F5強制重新整理,閘道器根據If-Modified-Since、Cache-Control:no-cache和Pragma:no-cache等資訊重新返回nginx中快取檔案
- 第四次請求url時,request_uri不一樣但檔案是同一個,nginx根據request_uri判斷閘道器中無此檔案,請求底層儲存返回檔案。
使用者認證
為避免檔案、圖片盜用,浪費伺服器流量和IO等資源,OSS採用防盜鏈的方式認證請求。每個使用OSS服務的系統都需要進行註冊、申請應用,成功後自動生成appkey、appsecret。appkey代表應用身份,appsecret即應用金鑰,用於生成簽名認證,請求檔案服務時必須要傳遞appkey和簽名生產的token,閘道器根據請求驗證請求的合法性性和時效性。後臺管理appkey的生成及防盜鏈的簽名如下圖:
手機終端認證
手機端認證同server端一樣,但是由於賬戶資訊的安全問題,appkey和appsecret只能儲存在服務端,手機終端訪問oss時無法生成簽名,那麼手機端如何訪問oss服務?這裡我們採用oauth認證的原理
- app使用者登入終端系統,App傳送請求OSS request請求
- server收到請求後,向OSS申請資源的臨時授權token
- OSS接收授權請求後,生成臨時訪問token返回給server
- server組裝檔案地址與臨時的token,返回給app
許可權管理
每個應用有了自己的appkey,檔案訪問時通過appkey驗證身份,預設檔案的歸屬只有上傳者可以檢視或修改,上傳者可以授權給其他賬戶,通過在後臺管理-許可權配置功能授權授權的級別分為:修改、檢視、刪除,不同的級別對應不同的操作,後臺管理系統會實時同步檔案許可權到檔案系統。這樣其他賬戶只需要傳遞自身的appkey就可以對此檔案訪問。具體流程及具體配置如下:
URL加解密、規範(實現參考)
底層儲存中的檔名稱必須全域性唯一,oss採用自定義演算法生成檔名稱,命名規範=時間戳+分隔符+執行緒ID+分隔符+程式ID+分隔符+客戶端IP,URL規範圖解如下:
為了保證oss伺服器的安全,防止程式檔案和目錄外洩,oss對url進行了私有協議的加密,按分隔符“_”對每一項進行base64編碼,再按62位字典碼加密生成加後的url,當然也有其他的演算法實現,是要實現url加密即可。解密是對加密的逆向操作,解密後的url即為儲存的訪問url。服務端的規範樣例及客戶端的url規範樣例:
oss統計監控
為保證檔案服務的質量和可靠性,系統的監控和告警是必不可少的,各個階段的執行資訊,以日誌的形式寫到檔案中,再使用Flume日誌收集元件採集各個子系統的日誌,按日誌類別直接傳送到kafka的不同topic,ossMonitor讀取kafka中訊息,以時間為單位計算流量、命中率,以空間為單位統計使用率,根據上傳日誌是否有異常傳送告警郵件,流程如下:
Flume是由cloudera軟體公司產出的可分散式日誌收集系統,由source,channel,sink三個元件組成:
- Source:
從資料發生器接收資料,並將接收的資料以Flume的event格式傳遞給一個或者多個通道channal,Flume提供多種資料接收的方式,比如Avro,Thrift,txt等
- Channel:
channal是一種短暫的儲存容器,它將從source處接收到的event格式的資料快取起來,直到它們被sinks消費掉,它在source和sink間起著一共橋樑的作用,channal是一個完整的事務,這一點保證了資料在收發的時候的一致性. 並且它可以和任意數量的source和sink連結. 支援的型別有: JDBC channel , File System channel , Memort channel等.
- sink:
sink將資料儲存到集中儲存器比如Hbase和kafka,它從channals消費資料(events)並將其傳遞給目標地.
Flume配置如下:
gateway.sources = fileEvent
gateway.channels = kafkaChannel
gateway.sinks = loggerSink
# For each one of the sources, the type is defined
gateway.sources.fileEvent.type = TAILDIR
gateway.sources.fileEvent.positionFile = / xxx.json
gateway.sources.fileEvent.filegroups = events
gateway.sources.fileEvent.filegroups.events=/xxx.log
#gateway.sources.fileEvent.type = spooldir
# The channel can be defined as follows.
gateway.sources.fileEvent.channels = kafkaChannel
#gateway.sources.fileEvent.channels = kafkaChannel
#gateway.sources.fileEvent.spoolDir = /home/app/oss_events
# Each sink's type must be defined
gateway.sinks.loggerSink.type = org.apache.flume.sink.kafka.KafkaSink
#Specify the channel the sink should use
gateway.sinks.loggerSink.channel = kafkaChannel
gateway.sinks.loggerSink.kafka.bootstrap.servers=xxx.xxx.xxx.xxx:9092
gateway.sinks.loggerSink.kafka.topic=oss-gateway-events
gateway.sinks.loggerSink.kafka.batchSize=20
gateway.sinks.loggerSink.kafka.producer.requiredAcks=1
# Each channel's type is defined.
gateway.channels.kafkaChannel.type = memory
# Other config values specific to each type of channel(sink or source)
# can be defined as well
# In this case, it specifies the capacity of the memory channel
gateway.channels.kafkaChannel.capacity = 30000
gateway.channels.kafkaChannel.transactionCapacity = 100
複製程式碼
統計圖如下:
作者簡介
劉利鵬,隨行付架構部中介軟體組高階開發工程師,參與隨行付OSS設計與開發,並推廣落地。