Discuz 论坛附件、头像等资源迁移到阿里云 OSS 并开启 CDN 的解决方案

赵达

Discuz 论坛的附件、头像等资源不断增长,如果和主程序一起存储在云服务器上,就会导致云盘要定期进行扩容操作;附件如果需要进行 CDN 加速也只能使用回源策略进行 CDN 配置。为了一劳永逸的解决附件存储和加速问题,将附件等资源迁移到对象存储服务上是一个好的选择,本文以阿里云 ECS、OSS 服务为背景,其他云计算平台也可以参考。

创建 OSS Bucket

开启 CDN

迁移附件和头像

ossfs 基于s3fs 构建,具有s3fs 的全部功能。主要功能包括

  • 支持POSIX 文件系统的大部分功能,包括文件读写,目录,链接操作,权限,uid/gid,以及扩展属性(extended attributes)
  • 通过OSS 的multipart 功能上传大文件
  • MD5 校验保证数据完整性
# 下载并安装
wget http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/32196/cn_zh/1524809958556/ossfs_1.80.4_centos7.0_x86_64.rpm?spm=a2c4g.11186623.2.6.XJB3Dd&file=ossfs_1.80.4_centos7.0_x86_64.rpm
mv ossfs_1.80.4_centos7.0_x86_64.rpm?spm=a2c4g.11186623.2.6.QwMtDE ossfs_1.80.4_centos7.0_x86_64.rpm
yum localinstall ossfs_1.80.4_centos7.0_x86_64.rpm
img-bucket:AccessKey:AccessKeySecret
my-bucket:AccessKey:AccessKeySecret
chmod 640 /etc/passwd-ossfs
yum install mailcap
# 假设论坛根目录为 /data/htdocs/www ,后续脚本将以此为准,请根据实际情况修改
mv /data/htdocs/www/data/attachment /data/
mv /data/htdocs/www/uc_server/data/avatar /data/
# 重新创建被剪的目录
mkdir /data/htdocs/www/data/attachment
mkdir /data/htdocs/www/uc_server/data/avatar

# 获取运行 php-fpm 和 nginx 的系统用户 uid 和 gid,比如 www 用户
# uid=1000(www) gid=1000(www) 组=1000(www)
id www

# 挂载 bucket
# Endpoint:请使用内网地址,速度快且流量免费
# -o noxattr:如果你没有使用eCryptFs等需要XATTR的文件系统,可以提升性能
# -o kernel_cache:使用文件系统的 page cache
# -o allow_other:允许其他用户访问挂载文件夹
# -ouid -ogid:制定挂载目录的用户和组权限
ossfs img-bucket /data/htdocs/www/data/attachment -ourl=Endpoint -o noxattr -o kernel_cache -o allow_other -ouid=1000 -ogid=1000
ossfs avatar-bucket /data/htdocs/www/uc_server/data/avatar -ourl=Endpoint -o noxattr -o kernel_cache -o allow_other -ouid=1000 -ogid=1000
cp -rf /data/attachment/* /data/htdocs/www/data/attachment
cp  -rf /data/avatar/* /data/htdocs/www/uc_server/data/avatar
# 到 oss bucket 文件管理验证数据没有问题后可以删除临时拷贝
rm -rf /data/attachment/
rm -rf /data/avatar/
# root用户
umount /data/htdocs/www/data/attachment
umount /data/htdocs/www/uc_server/data/avatar
# 非root用户
fusermount -u /data/htdocs/www/data/attachment
fusermount -u /data/htdocs/www/uc_server/data/avatar
# 根据下面的模板创建启动脚本
vi /etc/init.d/ossfs
# 添加执行权限
chmod a+x /etc/init.d/ossfs
# 设置开机启动
chkconfig ossfs on
#! /bin/bash
#
# ossfs      Automount Aliyun OSS Bucket in the specified direcotry.
#
# chkconfig: 2345 90 10
# description: Activates/Deactivates ossfs configured to start at boot time.

ossfs img-bucket /data/htdocs/www/data/attachment -ourl=Endpoint -o noxattr -o kernel_cache -o allow_other -ouid=1000 -ogid=1000
ossfs avatar-bucket /data/htdocs/www/uc_server/data/avatar -ourl=Endpoint -o noxattr -o kernel_cache -o allow_other -ouid=1000 -ogid=1000

修改论坛附件和头像地址

论坛附件url地址

论坛头像调用方式

// 查找下面的代码并修改
// $file = $ucenterurl.'/data/avatar/'.$dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg';
// return $returnsrc ? $file : '<img src="'.$file.'" onerror="this.onerror=null;this.src=\''.$ucenterurl.'/images/noavatar_'.$size.'.gif\'" />';
// 使用头像cdn地址
$cdnurl = 'http://avatar.example.com/';
$file = $cdnurl.$dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg';
return $returnsrc ? $file : '<img src="'.$file.'" onerror="this.onerror=null;this.src=\''.$cdnurl.'noavatar_'.$size.'.gif\'" />';
$avatar = './data/avatar/'.get_avatar($uid, $size, $type);
if(file_exists(dirname(__FILE__).'/'.$avatar)) {
	if($check) {
		echo 1;
		exit;
	}
	$random = !empty($random) ? rand(1000, 9999) : '';
  // rewrite avatar url
  $avatar = 'http://avatar.example.com/'.substr($avatar, 14);
  $avatar_url = empty($random) ? $avatar : $avatar.'?random='.$random;
} else {
	if($check) {
		echo 0;
		exit;
	}
	$size = in_array($size, array('big', 'middle', 'small')) ? $size : 'middle';
  // $avatar_url = 'images/noavatar_'.$size.'.gif';
  // rewrite avatar url
  $avatar_url = 'http://avatar.example.com/noavatar_'.$size.'.gif';
}

if(empty($random)) {
	header("HTTP/1.1 301 Moved Permanently");
	header("Last-Modified:".date('r'));
	header("Expires: ".date('r', time() + 86400));
}

// header('Location: '.UC_API.'/'.$avatar_url);
header('Location: '.$avatar_url);

论坛 JS、CSS、样式图片等资源接入 CDN

server
{
	listen	80;
	server_name static.example.com;

	index index.html index.htm;
	root  /data/htdocs/www;
	# error_page  404 = /topic-1.html;
	expires max;

	location ~ /\.git
	{
		return 404;
	}

	location ~ ^/.*\.(php|php5)$
	{
		deny all;
	}
	
	access_log  off;
}

论坛 JS、CSS、样式图片等资源接入 CDN

小云 APP 缩略图接入 CDN

private static function _getThumbUrlFile($image, $thumb) {
    //支持自定义CDN域名
    $cacheurl = Yii::app()->params['mobcent']['cache']['cdndomain'];
    if(empty($cacheurl)){
        $cacheurl = Yii::app()->getController()->dzRootUrl;
    }
    // return sprintf('%s/%s/%s/%s_%s', 
    //     $cacheurl,
    //     MOBCENT_THUMB_URL_PATH,
    //     self::_getThumbTempPath($image),
    //     (isset($_GET['sdkVersion']) && $_GET['sdkVersion'] > '1.0.0') ? 'xgsize' : 'mobcentSmallPreview',
    //     $thumb
    // );
    // 修改缩略图地址
    return sprintf('%s/%s/%s_%s', 
        $cacheurl,
        self::_getThumbTempPath($image),
        (isset($_GET['sdkVersion']) && $_GET['sdkVersion'] > '1.0.0') ? 'xgsize' : 'mobcentSmallPreview',
        $thumb
    );
}

后记

参考

返回首页