Обработка задержки заказа PHP - очередь задержки

Redis задняя часть Архитектура PHP

Очередь задержки, как следует из названия, представляет собой очередь сообщений с функцией задержки. Итак, в каком случае мне нужна такая очередь?

1. Предпосылки

Сначала рассмотрим бизнес-сценарий:

  • 1. Отправьте уведомление об отзыве за 3 дня до истечения срока членства.
  • 2. После того, как заказ будет успешно оплачен, через 5 минут проверьте, нормальные ли нисходящие ссылки.Например, после того, как пользователь приобрел членство, успешно ли установлены различные статусы членства.
  • 3. Как регулярно проверять, был ли успешно возвращен заказ в статусе возврата?
  • 4. Не удалось реализовать уведомление, повторить уведомление через 1, 3, 5, 7 минут, пока другая сторона не ответит?

Обычно самый простой и прямой способ решения вышеуказанных проблем — регулярное сканирование таблицы.

Проблемы со сканированием таблицы:

  • 1. Таблица сканирования длительное время подключена к БД, при большом количестве подвержена аварийному обрыву соединения, что требует большей обработки исключений и высоких требований к надежности программы.
  • 2. В случае большого количества данных задержка велика, и обработка не может быть завершена в рамках регламента, что влияет на бизнес.Хотя для обработки может быть запущено несколько процессов, это приведет к дополнительным затратам на обслуживание и не может быть принципиально решен.
  • 3. Каждое предприятие должно поддерживать собственную логику сканирования таблиц. Когда предприятий становится все больше и больше, выясняется, что логика сканирующей части будет развиваться неоднократно, но она очень похожа

Очередь с задержкой может быть хорошим решением вышеуказанных требований.

2. Исследование

Некоторые решения с открытым исходным кодом на рынке исследуются следующим образом:

  • 1. Технология Youzan: только принцип, без открытого исходного кода

  • 2. гитхаб персональный:GitHub.com/Оу Цян/Давай…

    1.基于redis实现,redis只能配置一个,如果redis挂了整个服务不可用,可用性差点
    2.消费端实现的是拉模式,接入成本大,每个项目都得去实现一遍接入代码
    3.在star使用的人数不多,放在生产环境,存在风险,加之对go语言不了解,出了问题难以维护
    
  • 3.SchedulerX-Alibaba с открытым исходным кодом: очень мощный, но сложный в эксплуатации и обслуживании, много зависимых компонентов, недостаточно легкий

  • 4. Отложенная задача RabbitMQ: у нее нет самой функции задержки, ее нужно реализовать самой с помощью фичи, и компания не развернула эту очередь, немного дорого развертывать одну для сделать очередь задержки, а также требует специальной эксплуатации и обслуживания.Техническое обслуживание, в настоящее время не поддерживается командой

В основном, по вышеуказанным причинам, я планирую написать его сам. Обычно я много использую PHP. Проект в основном использует структуру redis zset в качестве хранилища и реализует его на языке PHP. Принцип реализации относится к команде Youzan:Специальность Youzan.com/queuing_ Понял…

3. Цели

  • Легкий: его можно запускать напрямую с меньшим количеством расширений php, нет необходимости вводить сетевые фреймворки, такие как swoole, workman и т. д.
  • Стабильность: используя архитектуру мастер-работа, мастер не занимается бизнес-обработкой, а отвечает только за управление дочерним процессом, и дочерний процесс автоматически подтягивается, когда он выходит из строя.
  • Доступность:
    • 1. Поддержка развертывания с несколькими экземплярами, каждый экземпляр не имеет состояния, один экземпляр зависает, не влияя на службу.
    • 2. Поддержка настройки нескольких Redis, зависание Redis влияет только на некоторые сообщения.
    • 3. Бизнес-сторона легкодоступна и требует только заполнения соответствующего типа сообщения и интерфейса обратного вызова в фоновом режиме.
  • Масштабируемость: при возникновении узких мест в процессе потребления вы можете настроить увеличение количества процессов потребления.При возникновении узких мест при записи вы можете увеличить количество экземпляров.Производительность записи может быть линейно улучшена.
  • В режиме реального времени: допустить определенную ошибку времени.
  • Поддержка удаления сообщений: бизнес-пользователи могут удалять указанные сообщения в любое время.
  • Надежность передачи сообщения: после того, как сообщение попадает в очередь задержки, оно гарантированно будет использовано хотя бы один раз.
  • Производительность записи: qps>1000+

