За последние 24 часа нас посетили 22480 программистов и 1199 роботов. Сейчас ищут 672 программиста ...

Как снизить нагрузку на сайт, при большом количестве запросов к стороннему api?

Тема в разделе "PHP для новичков", создана пользователем Arcadiy, 26 июл 2021.

Метки:
  1. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    На сайт ложится слишком большая нагрузка, так как на странице около 20 запросов API. Поэтому думаю нужно переходить на многопоточность. Инструкцию изучил, но так и не разобрался. Суть в следующем. При получении ответа от api создаются файлы с кэшированными данными, откуда затем берется информация для вывода. Структура запросов такая. С каждым новым обращением к Api нагрузка на сайт сильно увеличивается.
    Так выглядит структура вызова Api.
    №1
    PHP:
    1. <?php
    2. $cache_ttl = 21600; // время жизни кэша в секундах
    3. $cache_file_airlines = "tmp/ish.data";
    4. $cache_file_products = "tmp/ish1.data";
    5. $map = function ($array, $from, $to)
    6. {
    7.     $result = [];
    8.     if (!empty($array) && is_array($array))
    9.     {
    10.         foreach ($array as $element)
    11.         {
    12.             $key = $element[$from] ? : null;
    13.             $value = $element[$to] ? : null;
    14.             if ($key && $value)
    15.             {
    16.                 $result[$key] = $value;
    17.             }
    18.         }
    19.     }
    20.     return $result;
    21. };
    22. if (file_exists($cache_file_airlines) && (time() - filemtime($cache_file_airlines)) < $cache_ttl)
    23. {
    24.     // берём кэшированные данные
    25.     $get_airlines = file_get_contents($cache_file_airlines);
    26. }
    27. else
    28. {
    29.     $get_airlines = file_get_contents('https://site.ru/json/airlines.json');
    30.     file_put_contents($cache_file_airlines, $get_airlines);
    31. }
    32. $airlines = array_column($dataAER, 'name', 'iata');
    33.  
    34. if (file_exists($cache_file_products) && (time() - filemtime($cache_file_products)) < $cache_ttl)
    35. {
    36.     // берём кэшированные данные
    37.     $response = file_get_contents($cache_file_products);
    38. }
    39. else
    40. {
    41.     $ch = curl_init();
    42.     curl_setopt($ch, CURLOPT_URL, "https://site.ru/v3/prices_for_dates?origin=MOW&destination=AER&token=*******&departure_at=" . date('Y-m-d'));
    43.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    44.     curl_setopt($ch, CURLOPT_HEADER, false);
    45.     curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    46.         "X-Access-Token: **********"
    47.     ));
    48.     $response = curl_exec($ch);
    49.     curl_close($ch);
    50.  
    51.     file_put_contents($cache_file_products, $response);
    52. }
    53. $products = json_decode($response, true);
    54. $replace_value = function ($key, $val) use ($airlines)
    55. {
    56.     $response = $val;
    57.     switch ($key)
    58.     {
    59.         case 'airline':
    60.             $response = $airlines[$val];
    61.         break;
    62.     }
    63.     return $response;
    64. } ?>
    65.     <div class="table-responsive" style="overflow-x:hidden;background: var(--responsiv-color)!important; display: flex; flex-direction: column; width: 100%;margin-left: auto; margin-right: auto; list-style-type: none;overflow-y:hidden;">
    66.     <?php
    67. if (isset($products['data']) && is_array($products['data']))
    68. {
    69.     foreach ($products['data'] as $key => $dataAER)
    70. ?>
    Далее следует вывод данных из этого API. Затем еще один вызов API.

    №2
    PHP:
    1. <?php
    2. $cache_ttl = 21600; // время жизни кэша в секундах
    3. $cache_file_airlines = "tmp/ish2.data";
    4. $cache_file_products = "tmp/ish3.data";
    5. $map = function ($array, $from, $to)
    6. {
    7.     $result = [];
    8.     if (!empty($array) && is_array($array))
    9.     {
    10.         foreach ($array as $element)
    11.         {
    12.             $key = $element[$from] ? : null;
    13.             $value = $element[$to] ? : null;
    14.             if ($key && $value)
    15.             {
    16.                 $result[$key] = $value;
    17.             }
    18.         }
    19.     }
    20.     return $result;
    21. };
    22. if (file_exists($cache_file_airlines) && (time() - filemtime($cache_file_airlines)) < $cache_ttl)
    23. {
    24.     // берём кэшированные данные
    25.     $get_airlines = file_get_contents($cache_file_airlines);
    26. }
    27. else
    28. {
    29.     $get_airlines = file_get_contents('https://site.ru/json/airlines.json');
    30.     file_put_contents($cache_file_airlines, $get_airlines);
    31. }
    32. $airlines = array_column($dataSIP, 'name', 'iata');
    33.  
    34. if (file_exists($cache_file_products) && (time() - filemtime($cache_file_products)) < $cache_ttl)
    35. {
    36.     // берём кэшированные данные
    37.     $response = file_get_contents($cache_file_products);
    38. }
    39. else
    40. {
    41.     $ch = curl_init();
    42.     curl_setopt($ch, CURLOPT_URL, "https://site.ru/v3/prices_for_dates?origin=MOW&destination=SIP&token=******&departure_at=" . date('Y-m-d'));
    43.     curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    44.     curl_setopt($ch, CURLOPT_HEADER, false);
    45.     curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    46.         "X-Access-Token: ******"
    47.     ));
    48.     $response = curl_exec($ch);
    49.     curl_close($ch);
    50.  
    51.     file_put_contents($cache_file_products, $response);
    52. }
    53. $products = json_decode($response, true);
    54. $replace_value = function ($key, $val) use ($airlines)
    55. {
    56.     $response = $val;
    57.     switch ($key)
    58.     {
    59.         case 'airline':
    60.             $response = $airlines[$val];
    61.         break;
    62.     }
    63.     return $response;
    64. } ?>
    65.      <div class="table-responsive" style="overflow-x:hidden;background: var(--responsiv-color)!important; display: flex; flex-direction: column; width: 100%;margin-left: auto; margin-right: auto; list-style-type: none;overflow-y:hidden;">
    66.     <?php
    67. if (isset($products['data']) && is_array($products['data']))
    68. {
    69.     foreach ($products['data'] as $key => $dataSIP)
    70. ?>
    Далее следует вывод данных из этого API. Разница между этими вызовами в файлах с кэшированными данными и этими переменными
    Код (Text):
    1. $dataSIP и $ dataAER.
    На одной странице 21 такой запрос.
    Как можно объединить эти запросы в один или облегчить нагрузку?
    Это снизит нагрузку на сервер?
    Как еще можно снизить нагрузку?
    --- Добавлено ---
    После десятого запроса, сайт стал значительно долго загружаться.
     
  2. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
  3. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Сам сайт (аBиа-аBиа.ру) (большую букву заменить на русскую)
    Сайт на голом php+html
    Под каждый город идет отдельный запрос, затем идет вывод информации и так 21 раз, каждые 5 минут выполняется Cron задача по удалению кэшированных данных из папки tmp/ , затем когда любой посетитель заходит на сайт, происходит обновление кэшированных данных (это уже в php коде происходит), это нужно чтобы цены были актуальны всегда, когда кэшированные данные записываются заново в этот момент идет долгая загрузка сайта.
    --- Добавлено ---
    Для наглядности сейчас сделал удаление по крону данных 1 минута.
     
    #3 Arcadiy, 26 июл 2021
    Последнее редактирование: 26 июл 2021
  4. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    видимо вот в этом проблема ))) тебе точно нужно на одной странице иметь инфу про 21 город? предположу, что требуется только конкретный один.
     
  5. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Да, нужен. Главная это одностраничник, с собранной информацией. 21 запрос на главной.
     
    #5 Arcadiy, 26 июл 2021
    Последнее редактирование: 26 июл 2021
  6. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Заранее спасибо всем!
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Ну ты сам себя загнал в угол. Сформулировал задачу так, чтобы оправдать неизбежность зла. Попробуй другой подход, который не будет требовать жертв.
    --- Добавлено ---
    Надо сделать потребности скромнее.
    --- Добавлено ---
    Я думаю что сервер-источник может иметь квоты по загрузке с одного адреса. Не стоит расчитывать на параллельные запросы. Лучше распредели их по времени.

    Допустим, ты решаешь что тебя устроит возраст кешированных данных в 10 минут. Пусть тогда 21 запрос будет распределен в расписании чтобы в целом успеть обойти всё что надо за 10 минут. Нутыпонел: по два уникальных запроса в минуту примерно. Тогда веб страничка будет иметь данные всегда готовыми без ожидания -- брать только из кеша, без фолбека к реальному запросу s2s.
     
  8. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    То-бишь сделать задачи по крону удалять не все файлы сразу, а сделать на каждый файл отдельное время удаления, путем подбора, определить лучший временной период?
     
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Нет. Я предложил вообще не инвалидировать (ты называешь удалением) кеш, а заполнять его в очереди заданий с заранее заданной периодичностью.
     
  10. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Отключить принудительное удаление, а в php индивидуально выставить время жизни кэша каждому запросу, чтоб разное было?
     
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Билят!!! Не инвалидировать -- значить считать что кеш всегда актуален и читать из него с одной и той же скоростью. Да, в первые десять минут после запуска шайтан машины с кроном кеш будет пустым. А потом всегда наполненными. Понял алгоритм?
    --- Добавлено ---
    Есть процесс писатель и есть процесс читатель. Удалять никто ничего не будет. Так трудно ломать шаблон, да?
     
  12. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Так, данные будут устаревшими
     
  13. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Они всегда устаревшие, это аксиома! Просто допусти что они будут актуализироваться с заданной частотой.
    --- Добавлено ---
    И тогда отпадет необходимость в ожидании, страница будет формироваться быстро всегда, график зависимости от нагрузки станет очень "пологий".
     
  14. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Хорошо, как это реализовать?
     
  15. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Я написал как. Тебе прямо код на пхп дать? Это будет дорого :)
     
  16. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Сколько такой код будет стоить, как буду готов обращусь?)
     
  17. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Сто тысяч рублей. И это будет только бекенд, никакой верстки. Или напрягись и врикни сам в идею. Бесплатно.
     
  18. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Спасибо
     
  19. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Чтобы было понятнее, приведу пример: ты приходишь в некий фастфуд за ланчем. Если они будут начинать готовить только после заказа, ты будешь ждать свой бургер полчаса. А если они будут гтовить заранее, то получишь моментально. Но правда бургер можеи быть 10 минутной свежести, они так расчитали. А может и свежий, если повезет. Но не старше 10 минут, т.к. старые бургеры они отправляют в... лучше не знать куда. И гтовят новые.
     
    Arcadiy нравится это.
  20. Arcadiy

    Arcadiy Активный пользователь

    С нами с:
    3 янв 2016
    Сообщения:
    23
    Симпатии:
    0
    Спасибо огромное