编程措辞:PHP、Javascript、Vue、Java
开拓框架:Laravel、SpringBoot
中间件:Redis、Kafka、Nginx

数据库:Mysql、MongoDB
云做事:腾讯云(利用了CDN加速)
业务接口的逻辑:
页面发送一个ajax要求,业务处理这块,PHP这块只是作为一个中转过渡的浸染,实际上业务的紧张处理都是放在SpringBoot这边。页面要求Laravel的一个接口,接口中只是做了一些基本的参数校验,然后内部调用SpringBoot接口,吸收到SpringBoot接口返回数据之后,PHP直接将数据返回给客户端。伪代码如下:
public function page(Request $Request){ //参数校验 //将要求数据包暂存redis,由于要求传参数据包比较大,这种办法可以减少传参数据的大小 $redis_id = makeUuid(); $WS->sessionSet($redis_id, json_encode($args), 120, true); //内部调用SpringBoot接口(利用的是内网IP) $apiData = InnerRequest::get($_SERVER['SERVER_NAME'],'application/page/handle',[ 'method' => 'page.get', 'data' => $redis_id ]); if ($apiData['code'] != 200) { return response()->json(['code' => $apiData['code'], 'message' => $apiData['message']]); } //获取缓存数据 $data = $WS->sessionGet($apiData['data']['data'], true); $WS->sessionRemove($apiData['data']['data'], true); if (empty($data)) { return response()->json(['code' => 500, 'message' => "无返回数据结果"]); } / 1、处理返回的工具数据包 1.1:去掉不须要的字段 / return response()->json($data); }
影响网页加载速率的成分
影响一个网站的成分是多方面的,我们大致可以列举一下:
1】做事器从磁盘中读取页面数据
2】页面静态文件数量以及大小
3】页面ajax要求数量
4】做事器的相应韶光
5】做事器本身的性能
6】浏览器本地渲染和打算的韶光
Chrome浏览器DevTools指标解释
剖析网页加载速率,紧张查看Timing指标,而Timing紧张有以下几个维度:
1、Queuing紧张是资源加载的排队
不可优化部分要求被渲染引擎推迟,如脚本/样式会优先,图片推迟。天生磁盘缓存条款所用的韶光(常日非常迅速)。可优化部分要求已被停息,以等待将要开释的不可用TCP套接字。浏览器线程池不是无限的,须要等待socket(TCP)开释。 合并小文件减少要求。 要求被停息,HTTP 1上,浏览器仅许可每个源拥有六个TCP连接。紧张是对做事器的保护。 可以把资源放到不同的域名上,参考`域名发散`。2、Stalled/Blocking要求等待发送所用的韶光。Queuing中的所有缘故原由加上代理协商所用的任何韶光。
不可优化部分Queuing中不可优化部分代理协商可优化部分Queuing中可优化部分相同的N次要求 缓存锁,一样平常资源加载不会加载相同的,但ajax有可能,加timestamp可办理。3、Proxy Negotiation与代理做事器连接协商所用的韶光。
紧张是浏览器通过代理做事器去做事目标做事,如本地代理Fiddler,一样平常无法优化。
4、DNS LookupDNS查询所用的韶光
可优化部分不要有太多的新域名(可能递归查询绕地球一圈),参考域名收敛。减少DNS解析路径(如果内部有很多DNS做事器解析)。5、Initial Connection / Connecting建立连接所用的韶光,包括TCP 握手/重试和协商 SSL的韶光。
6、SSL完成SSL握手所用的韶光。
可优化部分须要区分好什么资源须要https,什么须要http。7、Request Sent / Sending发出网络要求所用的韶光。常日不到一毫秒。
8、Waiting (TTFB)等待初始相应所用的韶光,也称为至第一字节的韶光。
可优化部分 做事器相应速率 做事器网络带宽9、Content Download / Downloading吸收相应数据所用的韶光。
可优化部分 做事器网络带宽 单个文件大小一、首先网站涌现TTFB时长变长干系截图:调取慢日志:Laravel框架一贯在打印涌现了文件锁
[13-May-2021 11:00:39] [pool wepaas] pid 98751script_filename = /ebsig/data/laravel/public/index.php[0x00007f9fb2e1ee20] fopen() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:54[0x00007f9fb2e1ed70] sharedGet() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php:71[0x00007f9fb2e1ecd0] read() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Store.php:97[0x00007f9fb2e1ec50] readFromHandler() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Store.php:87[0x00007f9fb2e1eb80] loadSession() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Store.php:71[0x00007f9fb2e1eb20] start() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:102[0x00007f9fb2e1eab0] Illuminate\Session\Middleware\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Support/helpers.php:1041[0x00007f9fb2e1ea30] tap() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:103[0x00007f9fb2e1e9c0] startSession() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:57[0x00007f9fb2e1e890] handle() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151[0x00007f9fb2e1e7c0] Illuminate\Pipeline\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53[0x00007f9fb2e1e700] Illuminate\Routing\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:37[0x00007f9fb2e1e630] handle() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151[0x00007f9fb2e1e560] Illuminate\Pipeline\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53[0x00007f9fb2e1e4a0] Illuminate\Routing\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:66[0x00007f9fb2e1e370] handle() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:151[0x00007f9fb2e1e2a0] Illuminate\Pipeline\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php:53[0x00007f9fb2e1e1e0] Illuminate\Routing\{closure}() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:104[0x00007f9fb2e1e160] then() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Routing/Router.php:667[0x00007f9fb2e1e0b0] runRouteWithinStack() /ebsig/data/laravel/vendor/laravel/framework/src/Illuminate/Routing/Router.php:642
办理方案:
由于分布式框架缘故原由,运用利用的是共享存储,后面将Laravel框架内的session文件目录调度到做事根目录的tmp下,调度Laravel框架下的config\session.php文件
/ |-------------------------------------------------------------------------- | Session File Location |-------------------------------------------------------------------------- | | When using the native session driver, we need a location where session | files may be stored. A default has been set for you but a different | location may be specified. This is only needed for file sessions. | / 'files' => '/tmp'
同时也将限流限定去掉
//调度文件app\Http\Kernel.php/ The application's route middleware groups. @var array / protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ //'throttle:60,1', //把这个拿掉 'bindings', ], ];
Laravel默认的限流是针对IP,频率为60次/分钟,经由测试创造,如果多个IP属于同一个局域网,比如连接同一个WI-FI,则会剖断为同一个IP,进行限流。也便是说如果同一个局域网下有20人在利用,那么每人刷新3次,就达到了限流标准。 就会返回429 Too Many Requests ,而且因此Laravel默认的缺点页面渲染的办法返回,如果不加以处理,在特定场景下无法知足业务需求。
VUE代码优化:vue-router配置路由 , 利用vue的异步组件技能 , 可以实现按需加载.但是,这种情形下一个组件天生一个js文件{ path: '/home', name: 'home', component: resolve => require(['@/components/home'],resolve) },{ path: '/index', name: 'Index', component: resolve => require(['@/components/index'],resolve) },{ path: '/about', name: 'about', component: resolve => require(['@/components/about'],resolve) }
办理方案:
删除了无用的路由和一些页面文件,调度路由,确保所有的路由页面都走
关于TTFB优化结语:
紧张还是由于Session文件存储问题导致的TTFB缓慢,业务的代码这块并不存在耗时的部分,调度了存储目录之后,网站没有再涌现TTFB过长问题,但是紧接着涌现了Content-download耗时过长问题,平时运行正常的页面,却涌现了须要3秒旁边的加载韶光。
二、办理网站涌现ContentDownload过长干系截图:
问题初步剖析:
从截图中可以剖析出来,返回的数据包相对较大(330KB),其次也有可能是由于做事真个网络带宽问题引起的传输过慢。于是从做事端和代码层面都做了详细的日志跟踪打印。
运用程序跟踪:
从Laravel框架index入口开始,对付全体要求链路做了耗时打印,由于做事端会对每次要求头追加一个要求ID,HTTP_X_REQUEST_ID,以是有了这个要求ID,就能够对一次要求的完全链路做很好的跟踪。
<?php/ Laravel - A PHP Framework For Web Artisans @package Laravel @author Taylor Otwell <taylor@laravel.com> //|--------------------------------------------------------------------------| Register The Auto Loader|--------------------------------------------------------------------------|| Composer provides a convenient, automatically generated class loader for| our application. We just need to utilize it! We'll simply require it| into the script here so that we don't have to worry about manual| loading any of our classes later on. It feels great to relax.|/$starttime = microtime(true);require __DIR__.'/../bootstrap/autoload.php';/|--------------------------------------------------------------------------| Turn On The Lights|--------------------------------------------------------------------------|| We need to illuminate PHP development, so let us turn on the lights.| This bootstraps the framework and gets it ready for use, then it| will load up this application so that we can run it and send| the responses back to the browser and delight our users.|/$app = require_once __DIR__.'/../bootstrap/app.php';require_once __DIR__ . '/../app/Libraries/Login.php';$handle_files_time = microtime(true)-$starttime;if ($handle_files_time > 0.5) {error_log($_SERVER['REQUEST_URI'].'<br>'.$_SERVER['HTTP_X_REQUEST_ID'].'==require_once文件结束总耗时:' . $handle_files_time);}/|--------------------------------------------------------------------------| Run The Application|--------------------------------------------------------------------------|| Once we have the application, we can handle the incoming request| through the kernel, and send the associated response back to| the client's browser allowing them to enjoy the creative| and wonderful application we have prepared for them.|/$send_starttime = microtime(true);$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);$response = $kernel->handle( $request = Illuminate\Http\Request::capture());$response->send();$handle_business_time = microtime(true)-$send_starttime;if ($handle_business_time > 0.5) {error_log($_SERVER['REQUEST_URI'].'<br>'.$_SERVER['HTTP_X_REQUEST_ID'].'==response->send耗时:' . $handle_business_time);}$terminate_starttime = microtime(true);$kernel->terminate($request, $response);$handle_terminate_time = microtime(true)-$terminate_starttime;if ($handle_terminate_time > 0.5) {error_log($_SERVER['REQUEST_URI'].'<br>'.$_SERVER['HTTP_X_REQUEST_ID'].'==kernel->terminate耗时:' . $handle_terminate_time);}
跟踪结果:
从打印的日志来看,凸显出了两块问题:
1、涌现了redis超时问题,正式环境支配的是哨兵模式
2、涌现了json_decode超时
做事端方面的优化:
1、办理CDN中的gzip问题 1.1:在CDN上调度gzip的策略 1.2:由于腾讯云只能针对详细文件后缀去压缩,程序这边将须要对返回数据包压缩的ajax接口加.pack后缀,变向实现2、调度redis,从哨兵模式换成单机模式3、进行了扩容 3.1:须要支配自动扩容机制
代码方面的优化:
1、由于之前调度了session的存储目录,以是关闭了框架的csrf校验
2、面查询接口返回数据办法调度,将数据包暂存redis,只返回redis的key,PHP再通过key获取数据
关于Content-download优化结语:
在业务代码这块没有什么问题,紧张还是周边的一些问题。比如腾讯云的CDN加速不能像Nginx那样可以根据Content-Type做加速,只能通过详细的文件后缀去做加速,基于这样的背景,我们不得不调度返回数据包比较大的接口路由,在Laravel接口路由后面加上了“.pack”后缀,然后把这个后缀加入到CDN加速里面。
三、结束语
经由针对两次性能问题的优化,终极网站相应很稳定,基本上在1秒之内即可完成加载和渲染。现在的网站培植不再像以前那样普通,架构上是分布式,做事器上用到各种云做事,代码层面上前后端分离开拓,以是要想办理一个网站的性能问题,得各方面结合起来一起剖析排查,这对付办理问题的职员整体本色哀求还是有点的,须要节制前端和后端整体的框架,也须要有足够多的技能根本作为剖析问题的支持。