4. Архитектурный проект и описание

Общая архитектура

在这里插入图片描述

Используя модель архитектуры мастер-работы, она в основном включает 6 модулей:

  • 1.dq-mster: основной процесс, отвечающий за управление созданием, уничтожением, повторным использованием и сигнальным уведомлением дочерних процессов.
  • 2.dq-сервер: отвечает за запись сообщений, чтение, удаление функций и поддержание пула соединений redis
  • 3. dq-timer-N: Отвечает за сканирование просроченных сообщений из структуры zset Redis и отвечает за запись в очередь готовности, число можно настроить, обычно 2 достаточно, потому что сообщения упорядочены по времени в zset структура
  • 4.dq-consume-N: отвечает за чтение сообщений из очереди готовности и уведомление соответствующего интерфейса обратного вызова, номер можно настроить
  • 5. dq-redis-checker: отвечает за проверку состояния службы redis, если redis не работает, отправьте электронное письмо с предупреждением.
  • 6.dq-http-server: Предоставляет фоновый веб-интерфейс для регистрации тем.

5. Развертывание

Зависимости от среды:PHP 5.4+ 安装sockets,redis,pcntl,pdo_mysql 拓展

Шаг 1: Установите базу данных для хранения некоторых тем и информации о тревогах.
create database dq;
#存放告警信息
CREATE TABLE `dq_alert` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `host` varchar(255) NOT NULL DEFAULT '',
  `port` int(11) NOT NULL DEFAULT '0',
  `user` varchar(255) NOT NULL DEFAULT '',
  `pwd` varchar(255) NOT NULL DEFAULT '',
  `ext` varchar(2048) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
#存放redis信息
CREATE TABLE `dq_redis` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `t_name` varchar(200) NOT NULL DEFAULT '',
  `t_content` varchar(2048) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
#存储注册信息
CREATE TABLE `dq_topic` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `t_name` varchar(1024) NOT NULL DEFAULT '',
  `delay` int(11) NOT NULL DEFAULT '0',
  `callback` varchar(1024) NOT NULL DEFAULT '',
  `timeout` int(11) NOT NULL DEFAULT '3000',
  `email` varchar(1024) NOT NULL DEFAULT '',
  `topic` varchar(255) NOT NULL DEFAULT '',
  `createor` varchar(1024) NOT NULL DEFAULT '',
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `method` varchar(32) NOT NULL DEFAULT 'GET',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
шаг 2: Настройте информацию о базе данных в файле DqConfg.: DqConf::$db
шаг 3: запустить службу http

Изменен путь $logPath в файле DqConf.php.

Заказ:

php DqHttpServer.php --port 8088

доступ:http://127.0.0.1:8088, появится интерфейс конфигурации

在这里插入图片描述
Формат информации Redis: host:post:auth, например 127.0.0.1:6379:12345.

stop4: запустить сервисный процесс:

php DqInit.php --порт 6789 Следующая информация указывает на то, что запуск прошел успешно.

在这里插入图片描述

stop5: информация отчета о конфигурации (например, время простоя Redis)

在这里插入图片描述

stop6: зарегистрировать тему

在这里插入图片描述
在这里插入图片描述

Шаг 7: Запишите данные, создайте новый файл test.php в корневом каталоге проекта для записи
<?php
include_once 'DqLoader.php';
date_default_timezone_set("PRC");
//可配置多个
$server=array(
    '127.0.0.1:6789',
);
$dqClient = new DqClient();
$dqClient->addServer($server);

$topic ='order_openvip_checker'; //topic在后台注册
$id = uniqid();
$data=array(
    'id'=>$id,
    'body'=>array(
        'a'=>1,
        'b'=>2,
        'c'=>3,
        'ext'=>str_repeat('a',64),
    ),
    //可选,设置后以这个通知时间为准,默认延时时间在注册topic的时候指定
    'fix_time'=>date('Y-m-d 23:50:50'),
);

