babahalki
Постоялец
- Регистрация
- 6 Май 2016
- Сообщения
- 247
- Реакции
- 107
- Автор темы
- #1
Работа по оптимизации работы сипла под нагрузкой продолжается. К сожалению сильно много выжать из оптимизации самых сложных запросов в БД не удалось, поэтому дальше мы развиваем следующую тему.
Логика работы.
При заходе пользователя на страницу, кел проверяет есть ли у него данные по работы отдельных функций. Если данные есть, пользователю грузим данные из кеша, а задание на обновление кеша, т.е. на полную отработку функции помещаем в очередь заданий. Cron 2 раза в час запускает выполнение очереди заданий и отрабатывает функции с обновлением кеша.
Преимущества:
1. Сайт может обрабатывать большее число пользователей без особого труда, скорость открытия самых тяжелых страниц (разделы с множеством товаров и включенных фильтров) возрастает в несколько раз. У нас без кеша страница может грузится секунд 15, а с кешем не более 4 секунд.
2. Кеш регулярно обновляется, те места куда ходят пользователи регулярно обновляются. Теоретически пользователь видит относительно свежий кеш, который обновился от получаса до нескольких часов назад.
3. Очередь заданий не нагружает систему, загрузка ЦП во время работы около 1%, но активно работает с mysql. Надо бы как-то оптимизировать.
Недостатки:
1. Кеш занимает приличный объем, сейчас у нас кеш занимает 8гб.
2. Кеш есть кеш, поэтому информация загружаемая пользователем хорошей свежести, но не первой.
Проблемы:
Есть особо сложные вызовы функций, когда после конвертации передаваемых им параметров из переменной массива в строку и обратно, что-то меняется и функция не отрабатывает как должна.
Помогите, если кто сталкивался.
Это класс очереди задач
Это функция с добавлением в очередь задач.
Как видно входные параметры $filter для функции в виде массива конвертируются в строку через var_export($filter, true), потом формируется задание, которые потом сможет принять eval().
//создаем переменную для задачи, соединяя между собой нужную функцию и массив параметров
$task = '$okay->products->get_images('; /*берем функцию*/
$task .= $filter_export; /*добавляем параметры массива в виде array(...........)*/
$task .= ');';/*закрываем скобки*/
В итоге в переменной $task у нас строка, которую мы через serialize($task) добавляем в бд.
Когда задание выполняется, просходит обратная конвертация unserialize($results->task), а потом eval() полученного.
Все работает, но спотыкается на некоторых параметрах.
Вот пример выхлопа из очереди заданий.
В чем может быть проблема?
Логика работы.
При заходе пользователя на страницу, кел проверяет есть ли у него данные по работы отдельных функций. Если данные есть, пользователю грузим данные из кеша, а задание на обновление кеша, т.е. на полную отработку функции помещаем в очередь заданий. Cron 2 раза в час запускает выполнение очереди заданий и отрабатывает функции с обновлением кеша.
Преимущества:
1. Сайт может обрабатывать большее число пользователей без особого труда, скорость открытия самых тяжелых страниц (разделы с множеством товаров и включенных фильтров) возрастает в несколько раз. У нас без кеша страница может грузится секунд 15, а с кешем не более 4 секунд.
2. Кеш регулярно обновляется, те места куда ходят пользователи регулярно обновляются. Теоретически пользователь видит относительно свежий кеш, который обновился от получаса до нескольких часов назад.
3. Очередь заданий не нагружает систему, загрузка ЦП во время работы около 1%, но активно работает с mysql. Надо бы как-то оптимизировать.
Недостатки:
1. Кеш занимает приличный объем, сейчас у нас кеш занимает 8гб.
2. Кеш есть кеш, поэтому информация загружаемая пользователем хорошей свежести, но не первой.
Проблемы:
Есть особо сложные вызовы функций, когда после конвертации передаваемых им параметров из переменной массива в строку и обратно, что-то меняется и функция не отрабатывает как должна.
Помогите, если кто сталкивался.
Это класс очереди задач
Код:
<?php
require_once('Okay.php');
class simpleq
{
public function addtask($key, $method, $task) {
if (empty($task || $key)) return false;
dtimer::log(__METHOD__.' key '.$key);
$okay = new Okay();
$task = serialize($task);
$task = $okay->db->escape($task);
$key = $okay->db->escape($key);
$query = "
INSERT t_queue
(`key`,`method`, `task`)
VALUES
('$key' , '$method' , '$task')
;";
dtimer::log(__METHOD__.' query '.$query);
$okay->db->query($query);
return TRUE;
}
public function count_tasks() {
//dtimer::log(__METHOD__.' start '.$key);
$okay = new Okay();
$query = "
SELECT COUNT(*) as count
from t_queue
;";
$okay->db->query($query);
$return = $okay->db->results();
//print_r($return);
return $return[0]->count;
}
public function getlasttask() {
dtimer::log(__METHOD__);
$okay = new Okay();
$okay->db->query("
SELECT *
FROM t_queue
ORDER BY id
LIMIT 1
;");
$return = $okay->db->results()[0];
dtimer::log(__METHOD__.' results:'.print_r($return,true));
return $return;
}
public function gettask($id) {
dtimer::log(__METHOD__.' id '.$id);
if (empty($id)) return FALSE;
$okay = new Okay();
$okay->db->query("
SELECT *
FROM t_queue
WHERE id = $id
;");
$return = $okay->db->results()[0];
dtimer::log(__METHOD__.' id '.$return->key);
return $return;
}
public function exectask($id) {
dtimer::log(__METHOD__.' id '.$id);
if (empty($id)) return FALSE;
$okay = new Okay();
$okay->db->query("
SELECT *
FROM t_queue
WHERE id = $id
;");
$task = unserialize($okay->db->results()[0]->task);
return eval($task);
}
public function execlasttask() {
dtimer::log(__METHOD__.' start ');
$okay = new Okay();
$query_select = "
SELECT *
FROM t_queue
ORDER BY id
LIMIT 1
;";
$okay->db->query($query_select);
$results = $okay->db->results();
//print($results);
if(!$results) return false;
$id = $results[0]->id;
$task = unserialize($results[0]->task);
$query_delete = "
DELETE t
FROM t_queue t
WHERE id = '$id'
;";
$delete_t = $okay->db->query($query_delete);
eval($task);
return true;
}
}
Это функция с добавлением в очередь задач.
Код:
public function get_images($filter = array()) {
//Проверяем нужен ли нам кеш
if($filter['nocache']) {
// делаем $filter_key, без параметра nocache, чтобы кеш правильно искал
$filter_key = $filter;
unset($filter_key['nocache']);
$filter_key = var_export($filter_key,true);
} else {
//делаем $filter_export если nocache не задан
$filter_key = var_export($filter,true);
}
//формируем $key для кеша и планировщика заданий
$key = "get_images"."_".hash(MD4, $filter_key);
dtimer::log(__METHOD__ . ' key after calculate '. $key . ' ' . __LINE__);
// если кеширование включено и параметр nocache не задан берем задание из кеша
// и добавляем task на обновление кеша
if(!$filter['nocache']) {
global $cache, $queue;
if($cache) $get_images = $cache->get("$key");
$filter['nocache'] = 1;
$filter_export = var_export($filter, true);
//создаем переменную для задачи, соединяя между собой нужную функцию и массив параметров
$task = '$okay->products->get_images(';
$task .= $filter_export;
$task .= ');';
$method = $filter['method'];
//пишем в базу сформированное задание
dtimer::log(__METHOD__ . ' add task key ' .$key.' '. __LINE__);
if($queue) $queue->addtask($key, $method, $task);
// если есть берем данные из кеша и заканчиваем выполнение функции
if($get_images != null) return $get_images;
}
$product_id_filter = '';
if(!empty($filter['product_id'])) {
$product_id_filter = $this->db->placehold('AND i.product_id in(?@)', (array)$filter['product_id']);
}
// images
$query = $this->db->placehold("SELECT
i.id,
i.product_id,
i.name,
i.filename,
i.position
FROM __images AS i
WHERE
1
$product_id_filter
ORDER BY i.product_id, i.position
");
$this->db->query($query);
//phpfastcache
$get_images = $this->db->results();
dtimer::log(__METHOD__.' results db:'.print_r($get_images,true));
// Write products to Cache in 30 days with same keyword 30 * 24 * 60 * 60
global $cache;
if($cache) {
dtimer::log(__METHOD__ . ' cache set ' .$key. ' ' . __LINE__);
$cache->set("$key", $get_images, 2592000);
}
return $get_images;
}
Как видно входные параметры $filter для функции в виде массива конвертируются в строку через var_export($filter, true), потом формируется задание, которые потом сможет принять eval().
//создаем переменную для задачи, соединяя между собой нужную функцию и массив параметров
$task = '$okay->products->get_images('; /*берем функцию*/
$task .= $filter_export; /*добавляем параметры массива в виде array(...........)*/
$task .= ');';/*закрываем скобки*/
В итоге в переменной $task у нас строка, которую мы через serialize($task) добавляем в бд.
Когда задание выполняется, просходит обратная конвертация unserialize($results->task), а потом eval() полученного.
Все работает, но спотыкается на некоторых параметрах.
Вот пример выхлопа из очереди заданий.
Код:
stdClass Object
(
[id] => 91683
[key] => get_categories_options_15ec77effec3ef909b8c0eff9ee56473
[method] => Features::get_categories_options_354
[task] => s:627:"$okay->features->get_categories_options(array (
'visible' => 1,
'feature_id' =>
array (
0 => 4,
1 => 20,
2 => 21,
3 => 22,
4 => 24,
5 => 17,
6 => 18,
7 => 19,
8 => 9,
9 => 8,
10 => 14,
11 => 13,
12 => 10,
13 => 2,
14 => 25,
15 => 15,
16 => 16,
17 => 26,
18 => 27,
19 => 12,
20 => 34,
21 => 35,
22 => 36,
23 => 3,
24 => 31,
25 => 23,
),
'category_id' =>
array (
0 => 47,
),
'features' =>
array (
2 =>
array (
0 => 'sovremennyj',
),
),
'brand_id' => '40',
'nocache' => 1,
));";
)
В чем может быть проблема?