swoole+php搭建高性能脚本服务

2018-12-07 11:20:49 浏览数 (1)

后台服务的业务逻辑中,或多或少需要一些异步去处理的脚本逻辑,例如业务的统计、上报、数据运算,定时监控等等。实现的方法也有很多,用linux自带的crontab,定时清理服务器上的日志就很常用,由于Python处理数据的优势,很多开发童鞋也会用python来跑一些需要运算的脚本,另外还有网上流行的一些脚本框架,一些大公司也有自己研发的框架服务。在最近的项目中,接触到swoole2 与php7 搭配的性能优越,普通4核心CPU,单机压测qps 10000 /s,突生灵感,除了用来搭后端服务,能不能用来搭一个脚本服务呢?

于是归纳了一下以前跑脚本的问题:

代码语言:javascript复制
1、crontab:不能实现到秒级,最多到分钟级,这是很多开发的小痛点,当然想实现秒级也是可以滴,这么写:    
 ***** sleep 10;/usr/bin/myshell.sh     
 ***** sleep 20;/usr/bin/myshell.sh     
 ***** sleep 30;/usr/bin/myshell.sh    
 ***** sleep 40;/usr/bin/myshell.sh     
 ***** sleep 50;/usr/bin/myshell.sh
 变相实现10秒执行一次,但这做法有点low有木有,而且crontab多了比较离散,缺乏集中管理。当然这里可以用一些
 crontab的管理工具来维护。
2、搭一套同步服务框架,走服务请求来跑脚本,这里有个好处,本身的服务的很多方法函数,走脚本服务框架时可以复用。
   但传统服务框架thinkphp、CI等性能较低,脚本内的逻辑存在调用下游时,由于下游服务的不可靠性。导致超时阻塞,
   服务雪崩,影响其它脚本。
3、其它第三方架构,包括之前用公司内部的一些脚本大师,都不甚好用。要么存在同步阻塞,要么时间粒度太粗,要么缺
   少好的监控。

问题理清楚后,需求也就很清晰了:

代码语言:javascript复制
1、时间粒度精确到秒。

2、有监控脚本,各脚本运行情况。

3、高性能,多任务同时在跑,不会相互影响。

表简单设计如下:

代码语言:sql复制
CREATE TABLE `task` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `task_desc` varchar(256) NOT NULL COMMENT '任务描述',
  `task_name` varchar(128) NOT NULL COMMENT '任务名称,对应控制器',
  `task_crontab` varchar(128) NOT NULL COMMENT '每隔多久执行一次',
  `task_status` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '-1未启用,0等待下次执行,1执行中',
  `runnings` smallint(6) NOT NULL DEFAULT '0' COMMENT '正在执行的进程数',
  `is_multy` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1允许同时执行多个;0须等待上一次执行完才执行下一次,即使下次执行时间到。',
  `exec_times` int(11) NOT NULL DEFAULT '0' COMMENT '已累计执行次数',
  `err_times` int(11) NOT NULL DEFAULT '0' COMMENT '累计失败次数',
  `last_exec_time` datetime NOT NULL COMMENT '最后执行时间',
  `next_exec_time` datetime NOT NULL COMMENT '下一次准备执行时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='任务管理表'

例如下面添加了一条测试任务:

任务的名称对应脚本框架服务中有一个控制器,来处理脚本逻辑。

脚本服务的调度流程脚本服务的调度流程

服务相关事项:

代码语言:javascript复制
1、shell起多个task.sh进程去调脚本框架服务的main入口,脚本服务支持1w qps/s,这里起多少个进程视情况定。
eg:#!/bin/bash
    while ((1));do
      exec main
    sleep 1
    done
2、用check_task.sh监控脚本task.sh是否运行。
    #!/bin/bash
    count=`ps aux|grep "task_idc"|grep -v 'grep'|wc -l`
    if [ $count -lt 1 ]; then
        echo `bash task_idc.sh 2>&1 &`
    fi
3、next_exec_time每个任务下一次执行时间,如果有任务这个时间小过了当前时间,所以有任务不健康,这里简单监控下。
    conn="mysql -h${HOSTNAME}  -P${PORT}  -u${USERNAME} -p${PASSWORD} ${DBNAME}"
    select_sql="select id,task_crontab,unix_timestamp(next_exec_time) from ${TABLENAME} where task_status>-1"
    ${conn} -s -e "${select_sql}">${FILE_PATH}
    IFS_OLD=${IFS}
    IFS=$'n'
    NOWTIME=$(date  %s)
    IS_ALARM=0
    for line in `cat ${FILE_PATH}`
    do
        ID=$(echo ${line}|awk '{print $1}')
        SEC=$(echo ${line}|awk '{print $2}')
        TIME=$(echo ${line}|awk '{print $3}')
        if [ ${TIME} -lt $[ ${NOWTIME}-1800 ] ];then//时间可以自由定
                IS_ALARM=1
        fi
    done
    IFS=${IFS_OLD}
    if [ ${IS_ALARM} -eq 1 ];then
      //告警
    fi
4、脚本服务框架的本身是否运行的监控check_server.sh。

任务服务注意事项:

代码语言:javascript复制
1、并发读取待执行任务,防止高并发时被读到同一条任务,利用MYSQL的DML的原子性保证。
2、拉待执行任务的时候,非超级任务,不可拉执行中的,超级任务才可以拉执行中,因为只有超级任务定义为,不需要等待上一
   次执行完,才执行下一次。
3、结束单条任务的时候,同样需要注意超级任务与非超级任务的区别来决定 runnings 和 status 的状态。

这套脚本服务主要用于php执行业务相关逻辑,当然php也可以运行shell脚本,但不支持python等其它一些语言的脚本调用。并没有高大尚的技术,充分发挥了swoole php的性能,有更好的脚本框架的开发者,欢迎一起交流进步 ^ ^

0 人点赞