//添加
$boolRet = $dqClient->add($topic, $data);
echo 'add耗时:'.(msectime() - $time)."ms\n";
//查询
$time = msectime();
$result = $dqClient->get($topic, $id);
echo 'get耗时:'.(msectime() - $time)."ms\n";

//删除
$time = msectime();
$boolRet = $dqClient->del($topic,$id);
echo 'del耗时:'.(msectime() - $time)."ms\n";

Выполнить php test.php

Шаг 8: Просмотр журнала

Каталог журналов по умолчанию находится в каталоге журналов каталога проекта, измените $logPath в DqConf.php.

  • 1. Журнал запросов: request_ymd.txt
  • 2. Журнал уведомлений: notify_ymd.txt
  • 3. Журнал ошибок: err_ymd.txt
Шаг 9: Если файл конфигурации изменился
  • 1. Система автоматически обнаружит новый файл конфигурации.Если есть какие-либо изменения, она автоматически завершится (лучшего решения для горячего обновления не существует).Если вам нужно перезагрузиться, вы можете создать задачу в crontab и выполнить ее один раз в 1 минута В ​​программе есть оценка check_self
  • 2. Команда изящного выхода: мастер обнаруживает и прослушивает сигнал USR2 и уведомляет все дочерние процессы после получения сигнала, а дочерний процесс автоматически завершается после завершения текущей задачи.

ps -ef | grep dq-master| grep -v grep | head -n 1 | awk '{print $2}' | xargs kill -USR2

6. Тест производительности

Необходимо установить расширение pthreads:

Принцип тестирования: используйте многопоточность для имитации параллелизма и успешно возвращайте количество успешных запросов в течение 1 с.

php DqBench  concurrency  requests
concurrency:并发数
requests: 每个并发产生的请求数

测试环境:内存 8G ,8核cpu,2个redis和1个dq-server 部署在一个机器上,数据包64字节
qps:2400

7. Стоит отметить моменты оптимизации производительности:

  • 1. команда redis multi: объедините несколько операций в redis в одну, чтобы уменьшить нагрузку на сеть.
  • 2. Операция подсчета выполняется асинхронно.В асинхронной логике для сохранения статической переменной используется статическая переменная функции.При успешной записи в Redis статическая переменная освобождается, и подсчет может оставаться согласованным, когда redis является ненормальным, если только процесс не завершается.
  • 3. Обнаружение утечки памяти необходимо: все выделения памяти вызывают brk или mmap на нижнем уровне.Пока программа имеет только большое количество системных вызовов brk или mmap, вероятность утечки памяти очень высока.Команда обнаружения : strace -c -p pid | grep 'mmap|brk'
  • 4. Обнаружить системные вызовы программы: strace -c -p pid , установлено, что вызов определенной системной функции в несколько раз больше, чем другие, с большой вероятностью может быть проблема в программе

Восемь, обработка исключений

Если интерфейс уведомления вызывается в течение периода ожидания и не получен ответ, считается, что уведомление не удалось, система повторно поставит данные в очередь и повторно уведомит.Система по умолчанию использует максимум 10 уведомлений (вы можете изменить $notify_exp_nums в файле Dqconf.php).Интервал уведомления 2n+1, например, в первый раз уведомление не приходит в течение 1 минуты. Через 3 минуты во второй раз, пока не будет получен ответ, система автоматически отбрасывает максимальное количество уведомлений и одновременно отправляет уведомление по электронной почте.

ps:网络抖动在所难免,通知接口如果涉及到核心的服务,一定要保证幂等!!

9. Онлайн-ситуация

Развёрнуто 2 инстанса онлайн, по одному на каждый отдел машинного зала и 4 редиса на хранилище.Сервис стабильно работает уже несколько месяцев, все показатели соответствуют ожиданиям

Основной бизнес доступа:

  • 10-минутное уведомление об отзыве заказов
  • Тайм-аут интерфейса или компенсация отказа

адрес проекта:GitHub.com/Чэнь Линьчжун, ох ты...