原由
我们在日常工作中一般会遇到你的服务器被请求拖慢的情况,刚开始我也是茫茫然,不知所措,但是我是公司里面负责架构的人啦,不能坐视不管,所以拼命求救。
这里总结一下大部分的看法
- 你的服务器请求太多了,一个子域名在特定的时间接受的请求是有限的
- 你的服务器的I/O到达了瓶颈
- 你的静态资源把网络卡死了,一直在转圈圈
上面的所有的观点都指向了一个方案——动静分离
我刚开始也不知道啥是动静分离哈,于是乎百度一看,原来稍微大点的项目都要用到动静分离。据说还有稍微负载大点的连数据库都要分离呢,不光分离,还需要读写分离。
行动
有了理论基础,那就是开干呗。
- 在市场上找与我们公司匹配的分离方案
- 先把静态资源(上传的文件)分离到 aws s3中,我们的客户是国外居多
- 问高人分离的方案
- 动手开干
结果
我的最后方案是:
- 后台采用我娴熟的thinkPHP框架,这次是采用TP5.1,肯定会有小伙伴问我为毛不用TP6.0搞哇,这个破框架太扯,一年能给你弄出几个大版本出来,你追新?算是一个巨坑,关键是他不支持无缝升级。
- 静态资源,经过多方面的考虑,放置于 aws s3上,因为直接开通,不用向公司申请就能用
- 前台首次采用vue.js
因为我是负责后端的,所以我用这里只写后端的东西,记录一下,方便以后查阅和升级改造
首先、利用composer安装我们的aws sdk
composer require aws/aws-sdk-php
自动加载是thinkPHP帮忙处理了,这里不多说,那些刨根问底的人去www.kancloud.cn去看看,或许能得到更多。
其次、我跟着aws API文档编写一个工具类 aws.php
文件有注释,所有这里不做太多的解释
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019/5/11
* Time: 8:47
*/
namespace app\common\helper;
use Aws\Exception\AwsException;
use Aws\Exception\MultipartUploadException;
use Aws\S3\S3Client;
use Aws\S3\MultipartUploader;
use think\facade\Config;
/**
* Class Aws
* @package app\common\helper
*/
class Aws
{
protected $Bucket;
/**
* 最后修改日期:20190520 1314520 我就是那个爱你的pythoner 啊
* 本方法 创建一个s3的客户端,app_key option 都存储在app.config中
* 具体写法 请参考 aws s3的php sdk 示例
* https://docs.aws.amazon.com/zh_cn/sdk-for-php/v3/developer-guide/getting-started_basic-usage.html
* @return S3Client
*/
public static function createClient()
{
$aws_app_key = Config::get('app.aws_app_key');
$aws_options = Config::get('app.aws_options');
$options = [
'version' => $aws_options['version'],
'region' => $aws_options['region'],
'credentials' => [
'key' => $aws_app_key['key'],
'secret' => $aws_app_key['secret']
],
'debug' => $aws_options['debug']
];
$s3 = new S3Client($options);
return $s3;
}
/**
* @param $source
* 源文件 上传文件 修改时间 20190517
* 本方法 上传文件到s3 存储桶中
* 需要两个参数 第一个参数是文件本身
* 第二个是 文件名 也就是key
* 该方法能将文件上传到亚马逊s3,如果成功返回文件在s3中的地址;
* API参考 连接 MultipartUploader
* https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html
* @param $key
* @return mixed|void
*/
public static function uploader($source, $key)
{
$client = self::createClient();
$uploader = new MultipartUploader($client, $source, [
"bucket" => Config::get('app.aws_bucket'),
"key" => $key,
]);
do {
try {
$result = $uploader->upload()->get('Key');
} catch (MultipartUploadException $exception) {
rewind($source);
$uploader = new MultipartUploader($client, $source, [
'state' => $exception->getState(),
]);
}
} while (!isset($result));
return $result;
}
/***
* 根据key 删除 本桶里的数据
* 修改时间 : 20190520 1314520
* 接收一个参数,就是需要删除的key
* 如果这个文件存在,就删除,没有查询到这个文件就忽略掉不删除,防止在存储桶里删除了文件,系统里没有删除导致程序出错
* API 参考 getObjectUrl deleteObject
* https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html
* @param $key
* @return bool
*/
public static function deleteKey($key)
{
$Bucket = Config::get('app.aws_bucket');
$client = self::createClient();
try {
$client->getObjectUrl($Bucket, $key); //有url
try{
$client->deleteObject(['Bucket' => $Bucket, 'Key' => $key,]);
return true; //删除成功
}catch (AwsException $exception){
return false; //删除失败!
}
} catch (AwsException $exception) {
return true; // 所查询的 KEY 不存在 不需要删除
}
}
}
有了这个类后,我们就可以use 他啊,很方便,我这里全部都定义了静态方法,在网上有看到他们的bucket \key 都放在这个文件里,我觉得不妥,我就提取出来放到了config里去了,所以这里你看不到真实的appkey bucket等信息
再次、我们就是调用该类,进行上传 和删除工作了是吧,这里提一个傻逼搞了一个错误2天才搞定,你知道是什么吗?哈哈。我在刚开始开发时把aws sdk的debug开启了,刚开始还蛮爽,都看到了所有的信息,但是后来,我要调用格式化数据是,发现这根本不是我要的数据,折腾了两天,结果把debug关闭就好了。我也是醉了。
<?php
/**
* Created by PhpStorm.
* User: admin
* Date: 2019/5/13
* Time: 14:05
*/
namespace app\admin\controller;
use app\common\helper\Aws as AwsHelper;
/**
* Class Aws
* @package app\admin\controller
*/
class Aws extends Base
{
public function uploader()
{
if (Request()->isGet()) {
return "ok";
}
if (Request()->isPost()) {
$soure = $this->request->file('file');
$key = $soure->getInfo('name');
$result = AwsHelper::uploader($soure, $key);
if ($result) {
return $result;
}
}
}
}
问题
上传,该方法接受post请求,将文件接受到$soure中,上面 use AwsHelper类,下面就直接调用他里面的uploader方法,即可把文件上传到s3的桶里去。这里当然经历了很多曲折
- 开启那个傻逼模式的debug,关闭他
- 上传文件大于50M就傻缺了
- 修改php.ini 里的 upload_max_filesize 为300M,因为我这里的文件可能会在300M以下
- 修改nginx.conf 里 http段下面的 client_body_timeout 300s; client_max_body_size 300m;
- 上线到线上服务器后发现超时错误,和超过内存限制错误
- 修改php.ini里的几个参数
- memory_limit = 256M //这个参数后面发现可以视情况调整小一点,我们要根据服务器的配置来调整这个参数哈
- max_input_time = 900 //这个时间是我们上线后才发现有问题的,把这个调长一点就能好了,具体多长看情况
- max_execution = 300 //我这里 从他原来的90 调整到300
- 修改php.ini里的几个参数
- 上传接收文件并上传是交给apache完成的,所以apache的配置也要修改,只不过他的这个修改在httpd-default.conf里
- 这个问题是关于上传到aws超时故障的,我们将Timeout 设置为3600
- 上线时发现thinkPHP 5.1 需要支持到PHP7以上才能工作
- 升级php5.6 到php-7.2.13
- 开启强制路由,用于防止一些安全事故发生的,我在Python 里写的都是基于路由的,tornado、flask里 都是基于路由的
- 在larval里 就明确地需要用路由映射才能使用
总结
- 开发过程中一定要写好故障处理指南,后面在其他项目中会减少跳坑动作
- 你写的文档会被别人看到,人家会来批判(喷水)你的编写,你可以从评论中学习其他高人的看法、
- 总结归纳你这个过程里的所有的坑,会让你更充实
下一步
新技术总是从边缘来到中心的,所以别以为现在我们学习的这些东西没啥用,或许哪天他就是主流。我兄弟袁普照就是这样。