傳統Web應用中全部的功能部署在一塊兒,圖片、文件也在一臺服務器;應用微服務架構後,服務之間的圖片共享經過FTP+Nginx靜態資源的方式進行訪問,文件共享經過nfs磁盤掛載的方式進行訪問,不管是單體架構仍是微服務架構下的應用都存在大量圖片、文件讀寫操做,可是昂貴的磁盤空間、高性能服務器無疑增長了運營成本。nginx
因此咱們但願文件服務也能微服務、獨立化,這樣既能下降運營成本,又能對文件進行統一的管理和維護,因此搭建獨立的文件服務是解決文件共享、釋放業務系統壓力的最優選擇。因而便誕生了隨行付分佈式文件系統簡稱OSS(Object Storage Service),提供的海量、安全、低成本、高可靠的雲存儲服務。它具備與平臺無關的RESTful API接口,可以提供數據可靠性和服務可用性。算法
隨着互聯網圖片、視頻時代的到來,對文件的處理成爲各個業務系統面臨的巨大挑戰,沒有文件服務器以前,系統之間處理圖片的方式截然不同:FTP、NFS、數據庫存儲等等,雖然都實現了對文件的存儲、訪問,可是系統之間很難達到文件共享,因此文件服務能夠造成一個統一的訪問標準,下降各個系統之間的互相依賴,提升開發效率、釋放業務系統壓力,因此文件服務的意義以下:數據庫
下降WEB服務器壓力apache
分擔業務服務器的I0、流程負載,將耗費資源的文件訪問、讀寫操做分離到文件服務器,能夠提升服務器的性能和穩定性,下降WEB服務器成本。json
獨立服務易擴展bootstrap
文件服務像微服務架構獨立化,能夠有針對性的進行配置提升性能;獨立域名讓圖片管理、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採用二級緩存:瀏覽器緩存、網關層緩存提高響應速度,具體以下:
第二次請求時同一個文件時,服務器根據請求中HTTP協議中的max-age/Expires,判斷文件未修改,返回狀態碼403,告訴瀏覽器能夠繼續使用本地緩存
第三次請求F5強制刷新,網關根據If-Modified-Since、Cache-Control:no-cache和Pragma:no-cache等信息從新返回nginx中緩存文件
第四次請求url時,requesturi不同但文件是同一個,nginx根據requesturi判斷網關中無此文件,請求底層存儲返回文件。
爲避免文件、圖片盜用,浪費服務器流量和IO等資源,OSS採用防盜鏈的方式認證請求。每一個使用OSS服務的系統都須要進行註冊、申請應用,成功後自動生成appkey、appsecret。appkey表明應用身份,appsecret即應用密鑰,用於生成簽名認證,請求文件服務時必需要傳遞appkey和簽名生產的token,網關根據請求驗證請求的合法性性和時效性。後臺管理appkey的生成及防盜鏈的簽名以下圖:
手機端認證同server端同樣,可是因爲帳戶信息的安全問題,appkey和appsecret只能保存在服務端,手機終端訪問oss時沒法生成簽名,那麼手機端如何訪問oss服務?這裏咱們採用oauth認證的原理:
server收到請求後,向OSS申請資源的臨時受權token
OSS接收受權請求後,生成臨時訪問token返回給server
server組裝文件地址與臨時的token,返回給app
每一個應用有了本身的appkey,文件訪問時經過appkey驗證身份,默認文件的歸屬只有上傳者能夠查看或修改,上傳者能夠受權給其餘帳戶,經過在後臺管理-權限配置功能受權受權的級別分爲:修改、查看、刪除,不一樣的級別對應不一樣的操做,後臺管理系統會實時同步文件權限到文件系統。這樣其餘帳戶只須要傳遞自身的appkey就能夠對此文件訪問。具體流程及具體配置以下:
底層存儲中的文件名稱必須全局惟一,oss採用自定義算法生成文件名稱,命名規範=時間戳+分隔符+線程ID+分隔符+進程ID+分隔符+客戶端IP,URL規範圖解以下:
爲保證文件服務的質量和可靠性,系統的監控和告警是必不可少的,各個階段的運行信息,以日誌的形式寫到文件中,再使用Flume日誌收集組件採集各個子系統的日誌,按日誌類別直接發送到kafka的不一樣topic,ossMonitor讀取kafka中消息,以時間爲單位計算流量、命中率,以空間爲單位統計使用率,根據上傳日誌是否有異常發送告警郵件,流程以下:
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
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
gateway.sources.fileEvent.channels = kafkaChannel #gateway.sources.fileEvent.channels = kafkaChannel #gateway.sources.fileEvent.spoolDir = /home/app/oss_events
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:9092=xxx.xxx.xxx.xxx gateway.sinks.loggerSink.kafka.topic=oss-gateway-events gateway.sinks.loggerSink.kafka.batchSize=20 gateway.sinks.loggerSink.kafka.producer.requiredAcks=1
gateway.channels.kafkaChannel.type = memory
gateway.channels.kafkaChannel.capacity = 30000 gateway.channels.kafkaChannel.transactionCapacity = 100
統計圖以下: