使用 Laravel 在 Azure 中来自单个请求的多个重复 HTTP 请求/查询

Posted

技术标签:

【中文标题】使用 Laravel 在 Azure 中来自单个请求的多个重复 HTTP 请求/查询【英文标题】:Multiple duplicate HTTP requests/queries from single requests in Azure with Laravel 【发布时间】:2019-05-06 10:11:20 【问题描述】:

我在 Azure 上提供了一个 Laravel 应用程序。我正在使用 AJAX 请求来轮询 javascript 图表的数据。

AJAX 请求在我的路由 (web.php) 中定义的 URL,因此:

Route::get('/rfp_chart_data', 'DataController@chart_data')->name('chart_data');

该控制器方法运行一个 postgresql 查询并返回一个 JSON 文件。这一切都很好。

但是,在遇到一些性能问题后,我决定监控 postgres 查询,发现对于此 URL 的每个请求,相同的查询运行了 3 次。

无论我是否:

通过 AJAX 请求访问 URL

在浏览器中直接访问网址

通过 cURL 访问 URL

这(AFAIK)消除了这是某种缺少 img src 问题的可能性(例如What can cause a double page request?)

非常感谢您的帮助...

编辑:

postgres pg_stat_activity 中重复查询的图像 -- 这是来自 1 个网络请求:

编辑:

完整的控制器代码:

<?php

namespace App\Http\Controllers;

use App\AllRfpEntry;
use DB;
use Illuminate\Http\Request;
use Yajra\Datatables\Facades\Datatables;

class DataController extends Controller 
    /**
     * Displays datatables front end view
     *
     * @return \Illuminate\View\View
     */

    //|| result_url || '\">' || result_title || '</a>'

    public function chart_data(Request $request) 

        $binding_array = array();

        $chart_data_sql = "SELECT relevant_dates.date::date,
            CASE WHEN award_totals.sum IS NULL
            THEN 0
            ELSE award_totals.sum
            END
            as sum

            ,


            CASE WHEN award_totals.transaction_count IS NULL
            THEN 0
            ELSE award_totals.transaction_count
            END
            as transaction_count FROM

            (
            SELECT * FROM generate_series('" . date('Y-m-01', strtotime('-15 month')) . "'::date, '" . date('Y-m-01') . "'::date, '1 month') AS date
            )  relevant_dates

            LEFT JOIN

            (
            SELECT extract(year from awarded_date)::text || '-' || RIGHT('0' || extract(month from awarded_date)::text, 2) || '-01'  as date, sum(award_amount)::numeric as sum, COUNT(award_amount) as transaction_count FROM all_rfp_entries

            WHERE awarded_date >= '" . date('Y-m-01', strtotime('-15 month')) . "'

            AND awarded_date <= '" . date("Y-m-d") . "' AND award_status = 'AWARDED'
            AND award_amount::numeric < 10000000000";

        if ($request->get('rfp_company_filter')) 

            $binding_array['rfp_company_filter'] = $request->get('rfp_company_filter');

            $chart_data_sql .= " AND company = :rfp_company_filter";

        ;

        if ($request->get('rfp_source_filter')) 

            $binding_array['rfp_source_filter'] = $request->get('rfp_source_filter');

            $chart_data_sql .= " AND rfp_source = :rfp_source_filter";

        

        if ($request->get('exclude_fed_rev')) 

            $chart_data_sql .= " AND rfp_source != 'US FED REV' ";

        

        if ($request->get('rfp_year_filter')) 

            $binding_array['rfp_year_filter'] = $request->get('rfp_year_filter');

            $chart_data_sql .= " AND year = :rfp_year_filter";

        

        if ($request->get('rfp_priority_level_filter')) 

            $binding_array['rfp_priority_level_filter'] = $request->get('rfp_priority_level_filter');

            $chart_data_sql .= " AND priority_level = :rfp_priority_level_filter";

        

        if ($request->get('rfp_search_input_chart')) 

            $binding_array['rfp_search_input_chart'] = $request->get('rfp_search_input_chart');

            $chart_data_sql .= " AND search_document::tsvector @@ plainto_tsquery('simple', :rfp_search_input_chart)";

        

        $chart_data_sql .= " GROUP BY extract(year from awarded_date), extract(month from awarded_date)
        ) award_totals
        on award_totals.date::date = relevant_dates.date::date

        ORDER BY extract(year from relevant_dates.date::date), extract(month from relevant_dates.date::date)
        ";

        return json_encode(DB::select($chart_data_sql, $binding_array));


    

    public function data(Request $request) 

        $query = AllRfpEntry::select('id', 'year', 'company', 'result_title', 'award_amount', 'edit_column', 'doc_type', 'rfp_source', 'posted_date', 'awarded_date', 'award_status', 'priority_level', 'word_score', 'summary', 'contract_age', 'search_document', 'link');

        if ($request->get('exclude_na')) 

            $query->where('all_rfp_entries.company', '!=', 'NA');

        

        if ($request->get('clicked_date')) 

            $query->where('all_rfp_entries.awarded_date', '>', $request->get('clicked_date'));

            $query->where('all_rfp_entries.awarded_date', '<=', $request->get('clicked_date_plus_one_month'));

        

        if ($request->get('filter_input')) 

            $query->whereRaw("search_document::tsvector @@ plainto_tsquery('simple', '" . $request->get('filter_input') . "')");

        

        $datatables_json = datatables()->of($query)

            ->rawColumns(['result_title', 'edit_column', 'link'])

            ->orderColumn('award_amount', 'award_amount $1 NULLS LAST')
            ->orderColumn('priority_level', 'priority_level $1 NULLS LAST');

        if (!$request->get('filter_input')) 

            $datatables_json = $datatables_json->orderByNullsLast();

        

        if (!$request->get('filter_input') and !$request->get('clicked_date')) 

            $count_table = 'all_rfp_entries';

            $count = DB::select(DB::raw("SELECT n_live_tup FROM pg_stat_all_tables WHERE relname = :count_table "), array('count_table' => $count_table))[0]->n_live_tup;

            $datatables_json = $datatables_json->setTotalRecords($count);

        

            $datatables_json = $datatables_json->make(true);

        return $datatables_json;

    



