<p>你們都知道 laravel 項目寫起來是挺爽,可是在生產環境性能不高,咱們來抽絲剝繭分析我本身項目的運行時間消耗:</p> <h2>Bootstrap 耗時</h2> <table> <thead><tr> <th>步驟</th> <th>耗時</th> </tr></thead> <tbody> <tr> <td><code>Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables</code></td> <td>0.3058910369873</td> </tr> <tr> <td><code>Illuminate\Foundation\Bootstrap\LoadConfiguration</code></td> <td>3.6571025848389</td> </tr> <tr> <td><code>Illuminate\Foundation\Bootstrap\HandleExceptions</code></td> <td>0.78296661376953</td> </tr> <tr> <td><code>Illuminate\Foundation\Bootstrap\RegisterFacades</code></td> <td>9.0579986572266</td> </tr> <tr> <td><code>Illuminate\Foundation\Bootstrap\RegisterProviders</code></td> <td>101.02701187134</td> </tr> <tr> <td><code>Illuminate\Foundation\Bootstrap\BootProviders</code></td> <td>96.982002258301</td> </tr> </tbody> </table> <p>觀察初步結論: laravel 在調用 <code>Illuminate\Foundation\Bootstrap\RegisterProviders</code> 和 <code>Illuminate\Foundation\Bootstrap\BootProviders</code> 的 <code>bootstrap</code> 方法時,消耗時間是大頭。</p> <ul> <li>類 <code>Illuminate\Foundation\Bootstrap\RegisterProviders</code> 是用於註冊服務提供者的。</li> <li>類 <code>Illuminate\Foundation\Bootstrap\BootProviders</code> 是用於啓動服務提供者的。</li> <li>laravel 的內置server <code>php artisan serve</code> 自帶了優化機制,上面數據僅體現首次加載的耗時。二次加載時會相比少不少。但此優化在 fpm 下無效。</li> </ul> <p>咱們進一步分析。</p> <hr> <h3>RegisterProviders 耗時</h3> <p><code>\Illuminate\Foundation\Bootstrap\RegisterProviders::bootstrap</code> 方法代碼以下:</p>php
/** * Bootstrap the given application. * * @param \Illuminate\Foundation\Application $app * @return void */ public function bootstrap(Application $app) { $app->registerConfiguredProviders(); }
<p>因此咱們仍是回到了 <code>\Illuminate\Foundation\Application</code> 這個文件:</p>laravel
/** * 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()); }
<p>針對上面的 <code>(new ProviderRepository)->load</code> 進行耗時分析發現數據爲</p> <table> <thead><tr> <th>步驟</th> <th>耗時</th> </tr></thead> <tbody><tr> <td><code>Illuminate\Foundation\ProviderRepository::load</code></td> <td>61.771869659424</td> </tr></tbody> </table> <p>毋庸置疑這就是消耗時間的大頭。 </p> <p>裏面的代碼爲</p>git
/** * 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']); }
<p>而再通過定位,發現慢在這一行</p>github
foreach ($manifest['eager'] as $provider) { $this->app->register($provider); }
<p>又回到 <code>\Illuminate\Foundation\Application</code></p>web
/** * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ 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; }
<p>在 register 方法中,根據 get_class($provider) 和 執行耗時,得出如下數據</p> <table> <thead><tr> <th>步驟</th> <th>耗時</th> </tr></thead> <tbody> <tr> <td><code>Illuminate\Events\EventServiceProvider</code></td> <td>0.02197265625</td> </tr> <tr> <td><code>Illuminate\Log\LogServiceProvider</code></td> <td>0.005859375</td> </tr> <tr> <td><code>Illuminate\Routing\RoutingServiceProvider</code></td> <td>0.011962890625</td> </tr> <tr> <td><code>Illuminate\Auth\AuthServiceProvider</code></td> <td>0.024169921875</td> </tr> <tr> <td><code>Illuminate\Cookie\CookieServiceProvider</code></td> <td>0.0048828125</td> </tr> <tr> <td><code>Illuminate\Database\DatabaseServiceProvider</code></td> <td>9.678955078125</td> </tr> <tr> <td><code>Illuminate\Encryption\EncryptionServiceProvider</code></td> <td>0.00732421875</td> </tr> <tr> <td><code>Illuminate\Filesystem\FilesystemServiceProvider</code></td> <td>0.014892578125</td> </tr> <tr> <td><code>Illuminate\Foundation\Providers\FormRequestServiceProvider</code></td> <td>0.0009765625</td> </tr> <tr> <td><code>Illuminate\Foundation\Providers\FoundationServiceProvider</code></td> <td>0.416015625</td> </tr> <tr> <td><code>Illuminate\Notifications\NotificationServiceProvider</code></td> <td>0.011962890625</td> </tr> <tr> <td><code>Illuminate\Pagination\PaginationServiceProvider</code></td> <td>5.04296875</td> </tr> <tr> <td><code>Illuminate\Session\SessionServiceProvider</code></td> <td>0.072021484375</td> </tr> <tr> <td><code>Illuminate\View\ViewServiceProvider</code></td> <td>0.01318359375</td> </tr> <tr> <td><code>Cog\Laravel\Love\Providers\LoveServiceProvider</code></td> <td>0.01708984375</td> </tr> <tr> <td><code>Dingo\Api\Provider\RoutingServiceProvider</code></td> <td>0.0146484375</td> </tr> <tr> <td><code>Dingo\Api\Provider\HttpServiceProvider</code></td> <td>0.03271484375</td> </tr> <tr> <td><code>Dingo\Api\Provider\LaravelServiceProvider</code></td> <td>20.23583984375</td> </tr> <tr> <td><code>Fideloper\Proxy\TrustedProxyServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>InfyOm\AdminLTETemplates\AdminLTETemplatesServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>InfyOm\Generator\InfyOmGeneratorServiceProvider</code></td> <td>0.045166015625</td> </tr> <tr> <td><code>JeroenNoten\LaravelAdminLte\ServiceProvider</code></td> <td>0.013671875</td> </tr> <tr> <td><code>Laracasts\Flash\FlashServiceProvider</code></td> <td>0.013916015625</td> </tr> <tr> <td><code>Laravelfy\Validator\ServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>Lshorz\Luocaptcha\LCaptchaServiceProvider</code></td> <td>0.01171875</td> </tr> <tr> <td><code>Maatwebsite\Excel\ExcelServiceProvider</code></td> <td>6.778076171875</td> </tr> <tr> <td><code>Overtrue\LaravelWeChat\ServiceProvider</code></td> <td>9.040771484375</td> </tr> <tr> <td><code>Prettus\Repository\Providers\EventServiceProvider</code></td> <td>0.00390625</td> </tr> <tr> <td><code>Prettus\Repository\Providers\RepositoryServiceProvider</code></td> <td>1.244140625</td> </tr> <tr> <td><code>Spatie\Permission\PermissionServiceProvider</code></td> <td>0.3759765625</td> </tr> <tr> <td><code>Tymon\JWTAuth\Providers\LaravelServiceProvider</code></td> <td>0.03515625</td> </tr> <tr> <td><code>Collective\Html\HtmlServiceProvider</code></td> <td>0.025146484375</td> </tr> <tr> <td><code>Yajra\DataTables\HtmlServiceProvider</code></td> <td>2.22314453125</td> </tr> <tr> <td><code>Yajra\DataTables\ButtonsServiceProvider</code></td> <td>4.593017578125</td> </tr> <tr> <td><code>Yajra\DataTables\DataTablesServiceProvider</code></td> <td>0.333984375</td> </tr> <tr> <td><code>App\Providers\AppServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>App\Providers\AuthServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>App\Providers\EventServiceProvider</code></td> <td>0.001953125</td> </tr> <tr> <td><code>App\Providers\RouteServiceProvider</code></td> <td>0.001708984375</td> </tr> <tr> <td><code>App\Providers\ResponseMacroServicePrivoder</code></td> <td>37.69677734375</td> </tr> <tr> <td><code>Overtrue\LaravelLang\TranslationServiceProvider</code></td> <td>0.01220703125</td> </tr> <tr> <td><code>Illuminate\Validation\ValidationServiceProvider</code></td> <td>0.029052734375</td> </tr> <tr> <td><code>Illuminate\Cache\CacheServiceProvider</code></td> <td>0.01318359375</td> </tr> <tr> <td><code>Illuminate\Hashing\HashServiceProvider</code></td> <td>0.031005859375</td> </tr> </tbody> </table> <p>得出 RegisterProviders 瓶頸的結論</p> <ul> <li> <code>App\Providers\ResponseMacroServicePrivoder</code> 佔用 37ms</li> <li> <code>Dingo\Api\Provider\LaravelServiceProvider</code> 佔用 20ms</li> <li> <code>Illuminate\Database\DatabaseServiceProvider</code> 佔用 9ms</li> <li> <code>Overtrue\LaravelWeChat\ServiceProvider</code> 佔用 9ms</li> </ul> <hr> <h3>BootProviders 耗時</h3> <table> <thead><tr> <th>服務提供者</th> <th>啓動時間</th> <th>請求時</th> </tr></thead> <tbody> <tr> <td><code>Illuminate\Database\DatabaseServiceProvider::boot</code></td> <td>0.851074875</td> <td>3.6809083125</td> </tr> <tr> <td><code>Illuminate\Foundation\Providers\FormRequestServiceProvider::boot</code></td> <td>0.022949875</td> <td>0.0290524375</td> </tr> <tr> <td><code>Illuminate\Notifications\NotificationServiceProvider::boot</code></td> <td>2.113769125</td> <td>9.91894525</td> </tr> <tr> <td><code>Illuminate\Pagination\PaginationServiceProvider::boot</code></td> <td>0.062988125</td> <td>0.089843</td> </tr> <tr> <td><a href="https://github.com/mingyoung/easywechat-composer/blob/e0a24198ab5f8c58c867d25978c86624730a5cf6/src/Laravel/ServiceProvider.php#L26" rel="nofollow noreferrer"><code>EasyWeChatComposer\Laravel\ServiceProvider::boot</code></a></td> <td>6.5910643125</td> <td>22.644042875</td> </tr> <tr> <td><code>Cog\Laravel\Love\Providers\LoveServiceProvider::boot</code></td> <td>0.6311035625</td> <td>2.3010250625</td> </tr> <tr> <td><code>Dingo\Api\Provider\LaravelServiceProvider::boot</code></td> <td>9.228027375</td> <td>53.9980465</td> </tr> <tr> <td><code>Fideloper\Proxy\TrustedProxyServiceProvider::boot</code></td> <td>0.1589356875</td> <td>0.6091309375</td> </tr> <tr> <td><code>InfyOm\AdminLTETemplates\AdminLTETemplatesServiceProvider::boot</code></td> <td>0.033691625</td> <td>0.0410155</td> </tr> <tr> <td><code>Prettus\Repository\Providers\EventServiceProvider::boot</code></td> <td>0.020996375</td> <td>0.0432120625</td> </tr> <tr> <td><code>Prettus\Repository\Providers\RepositoryServiceProvider::boot</code></td> <td>1.7600095625</td> <td>8.361816625</td> </tr> <tr> <td><code>Laracasts\Flash\FlashServiceProvider::boot</code></td> <td>0.191894125</td> <td>0.066894125</td> </tr> <tr> <td><code>InfyOm\Generator\InfyOmGeneratorServiceProvider::boot</code></td> <td>0.0832513125</td> <td>0.019042875</td> </tr> <tr> <td><code>JeroenNoten\LaravelAdminLte\ServiceProvider::boot</code></td> <td>3.2441405</td> <td>17.807128625</td> </tr> <tr> <td><code>Laravelfy\Validator\ServiceProvider::boot</code></td> <td>2.940917875</td> <td>10.8391118125</td> </tr> <tr> <td><code>Lshorz\Luocaptcha\LCaptchaServiceProvider::boot</code></td> <td>0.0832513125</td> <td>0.075683375</td> </tr> <tr> <td><code>Overtrue\LaravelWeChat\ServiceProvider::boot</code></td> <td>0.074707125</td> <td>0.0139165625</td> </tr> <tr> <td><code>Spatie\Permission\PermissionServiceProvider::boot</code></td> <td>9.5026856875</td> <td>15.3239749375</td> </tr> <tr> <td><code>Tymon\JWTAuth\Providers\LaravelServiceProvider::boot</code></td> <td>1.070800125</td> <td>11.508300125</td> </tr> <tr> <td><code>Yajra\DataTables\DataTablesServiceProvider::boot</code></td> <td>0.2839356875</td> <td>1.0837404375</td> </tr> <tr> <td><code>Yajra\DataTables\HtmlServiceProvider::boot</code></td> <td>0.0827631875</td> <td>0.0651856875</td> </tr> <tr> <td><code>Maatwebsite\Excel\ExcelServiceProvider::boot</code></td> <td>0.0461428125</td> <td>0.0097655</td> </tr> <tr> <td><code>Yajra\DataTables\ButtonsServiceProvider::boot</code></td> <td>0.0529785625</td> <td>0.046875</td> </tr> <tr> <td><code>App\Providers\AppServiceProvider::boot</code></td> <td>0.1179191875</td> <td>0.0979000625</td> </tr> <tr> <td><code>App\Providers\AuthServiceProvider::boot</code></td> <td>0.1901856875</td> <td>0.437988125</td> </tr> <tr> <td><code>App\Providers\EventServiceProvider::boot</code></td> <td>0.196777375</td> <td>0.8210441875</td> </tr> <tr> <td><code>App\Providers\RouteServiceProvider::boot</code></td> <td>4.6032714375</td> <td>12.817871375</td> </tr> <tr> <td><code>App\Providers\ResponseMacroServicePrivoder::boot</code></td> <td>5.6691893125</td> <td>16.917968</td> </tr> <tr> <td><code>Laravel\Tinker\TinkerServiceProvider::boot</code></td> <td>0.3859868125</td> <td>null</td> </tr> <tr> <td><code>Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::boot</code></td> <td>0.1750488125</td> <td>null</td> </tr> </tbody> </table> <h4>緣由分析</h4> <ul><li> <code>EasyWeChatComposer\Laravel\ServiceProvider::boot</code> 的啓動速度,略慢,分析緣由: 代碼 <a href="https://github.com/mingyoung/easywechat-composer/blob/e0a24198ab5f8c58c867d25978c86624730a5cf6/src/Laravel/ServiceProvider.php#L26" rel="nofollow noreferrer">Github</a> boot 方法中,加載了路由。而 Laravel 的路由,確實是比較慢的。</li></ul> <p>[未完]</p>bootstrap
原文地址:https://segmentfault.com/a/1190000016411386segmentfault