方案介绍

该方案出来的场景:一天有一个业务需求,需要把我方的一些信息或订单状态等异步发起请求同步给第三方,这里就会出现定时时间和延迟时间消息的处理,考虑过很多消息队列方案(如:rabbitmq、云消息服务等)。

不过最后公司定了因为该业务流量很小,不用做那么麻烦。所以就直接出了这个方案

该方案在50条消息/s,应该压力不大,量大了就会出现一个消息延迟问题,如果不注重这个业务时间准确性,该方案承载的秒级处理在1000内应该问题也不大

方案架构图

mysql的任务队列表

CREATE TABLE `open_queue` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`type` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '任务类型,可用于后续读取不同任务失败次数区分',`order_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '业务绑定的订单id等,根据自己自行设计业务id',`event_identity` varchar(30) NOT NULL DEFAULT '' COMMENT '事件表示分类,可不用,同type',`data` text NOT NULL COMMENT '需要处理的数据,json格式化',`try` tinyint(4) unsigned NOT NULL DEFAULT '1' COMMENT '特定任务需要当时就处理的次数,而不是发起回调请求的任务',`again` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0不是重试记录 1重试记录,失败后发起任务未1,否者未0',`status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否被执行 1是 0否',`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '任务创建的时间戳',`at_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '任务时间的时间戳',`task_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '执行结果 -1重复消息系统主动取消 0未执行 1执行成功 2执行失败',`task_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '执行时间',PRIMARY KEY (`id`),KEY `IDX_EVENT` (`event_identity`),KEY `IDX_AT_TIME` (`at_time`) USING BTREE,KEY `IDX_ORDER` (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

方案实现源码

下方代码都是伪代码,大家自行根据思路自己设计业务

redis同步到mysql

该步骤可以省略,因为我方当时redis是单机部署,也没做持久化,

$redisTypeLock; //lock类型
if (!IS_WIN) {$file = fopen($path . "/lock/{$redisTypeLock}.lock","w+");if (!flock($file, LOCK_EX | LOCK_NB)) {flock($file,LOCK_UN);fclose($file);exit;}
}//成功获得锁 开始业务执行$count = get_redis_lLen('msgevent:' . $redisType);
if (!$count) {//无需要入数据库订单队列,直接返回return false;
}$successCount = 0;
for ($i = 0; $i < $loopLen; $i++) {$data = get_redis_lPop('msgevent:' . $redisType);//把redis数据格式化存入到数据库持久化$result = $this->saveToMysql($data);if (!$result) {//如果执行失败,重新推入redis队列get_redis_lPush('msgevent:' . $redisType, $data);}$successCount++;
}if (!IS_WIN) {flock($file, LOCK_UN);fclose($file);
}

定时执行任务的的入口

这个入口是定时秒级处理脚本和处理小于当前时间的脚本调用的入口

public function task_run()
{$timeType = $_GET['tt'] ? : 'now';//获取当前秒需要处理的所有消息, 依次路由后执行//如果你redis无需存入mysql,你可以redis的list结构实现, 一次全部取出数据集合,并删除list//如果接下去业务里发现发起请求失败了,重新把任务分配给redis建立恢复list,list名为t+需要什么时间执行的时间戳$lists = $this->getTaskLists($timeType);foreach ($lists as $item) {$this->task('event:' . $item['event_type']);//$this->task('event:demo1');//$this->task('event:demo2');//$this->task('event:demo3');}
}

实际处理业务(发起通知请求)