编辑:

更疯狂的皱纹......

我在这台服务器上的 Laravel 中有一个方法指向另一台服务器上的 postgres 数据库来摄取新数据。我刚刚发现,即使那个方法(指向外部服务器的方法)也在外部 postgres 服务器上生成多个查询!

除非我遗漏了什么,否则这可以避免 nginx 问题或我的提供程序 (Azure) 的问题,或任何一种特定方法的问题。即使是通过端口 5432 的直接数据库连接(我假设这就是 Laravel 访问外部数据库的方式)也会产生乘数效应,所以它一定是我的 Laravel 安装有问题......但没有更接近弄清楚是什么。

【问题讨论】:

您如何监控您的查询?您是在查看服务器日志还是通过应用程序中的一些调试器执行此操作? 我正在实时观看它们:SELECT pg_stat_activity.pid, now() - pg_stat_activity.query_start AS 持续时间, pg_stat_activity.query, pg_stat_activity.state FROM pg_stat_activity;; 我错了——我的本地 vagrant 系统也出现了这个问题。查询发生得太快,无法实时查看。所以这似乎不是 Azure 问题。 我认为这与datatables() 方法调用有关。如果您查看您发布的查询,它是最有可能用于分页的聚合计数(它需要知道有多少东西才能说出有多少页,对吧?)不知道该方法是什么/确实,我不能更具体。但我相信您的问题在于该实施。 你的路由指向DataController@chart_data,但是控制器没有那个方法 【参考方案1】:

调试此问题的最佳方法是使用 xdebug 启动调试会话并单步执行代码,同时在单独的窗口中关注 stdout/logging 输出。

在控制器的第一行设置一个断点,当它中断时应该完成 0 个查询。如果不是,您知道路由/请求中发生了一些奇怪的事情。然后逐步执行用于构建查询的函数调用。

可能是您使用触发器执行查询的功能之一(如 Aaron Saray 所建议)或缺少方法(如 Diogo Gomes 所建议),但如果不知道代码或逐步执行,这很难说上下文一步一步。

如果您没有调试器,您可以随时在任何行使用dd($data); 来停止处理并转储给定的数据。这将需要更长的时间,因为您将为代码中的每个步骤执行一个新请求。

【讨论】:

【参考方案2】:

对于它的价值,我将其追踪到多个 postgres 工作进程(您可以在 postgres .conf 文件中设置)。所以,不是错误,也不是 Laravel 的问题——只是 postgres 产生的并行工作者。

【讨论】:

以上是关于使用 Laravel 在 Azure 中来自单个请求的多个重复 HTTP 请求/查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 Vuejs 填充特定输入 - 来自数据库的 Laravel

如何使用单个事件中心名称空间处理多个数据源

来自单个控制器的多个模型[关闭]

使用 Redis 存储数据数组(来自 Laravel)

如何在 laravel 中使用 get 在单页路由中使用来自同一控制器的两个功能

来自同一浏览器的 laravel 和多会话