欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

魅族图片服务2.0

程序员文章站 2022-03-29 19:59:29
...

魅族图片服务2.0

图片服务1.0现状及问题

  1. 使用MFS作为存储,有单点失效问题IO性能差,经常不可用.
  2. 代码耦合度高,不易拆分功能模块,难以维护和扩展新功能.
  3. 调用第三方图片处理工具的效率低下,每秒处理图片不足20张.

图片服务2.0功能需求

  1. 对图片进行处理,按需要转换为指定的尺寸.
  2. 对gif图片进行静态化处理
  3. 图片文件存储方式灵活可靠,具备横向扩展能力
  4. 图片上传/下载支持自定义路径
  5. 支持用户直接上传图片到图片服务器,避免占用业务服务器带宽.

设计说明

设计目标

  1. 模块松散耦合,可以简单拆分,预留演化为分布式的空间 2. 存储设备可以灵活选择替换,并且高可用
  2. 业务可以低成本接入
  3. 为业务提供丰富的上传/下载图片方式

图片模式表达式设计 模式表达式分为尺寸说明和修饰符两部分,一个模式表达式可以包含一组尺寸说明和多个不同的修饰符.

尺寸说明表示为[X*Y*]W*H*[.ext], 表示期望图片处理得到的结果的最终尺寸,“*”可以替换 为数字.

  • W*H* : 结果图片的宽高
  • X*Y* : 左上角在源图上的坐标,可选 .ext : 结果图片的格式扩展名

修饰符表示从处理源图得到目标尺寸结果的方法,例如“居中裁剪”,“等比缩放”等等.多个修饰符尺寸说明间使用“_”进行分割.

现有的修饰符如下:

  • CENTER : 居中裁剪
  • MAX : 不超过W*H*指定的尺寸
  • CUT : 从源图的X*Y*开始裁剪W*H*
  • AUTO: 自动降低图片质量
  • FIT : 先按W或H进行等比放大,然后裁剪为目标尺寸 B : 处理后的结果图片边界尺寸不能超过原始图片 GIF1 : 取gif图片的第一帧

实例:
X50Y50W100H100_CUT : 从源图的(50,50)坐标点开始裁剪长宽均为100的图片.

W200H200_B_GIF1 : 取出gif图片的第一帧,如结果图片尺寸<200*200,则保持原有尺寸 不变.

图片处理方案

图片处理能力沿用1.0使用的第三方工具GraphicMagick(gm)+im4java,升级到当前稳定版 的最新版本.1.0中使用gm命令处理图片,该命令每次启动一个进程处理完图片就退出了, 在并发处理图片时进程频繁创建销毁效率低下.

通过查阅GraphicMagick文档发现 gm batch 命令处理完图片之后不会退出进程,而是会 从标准输入中等待下一张图片进行处理.利用该特性,重新实现im4j的ImageCommand接 口.并对 gm batch 进程进行池化管理,提高图片处理效率.最终实现经过测试,在魅族标准 化服务器环境下(6核CPU),每秒可以处理270多张图片,是1.0的20倍左右.

元数据结构设计与存储

图片上传后需要保存图片的元数据,用于进行图片在存储设备中的定位和缓存图片的尺 寸格式信息.数据结构可以表示为如下形式:

{
  "_id": "c5f41e85dccc4445eba7ef92e9e3045a",
  //图片的唯一标识
  "bizId": "uc",
  //图片所属的业务id
  "storageId": 1,
  //保存图片的存储设备id
  "url": "uc:/83/44/39/20/00/8344392",
  //图片的自定义url可以为null
  "size": 7,
  //占用的磁盘空间,单位KB
  "files": [
    //图片文件列表,第一个是源图,其余是被访问后生成的图片
    {
      //图片的模式表达式
      "model": "W300H300.PNG",
      //文件的md5
      "md5": "3b80b0347254e9ef511ebcb6daea39e7",
      //文件在存储设备上的路径
      "path": "aaa@qq.com/00/00/rBADO1cN_DmAAIvCAAAeQnH7sUY998.PNG",
      "size": 7
      //文件占用的磁盘空间
    },
    ...
  ],
  "updateTime": "2016-04-13T07:58:48.318Z"//最后更新时间
}

