千万级图片资源存储方案分享

浏览:5029 发布日期:2016/05/01 分类:技术分享 关键字: 图片存储 图片服务器
本文节选自
H5应用必须掌握的技能点-图片篇
http://www.imwinlion.com/archives/158
1、怎么存储图片
这个问题的实质是如何设计上节 的$dstPath问题。是为什么会有这个问题呢?笔者在日常开发种发现很多图片存储无设计, 所以的到的图片大概是这样的

http://shang.qq.com/wpa/qunwpa?idkey=7322d7b39a8564d24b48b5e7d83fcde645f4c0e9ad84f1f7ddc7baff47574d7d

http://www.imwinlion.com/wp-content/uploads/2016/04/新建图像-300×300.png

像这种图片结构,在应用根目录下新建一个upload 文件夹,然后下面分日期/uploads/2016/04/ 在小型的应用中,还能将就着用的,但是一旦图片数目多起来,并且要存储的是图片的id时,我们该怎么做呢?笔者研读阿里的 fastfs,并经过大量的应用实践,积累了一套实用好操作的图片命名策略,如下

[hostid][level][dirstr][filename][suffix]

这种名称策略怎么理解呢?

hostid:图片服务器资源ID.这个涉及到我们自身的服务器资源规划问题。自定义的,比如我们应用占用了俩台服务器资源,一台是应用服务器,我们编号为0,一台是资源服务器,我们将这个服务器资源编号为1,这个数据就是hostid
level:相对于图片服务根目录来说,图片存储的文件夹目录深度,一般为俩层。比如我们存储的根目录为 /mnt/h5app/,那么这下面 的 目录 a/b/c,level就是3
dirstr:目录字符串,如上,目录字符串就是abc
filename: md5 策略或者uuid 策略生成 的文件名,如md5(microtime() . mt_rand(1000,9999));
suffix:文件的后缀,如.jpg,.png
举个列子。假设我们的应用服务器服务器,编号是0,根目录是/alidata/www/www.imwinlion.com/ ,对应的域名是www.imwinlion.com

我们的图片服务器有三台,一台编号是1,目录是/mnt/www.imwinlion.com/ ,对应的域名是res1.imwinlion.com

另一台编号是2,根目录是/mnt/www.imwinlion.cn/,对应的域名是res2.imwinlion.com

现在,我们根据我们设计的文件存储策略,假设名称是13abc01f9c76ce5c45aeec2e6f816c95b854b.jpg,那么根据问价夹的第1位数字,知道这个文件hostid 是1,

应该存放在编号为1的服务器,也就是/mnt/www.imwinlion.com/ 下

根据第二个参数level 为3,我们知道这个文件有3个父级子目录,那么接下来的三个字母abc 就是dirstr , 接下来的01f9c76ce5c45aeec2e6f816c95b854b 是md5 生成的随机字符串

最后.jpg 是文件格式,那么这个文件的存储路径应该是这样

/mnt/www.imwinlion.com/a/b/c/13abc01f9c76ce5c45aeec2e6f816c95b854b.jpg

对应访问地址是这样 http://res1.imwinlion.com/a/b/c/13abc01f9c76ce5c45aeec2e6f816c95b854b.jpg,文件id 就是文件名称 13abc01f9c76ce5c45aeec2e6f816c95b854b.jpg

我们数据库存这个id ,前端只要根据策略和这个ID就能够获得 图片路径

这种策略的核心在于先根据业务逻辑规划出图片存放路径。是先知道了文件路径,然后再存储。但是我们常用的框架,把文件的命名策略封闭起来了,我们只能先存起来,再获得文件名。这需要改造!!
2、给个实例

此列子相关的详细场景 见
http://www.imwinlion.com/archives/158<?php  //cfgupload.php 配置文件
return array (
  'UPLOAD' => 
  array (
    'maxSize' => 2097152,
    'exts' => 
    array (
      0 => 'jpg',
      1 => 'gif',
      2 => 'png',
      3 => 'jpeg',
      4=>"mp3",
    ),
    'rootPath' => '/mnt/img.imwinlion.com/',
    'savePath' => '',
    'driver' => 'Local',
    'subType' => 'hash',
    'hashLevel' => 1,
    'domain' => 'res1.imwinlion.com',
    'scheme' => 'http',
    'subDir' => 'upload',
  ),
);

 /*该函数处理前端上传过来的base64场景*/    
 function uploadb64(){
        $uploadcfg=C('UPLOAD');
        
        $hashLevel = intval($uploadcfg["hashLevel"]);
        $rootPath = $uploadcfg["rootPath"];
        $savePath = $uploadcfg["savePath"];
        $subDir = $uploadcfg["subDir"];
        $scheme = $uploadcfg["scheme"];
        $domain = $uploadcfg["domain"];
        $dir = "";
        $filename = md5(microtime()).".jpg";
        
        $str = "0123456789abcdef";
        $a1 = "";
        $a2 = "";
        if($hashLevel!=2 && $hashLevel!=1){
            $$hashLevel = 1;
        }
        if($hashLevel==1){
            $a1 = $str[mt_rand(0,strlen($str))];
            $savePath = $a1;
            $filename = $hashLevel. $a1 .$a2. $filename;
        }
        if($hashLevel==2){
            $a1 = $str[mt_rand(0,strlen($str))];
            $a2 = $str[mt_rand(0,strlen($str))];
            $savePath = $a1 ."/" .$a2 ;
            $filename = $hashLevel . $a1 .$a2. $filename;
        }
        
        //根据策略获得hostid
        $filename .= ($this->gethostid(0) . $filename);
        
        $this->base64toimage($this->request["data"],$rootPath . "/" . $subDir ."/". $savePath ."/". $filename );
        
        
        
        $resp = array();    
            
       

        
       $url = $scheme. "://" . $domain . "/".   $subDir ."/".$savePath ."/". $filename ;
       $resp["url"] = $url;
       $resp["error"] = 0;
       $resp["state"]="SUCCESS";
        
    
         if($this->request["callback"]) {
                    echo '<script>'.$callback.'('.json_encode($resp).')</script>';
                } else {
                    echo json_encode($resp);
                }

    }
    
    
    function base64toimage($strBase64, $outputFile ) {
        
        $ifp = fopen( $outputFile, "wb" ); 
        fwrite( $ifp, base64_decode( $strBase64) ); 
        fclose( $ifp ); 
        return( $outputFile ); 
    } 
    
    
    /*这里有个技巧,我们根据入参业务频繁程度获取if*/
    function gethostid($type=0){
            //存那一台服务器逻辑需要我们自己编写
            //我们这里演示 默认定死了 为1
            return 1;
        
    }
最佳答案
评论( 相关
后面还有条评论,点击查看>>