Очередь задержки, как следует из названия, представляет собой очередь сообщений с функцией задержки. Итак, в каком случае мне нужна такая очередь?
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/Чэнь Линьчжун, ох ты...