该数据结构解释为如下描述:

一个“图片”隶属于一个“业务”,可以包含多个文件,保存在同一个“存储设备”上.

对图片元数据的查询需求99%都是根据图片ID的定位查询,对其的操作也无须事务保障. 基于此,使用nosql数据库可以更加简单的维护上述数据结构.

mongodb作为一种相对成 熟的方案,具有原生的分片集群方案,具备良好的横向扩展性.

在运维方面,mongodb的分片方案也比较容易部署,在公司内部也有实施经验.

对开发人员来说集群是透明的,不需要额外的编码支持.相比mysql这类关系数据而言,往往需要在编码层面提供分表分库支持,才能组织利用集群,且扩容时很难避免数据迁移操作.这类操作的运维成本往往较高.

安全性上,mongodb集群提供副本集能力,且在API级别提供丰富的操作副本的能力,对当个文档的操作提供原子性保障.

性能上,经过测试对上述数据结构基于ID的查询支持每秒2万次以上(不是极限性能,只是 根据当前图片服务访问量需求进行的指标测试)

故图片2.0选用mongodb3进行元数据存储

高可用文件存储存储设备方案

在图片服务2.0中,建立存储设备抽象隔离具体使用的存储设备,理论上可以支持任何存 储方案,例如NFS,MFS,FastDFS.最终经过咨询和资料调研,选择了FastDFS作为主要存储设 备方案.FastDFS适合小文件的分布式存储,而图片类文件一般都符合FastDFS的小文件定 义,且FastDFS没有1.0使用的MFS的单点问题.
存储设备定义:
1. 可以持久化保存图片文件的设备.

  1. 上传图片到该设备返回字符串标示(例如底盘上的存储路径),根据该表示可以定位读 取该文件.

  2. [可选]提供HTTP下载能力

存储设备可以配置为公共的,或者某个业务独享的.多个存储设备间可以配置为加权轮询方式使用,提供IO的横向扩展能力,和一定的容灾能力.
魅族图片服务2.0

软件架构

图片服务2.0分为4个解耦的独立模块

  1. 接入服务 : 暴露对外的上传/下载接口

    • 上传 业务服务器直接上传图片,需要传入业务id和预分配的secret_key,并对请求进行签名.以防止非法上传文件. 外部用户上传图片,需要先通过业务服务器申请授权token以识别上传的图片隶属于哪个业务.

    • 下载 下载服务是公开的,使用CDN进行缓存.

    下载可以使用三种URL
    1). http://image.meizu.com/image/{业务ID}/{图片ID}
    2). http://image.meizu.com/get/{自定义或原始图片地址} (图片地址由上传时传入的参数 决定)
    3). http://{业务原始图片服务域名}/{业务原始图片服务地址}

  2. 图片处理 : 调用gm batch命令进行图片处理,管理命令进程池. 处理命令抽象为三步,解析模式表达式->生成gm命令参数->执行命令->返回结果

  3. 存储服务 : 管理存储设备和业务关系,对其他模块提供图片读写服务
  4. 授权服务 : 对外部用户上传图片操作进行鉴权/授权 授权token设计为业务ID+16位随机字符串,可以由业务设置有效时间.

下图为各模块与外部协调交互完成上传/下载操作的示意图:
魅族图片服务2.0

部署架构

魅族图片服务2.0

业务接入方式设计

  1. 如果业务没有原始图片,可以直接使用提供的JAVA-SDK进行接入.

  2. 如果业务原本使用其他存储方案已经保存了大量图片,迁移图片的过程是痛苦的. 图片服务2.0提供了托管下载模式. 流程图如下:
    魅族图片服务2.0
    通过将业务的原始服务器内网ip地址配置在图片服务2.0的配置中心,然后直接将域名DNS解析到图片服务的ip地址即可对外不间断提供图片下载服务(使用下载地址3)方 式).不改代码,不改图片地址,完全无缝接入. 如果受条件限制不能配置DNS解析,则需 要更改原始图片下载地址的前缀为图片服务约定前缀(下载地址2)方式). 无须改动业 务逻辑代码.

相关标签: 架构