# 模拟一个发起的请求事件demo
private function pushDemo1Event($info)
{$sendInfoData = $this->getSendInfoFromInfo($info);//发起请求,这里做的真正的发起给对方的请求,你可以根据$sendInfo拼接各种事件或消息分类给对方$isSuccess = $this->sendInfo($sendInfoData);$data = array('status'        => 1,'task_status'   => $isSuccess ? 1 : 2,'task_time'     => NOW_TIME);$db->save($data);//如果执行失败,重新插入一条记录,并把at_time生成下次执行的时间戳,这样定时器根据at_time字段可以取出判断执行到当时的秒级if (!$isSuccess) {$tryCount = $db->where(...)->count();if ($tryCount >= 5) {return false;}$this->newTask($info, $tryCount, 30);}
}private function newTask($info, $tryCount, $timeout = 30)
{$newTime = $this->nextTaskTime($info, $timeout);$data = array(...'at_time' => newTime //执行的时间(时间戳));$db->add($data);
}

定时消费方

$timeType = $_GET['time_type'] ? : 'now';
$lists = $this->getMsgAll($timeType);
if (!$lists) {return false;
}foreach ($lists as $item) {if ($item['type'] == '1') {//根据业务生成我方真实订单call_user_func_array(array($this, "add_real_order"), array($item));}if (in_array($item['type'], array(2,3))) {$this->push('push:toengineer', $item);  //指派或取消工程师}if ($item['type'] == '5') {$this->push('push:edit', $item);  //编辑}if ($item['type'] == '6') {$this->push('push:cancel', $item);  //取消}if ($item['type'] == '7' || $item['type'] == '8' || $item['type'] == '9') {$this->push('push:status', $item);  //简单订单状态}
}

借助crontab+shell外力实现秒级执行

因为crontab是最小单位是分钟,所以需要借助shell脚本来实现秒级执行

读取redis任务队列到mysql存储

#!/bin/bash
cd /web/project/src
for (( i = 1; i < 60; i = i + 1 ))
do#执行php直接返回,不会阻塞 不要忘记最后面的 &$(/usr/bin/php index.php redis2mysql > /dev/null 2>&1 &)sleep 1
doneexit 0

处理秒级时间sh脚本

#!/bin/bash
cd /web/project/src
for (( i = 1; i < 60; i = i + 1 ))
do$(/usr/bin/php index.php task_run > /dev/null 2>&1 &)sleep 1
doneexit 0

处理秒级小于当前时间sh脚本

#!/bin/bash
cd /web/project/src
for (( i = 1; i < 60; i = i + 1 ))
do$(/usr/bin/php index.php task_run/tt/lt > /dev/null 2>&1 &)sleep 1
doneexit 0

linux下的crontab

* * * * * sh /web/project/src/shell/repair_build_order.sh
* * * * * sh /web/project/src/shell/repair_sync_second.sh
* * * * * sh /web/project/src/shell/repair_sync_lt_time.sh

php+crontab+shell方案实现的秒级定时发起异步请求回调方案相关推荐

  1. java定时任务管理_基于SpringBoot+layui秒级定时任务管理:JTimer for JAVA项目

    一.JTimer for JAVA简介 1.项目介绍 JTimer for JAVA是基于SpringBoot+layui秒级定时任务管理,取代crontab.其PHP版本 https ://gite ...

  2. 亿级数据多条件组合查询——秒级响应解决方案

    1 概述 组合查询为多条件组合查询,在很多场景下都有使用.购物网站中通过勾选类别.价格.销售量范围等属性来对所有的商品进行筛选,筛选出满足客户需要的商品,这是一种典型的组合查询.在小数据量的情况下,后 ...

  3. 一秒级接收20W+消息落库比Mysql快1000倍

    项目地址  flowback: 亿级消息落库,大数据收集,秒级10w+数据落库,亿级数据检索秒级响应解决方案 最近有大数据落库需求秒级达到10w+于是写了个开源项目 总体使用Netty 与 堆外内存 ...

  4. c语言 linux系统 delay,Linux下实现秒级定时任务的两种方案

    Linux下实现秒级定时任务的两种方案(Crontab 每秒运行): 第一种方案,当然是写一个后台运行的脚本一直循环,然后每次循环sleep一段时间. while true ;do command s ...

  5. DDM实践:数据库秒级平滑扩容方案

    2019独角兽企业重金招聘Python工程师标准>>> 本文部分内容节选自华为云帮助中心的分布式数据库中间件(DDM)服务的产品介绍 背景 随着业务增长,逻辑库存储空间不足,并发压力 ...

  6. Android秒级编译方案-FreeLine

    Freeline 是什么? Freeline 是一款 Android 平台上的秒级编译方案,能够显著地提高 Android 工程的编译速度 为什么使用FreeLine 随着Android app 工程 ...

  7. mysql秒级平滑_DDM实践:数据库秒级平滑扩容方案

    本文部分内容节选自华为云帮助中心的分布式数据库中间件(DDM)服务的产品介绍 背景 随着业务增长,逻辑库存储空间不足,并发压力较大. 解决方案 此时可对DDM实例逻辑库进行平滑扩容,通过增加RDS实例 ...

  8. PowerBI 秒级实时大屏展示方案 全面助力双十一

    双十一来了,你准备好了吗?不管你是否准备完毕,我们带来了全网首发的 PowerBI 秒级实时大屏展示方案,你可以直接用来展示双十一的实时状况. 我们一步步来说明这个套件模板教程. 真实效果 功能如下: ...

  9. mysql 平滑扩容_数据库秒级平滑扩容架构方案

    一.缘起 (1)并发量大,流量大的互联网架构,一般来说,数据库上层都有一个服务层,服务层记录了"业务库名"与"数据库实例"的映射关系,通过数据库连接池向数据库路 ...

最新文章

  1. CSDN湘苗培优|高起点步入职场,快人一步!
  2. python入门须知:包、模块、库的含义以及导入以及包下__init__.py的作用
  3. python 编译exe
  4. Linux 备份系统重要服务的配置文件脚本
  5. 求输入的单词个数(单词间用空格隔开 不限空格个数) 首尾不能用空格
  6. [转载] 羽毛球——学打羽毛球 05 正手发后场高远球练习方法
  7. javascript 模拟滚动 隐藏滚动条
  8. ubuntu下的vim与ctags
  9. java生命游戏并行_Java架构--线程的发展历史
  10. sr里简体中文的代码_各国语言代码大全Locale ID (LCID)表
  11. ubuntu20.04.1下安装qt4相关依赖库
  12. iPhone如何快速设置自定义铃声?苹果手机铃声设置教程
  13. 蓝桥杯 2014真题 史丰收速算
  14. ExpRe[10] Ubuntu[2] 准备神秘软件、备份恢复软件
  15. 钢铁侠是如何练成的(一)
  16. Android使用AIUI快速搭建智能助手
  17. matlab绘制x坐标是底数为2的幂函数的折线图
  18. 注册昵称时限制 中文7个字 字母21个
  19. 盛迈坤电商:电商运营要怎么样进行选款
  20. 西瓜书与蓝皮书 思维导图(转)

热门文章

  1. Linux系统安全防护加固
  2. VBS操作IE ---(【当不使用IE时】可以使用Chrome插件,自定义JS插件操作浏览器)
  3. php mysql多表关联删除_MySQL中多表删除方法
  4. Mysql解决死锁的问题,防止阻塞
  5. maven项目发布到tomcat后没有lib目录解决方案
  6. Vue解决接口访问跨域问题
  7. @Value取值为NULL的解决方案
  8. 【SpringBoot】拦截器使用@Autowired注入接口为null解决方法
  9. 解决vscode卡顿,CPU占用过高的问题
  10. 使用Jackson忽略JSON对象上的新字段[复制]