大家都知道 laravel 项目写起来是挺爽,但是在生产环境性能不高,我们来抽丝剥茧分析我自己项目的运行时间消耗:
Bootstrap 耗时
步骤 | 耗时 |
---|---|
IlluminateFoundationBootstrapLoadEnvironmentVariables |
0.3058910369873 |
IlluminateFoundationBootstrapLoadConfiguration |
3.6571025848389 |
IlluminateFoundationBootstrapHandleExceptions |
0.78296661376953 |
IlluminateFoundationBootstrapRegisterFacades |
9.0579986572266 |
IlluminateFoundationBootstrapRegisterProviders |
101.02701187134 |
IlluminateFoundationBootstrapBootProviders |
96.982002258301 |
观察初步结论: laravel 在调用 IlluminateFoundationBootstrapRegisterProviders
和 IlluminateFoundationBootstrapBootProviders
的 bootstrap
方法时,消耗时间是大头。
- 类
IlluminateFoundationBootstrapRegisterProviders
是用于注册服务提供者的。 - 类
IlluminateFoundationBootstrapBootProviders
是用于启动服务提供者的。 - laravel 的内置server
php artisan serve
自带了优化机制,上面数据仅体现首次加载的耗时。二次加载时会相比少很多。但此优化在 fpm 下无效。
我们进一步分析。
RegisterProviders 耗时
IlluminateFoundationBootstrapRegisterProviders::bootstrap
方法代码如下:
/**
* Bootstrap the given application.
*
* @param IlluminateFoundationApplication $app
* @return void
*/
public function bootstrap(Application $app)
{
$app->registerConfiguredProviders();
}
所以我们还是回到了 IlluminateFoundationApplication
这个文件:
/**
* Register all of the configured providers.
*
* @return void
*/
public function registerConfiguredProviders()
{
$providers = Collection::make($this->config['app.providers'])
->partition(function ($provider) {
return Str::startsWith($provider, 'Illuminate\');
});
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
->load($providers->collapse()->toArray());
}
针对上面的 (new ProviderRepository)->load
进行耗时分析发现数据为
步骤 | 耗时 |
---|---|
IlluminateFoundationProviderRepository::load |
61.771869659424 |
毋庸置疑这就是消耗时间的大头。
里面的代码为
/**
* Register the application service providers.
*
* @param array $providers
* @return void
*/
public function load(array $providers)
{
$manifest = $this->loadManifest();
// First we will load the service manifest, which contains information on all
// service providers registered with the application and which services it
// provides. This is used to know which services are "deferred" loaders.
if ($this->shouldRecompile($manifest, $providers)) {
$manifest = $this->compileManifest($providers);
}
// Next, we will register events to load the providers for each of the events
// that it has requested. This allows the service provider to defer itself
// while still getting automatically loaded when a certain event occurs.
foreach ($manifest['when'] as $provider => $events) {
$this->registerLoadEvents($provider, $events);
}
// We will go ahead and register all of the eagerly loaded providers with the
// application so their services can be registered with the application as
// a provided service. Then we will set the deferred service list on it.
foreach ($manifest['eager'] as $provider) {
$this->app->register($provider);
}
$this->app->addDeferredServices($manifest['deferred']);
}
而再经过定位,发现慢在这一行
foreach ($manifest['eager'] as $provider) {
$this->app->register($provider);
}
又回到 IlluminateFoundationApplication
/**
* Register a service provider with the application.
*
* @param IlluminateSupportServiceProvider|string $provider
* @param array $options
* @param bool $force
* @return IlluminateSupportServiceProvider
*/
public function register($provider, $options = [], $force = false)
{
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
// If the given "provider" is a string, we will resolve it, passing in the
// application instance automatically for the developer. This is simply
// a more convenient way of specifying your service provider classes.
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
if (method_exists($provider, 'register')) {
$provider->register();
}
// If there are bindings / singletons set as properties on the provider we
// will spin through them and register them with the application, which
// serves as a convenience layer while registering a lot of bindings.
if (property_exists($provider, 'bindings')) {
foreach ($provider->bindings as $key => $value) {
$this->bind($key, $value);
}
}
if (property_exists($provider, 'singletons')) {
foreach ($provider->singletons as $key => $value) {
$this->singleton($key, $value);
}
}
$this->markAsRegistered($provider);
// If the application has already booted, we will call this boot method on
// the provider class so it has an opportunity to do its boot logic and
// will be ready for any usage by this developer's application logic.
if ($this->booted) {
$this->bootProvider($provider);
}
return $provider;
}
在 register 方法中,根据 get_class($provider) 和 执行耗时,得出以下数据
步骤 | 耗时 |
---|---|
IlluminateEventsEventServiceProvider |
0.02197265625 |
IlluminateLogLogServiceProvider |
0.005859375 |
IlluminateRoutingRoutingServiceProvider |
0.011962890625 |
IlluminateAuthAuthServiceProvider |
0.024169921875 |
IlluminateCookieCookieServiceProvider |
0.0048828125 |
IlluminateDatabaseDatabaseServiceProvider |
9.678955078125 |
IlluminateEncryptionEncryptionServiceProvider |
0.00732421875 |
IlluminateFilesystemFilesystemServiceProvider |
0.014892578125 |
IlluminateFoundationProvidersFormRequestServiceProvider |
0.0009765625 |
IlluminateFoundationProvidersFoundationServiceProvider |
0.416015625 |
IlluminateNotificationsNotificationServiceProvider |
0.011962890625 |
IlluminatePaginationPaginationServiceProvider |
5.04296875 |
IlluminateSessionSessionServiceProvider |
0.072021484375 |
IlluminateViewViewServiceProvider |
0.01318359375 |
CogLaravelLoveProvidersLoveServiceProvider |
0.01708984375 |
DingoApiProviderRoutingServiceProvider |
0.0146484375 |
DingoApiProviderHttpServiceProvider |
0.03271484375 |
DingoApiProviderLaravelServiceProvider |
20.23583984375 |
FideloperProxyTrustedProxyServiceProvider |
0.001953125 |
InfyOmAdminLTETemplatesAdminLTETemplatesServiceProvider |
0.001953125 |
InfyOmGeneratorInfyOmGeneratorServiceProvider |
0.045166015625 |
JeroenNotenLaravelAdminLteServiceProvider |
0.013671875 |
LaracastsFlashFlashServiceProvider |
0.013916015625 |
LaravelfyValidatorServiceProvider |
0.001953125 |
LshorzLuocaptchaLCaptchaServiceProvider |
0.01171875 |
MaatwebsiteExcelExcelServiceProvider |
6.778076171875 |
OvertrueLaravelWeChatServiceProvider |
9.040771484375 |
PrettusRepositoryProvidersEventServiceProvider |
0.00390625 |
PrettusRepositoryProvidersRepositoryServiceProvider |
1.244140625 |
SpatiePermissionPermissionServiceProvider |
0.3759765625 |
TymonJWTAuthProvidersLaravelServiceProvider |
0.03515625 |
CollectiveHtmlHtmlServiceProvider |
0.025146484375 |
YajraDataTablesHtmlServiceProvider |
2.22314453125 |
YajraDataTablesButtonsServiceProvider |
4.593017578125 |
YajraDataTablesDataTablesServiceProvider |
0.333984375 |
AppProvidersAppServiceProvider |
0.001953125 |
AppProvidersAuthServiceProvider |
0.001953125 |
AppProvidersEventServiceProvider |
0.001953125 |
AppProvidersRouteServiceProvider |
0.001708984375 |
AppProvidersResponseMacroServicePrivoder |
37.69677734375 |
OvertrueLaravelLangTranslationServiceProvider |
0.01220703125 |
IlluminateValidationValidationServiceProvider |
0.029052734375 |
IlluminateCacheCacheServiceProvider |
0.01318359375 |
IlluminateHashingHashServiceProvider |
0.031005859375 |
得出 RegisterProviders 瓶颈的结论
-
AppProvidersResponseMacroServicePrivoder
占用 37ms -
DingoApiProviderLaravelServiceProvider
占用 20ms -
IlluminateDatabaseDatabaseServiceProvider
占用 9ms -
OvertrueLaravelWeChatServiceProvider
占用 9ms
BootProviders 耗时
服务提供者 | 启动时间 | 请求时 |
---|---|---|
IlluminateDatabaseDatabaseServiceProvider::boot |
0.851074875 | 3.6809083125 |
IlluminateFoundationProvidersFormRequestServiceProvider::boot |
0.022949875 | 0.0290524375 |
IlluminateNotificationsNotificationServiceProvider::boot |
2.113769125 | 9.91894525 |
IlluminatePaginationPaginationServiceProvider::boot |
0.062988125 | 0.089843 |
EasyWeChatComposerLaravelServiceProvider::boot |
6.5910643125 | 22.644042875 |
CogLaravelLoveProvidersLoveServiceProvider::boot |
0.6311035625 | 2.3010250625 |
DingoApiProviderLaravelServiceProvider::boot |
9.228027375 | 53.9980465 |
FideloperProxyTrustedProxyServiceProvider::boot |
0.1589356875 | 0.6091309375 |
InfyOmAdminLTETemplatesAdminLTETemplatesServiceProvider::boot |
0.033691625 | 0.0410155 |
PrettusRepositoryProvidersEventServiceProvider::boot |
0.020996375 | 0.0432120625 |
PrettusRepositoryProvidersRepositoryServiceProvider::boot |
1.7600095625 | 8.361816625 |
LaracastsFlashFlashServiceProvider::boot |
0.191894125 | 0.066894125 |
InfyOmGeneratorInfyOmGeneratorServiceProvider::boot |
0.0832513125 | 0.019042875 |
JeroenNotenLaravelAdminLteServiceProvider::boot |
3.2441405 | 17.807128625 |
LaravelfyValidatorServiceProvider::boot |
2.940917875 | 10.8391118125 |
LshorzLuocaptchaLCaptchaServiceProvider::boot |
0.0832513125 | 0.075683375 |
OvertrueLaravelWeChatServiceProvider::boot |
0.074707125 | 0.0139165625 |
SpatiePermissionPermissionServiceProvider::boot |
9.5026856875 | 15.3239749375 |
TymonJWTAuthProvidersLaravelServiceProvider::boot |
1.070800125 | 11.508300125 |
YajraDataTablesDataTablesServiceProvider::boot |
0.2839356875 | 1.0837404375 |
YajraDataTablesHtmlServiceProvider::boot |
0.0827631875 | 0.0651856875 |
MaatwebsiteExcelExcelServiceProvider::boot |
0.0461428125 | 0.0097655 |
YajraDataTablesButtonsServiceProvider::boot |
0.0529785625 | 0.046875 |
AppProvidersAppServiceProvider::boot |
0.1179191875 | 0.0979000625 |
AppProvidersAuthServiceProvider::boot |
0.1901856875 | 0.437988125 |
AppProvidersEventServiceProvider::boot |
0.196777375 | 0.8210441875 |
AppProvidersRouteServiceProvider::boot |
4.6032714375 | 12.817871375 |
AppProvidersResponseMacroServicePrivoder::boot |
5.6691893125 | 16.917968 |
LaravelTinkerTinkerServiceProvider::boot |
0.3859868125 | null |
BarryvdhLaravelIdeHelperIdeHelperServiceProvider::boot |
0.1750488125 | null |
原因分析
-
EasyWeChatComposerLaravelServiceProvider::boot
的启动速度,略慢,分析原因: 代码 Github boot 方法中,加载了路由。而 Laravel 的路由,确实是比较慢的。
[未完]