传统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采用二级缓存:浏览器缓存、网关层缓存提高响应速度,具体以下:
第一次请求文件时,OSS返回文件给浏览器http的状态码是200
第二次请求时同一个文件时,服务器根据请求中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认证的原理:
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
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.channels = kafkaChannel
gateway.sinks.loggerSink.type = org.apache.flume.sink.kafka.KafkaSink
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
gateway.channels.kafkaChannel.type = memory
gateway.channels.kafkaChannel.capacity = 30000
gateway.channels.kafkaChannel.transactionCapacity = 100
统计图以下: