原标题:SAE上使用自定义环境运行异步任务
在实际的业务场景中,总有很多的任务需要实时的长时间的执行,例如:
需要使用tcp/http长连接去外部获取数据;
需要实时监控一些数据;
任务队列的处理,发短信、发报警、发邮件等等。
在新浪云的云应用环境,可能大家熟知的有三种处理方式:
通过定时任务处理,因为定时任务可以执行30分钟,普通的http请求最长只能处理300秒。
通过taskqueue任务队列处理,接口程序将一个大任务打散成小的任务,然后通过taskqueue将任务的参数通过http的GET参数通过taskqueue的异步回调到另外的接口处理,taskqueue天生有并发度,可以并行处理多个请求。
通过新浪云提供的后台进程服务实现,后台进程帮助你启动一个PHP的进程完成响应的处理,大多的后台进程都需要这样的死循环实现:while (1) { // 任务的执行逻辑 sleep(1);}
本文将为大家介绍一个更通俗、接地气的进程处理方式,使用新浪云提供的自定义运行环境实现可控的进程管理,以PHP为例进行说明。
实现的流程图
为了达成我们的目的,主要有这么几个问题需要解决:
运行环境的创建
数据怎么获取
代码怎么更新
进程怎么启动、重启、管理
日志的处理
为了说清楚这几个问题,我们绘制了一张示意图:
下面我们将逐一阐述以上问题:
运行环境的制作
自定义的运行环境当前提供的都是一个空的操作系统,目前提供的分类有centos、ubuntu、debian、opensuse、alpine、fedora,每个操作系统的分类都支持几个主流的版本,你可以在创建应用的时候选择具体的分类。
本文假定你已经注册好新浪云账号并完成实名认证,且账户有余额,如果以上的基本要求没达到,请从
https://www.sinacloud.com 注册账户并完成以上步骤。
进入云应用的创建应用页面,选择开发语言选择『自定义』,部署方式选择『手工部署』,选定操作系统和版本(你最熟悉的即可),本文以centos的7.5.1804为例,如图:
创建完成后几秒种后,属于你的一个空的容器应用就完成了,进入容器管理页面:
可以看到容器已经在运行中了,点击上图标示的终端就可以进入到terminal,就可以开始运行环境的制作了。
安装PHP7的环境
安装PHP7需要使用remi的仓库,请参考以下步骤(如果不是centos的环境请自行解决):
yum -C install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm http://rpms.remirepo.net/enterprise/remi-release-7.rpm rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 /etc/pki/rpm-gpg/RPM-GPG-KEY-remi /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 yum -y install yum-utils yum-config-manager --enable remi,remi-php70 yum install -y vim git svn php php-gd php-intl php-tidy php-pdo php-cli php-process php-xml php-mysql php-mbstring php-bcmath php-pecl-swoole php-pecl-redis php-pecl-imagick php-pecl-zip php-pecl-xdebug which --skip-broken echo 'date.timezone=Asia/Shanghai' > /etc/php.d/00-docker-php-date-timezone.ini curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin
为了简便,也可以快速执行:
curl 'http://cdn.sinacloud.net/opensource/php7/centos_init_php7.sh'|bash
安装是一个比较漫长的过程,因为安装的软件包比较多,需要耐心等待。以上步骤执行完成后,PHP7及常用扩展、SVN、Git、Vim等软件就都安装完成了,验证一下PHP的版本及安装的扩展,看到下面这个输出就安装完成了:
Complete! All settings correct for using Composer Downloading... Composer (version 1.6.5) successfully installed to: /usr/bin/composer.phar Use it: php /usr/bin/composer.phar
验证一下PHP的版本:
[root@demo1 /]# php -v PHP 7.0.31 (cli) (built: Jul 17 2018 15:30:29) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans
到此,运行环境就已经安装完成了。
如果你需要安装其他的扩展,你可以编译安装或者直接使用yum安装,如果使用yum安装,类似执行即可:
yum install -y php-pecl-swoole # 提示,这是示例。这个swoole上面已经安装了,不用重复安装了
数据怎么获取
容器中可以使用同一个账户下的其他应用的数据(共享型数据库)及账户级服务的服务,例如redis、rds等。
代码怎么更新
以上在安装软件时,已经帮你装好了SVN和GIT客户端,你可以在容器上直接svn checkout或者git clone其他标准环境应用的仓库,以SVN为例:
mkdir -p /data1/code/ cd /data1/code svn checkout "https://svn.sinacloud.com/gequ/2/" . # 这里的https://svn.sinacloud.com/gequ/2/ 要换成你自己的代码仓库
如上图的步骤,就下载了应用gequ的版本2代码到容器的本地了。
注意:你提交带仓库的代码不会自动更新到容器上,每次修改后需要手工更新。
进程启动、重启、管理
写一个简单的进程示例代码process.php:
<?php if (!function_exists('get')) { function get($url, $timeout = 5, $headers = false) { $s = curl_init($url); curl_setopt($s, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); curl_setopt($s, CURLOPT_RETURNTRANSFER, true); curl_setopt($s, CURLINFO_HEADER_OUT, true); if ($headers) { curl_setopt($s, CURLOPT_HTTPHEADER, $headers); } curl_setopt($s, CURLOPT_TIMEOUT, $timeout); $ret = curl_exec($s); $info = curl_getinfo($s); curl_close($s); if ($info['http_code'] > 0) { return $ret; } return false; }}while (1) { $url = 'http://ip.cn'; $ip = get($url, 5, array('User-Agent: curl/7.29.0')); $time_now = date('Y-m-d H:i:s', time()); echo(sprintf("Now: %sn", $time_now)); echo(sprintf("%sn", $ip)); sleep(10);}
以上程序每10秒钟请求一个外部的地址获取本机的出口ip,然后输出,直接执行 php process.php
root@demo1 /data1/code/process]# php process.php Now: 2018-08-03 10:35:23 当前 IP:123.125.23.213 来自:北京市 联通Now: 2018-08-03 10:35:34 当前 IP:123.125.23.213 来自:北京市 联通
可以看到每十秒钟就输出了一段IP信息,还可以看到通过php process.php就可以启动一个PHP的进程,去完成需求,那么也不可能一直挂在这个页面上一直执行着,因此需要一个进程管理器去管理这个进程,supervisor横空出世。关于supervisor的介绍请参考 http://www.supervisord.org官网。
安装supervisor
yum install supervisor -y 写supervisor的配置文件
supervisor的默认配置文件是
/etc/supervisord.conf,其中配置的加载配置设置为
[include]files = supervisord.d/*.ini
从配置可以看出,只要是
/etc/supervisord.d/ 目录下所有以ini结束的文件都会额外加载。
将示例的进程写到配置文件
/etc/supervisord.d/process.ini
[root@demo1 /data1/code/process]# cat /etc/supervisord.d/process.ini[program:process]command=php /data1/code/process/process.php stdout_logfile=/tmp/process.log autostart=true autorestart=true startsecs=5 priority=3 stopasgroup=true killasgroup=true
启动supervisord
[root@demo1 /data1/code/process]# supervisord /usr/lib/python2.7/site-packages/supervisor/options.py:296: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security. 'Supervisord is running as root and it is searching '
看进程列表和状态
[root@demo1 /data1/code/process]# supervisorctl statusprocess RUNNING pid 426, uptime 0:00:08
可以看到进程已经启动。
查看输出日志
如supervisor的配置文件中设置,将日志定位到了 /tmp/process.log
[root@demo1 /data1/code/process]# tail -f /tmp/process.log当前 IP:123.125.23.213 来自:北京市 联通Now: 2018-08-03 10:45:35 当前 IP:123.125.23.213 来自:北京市 联通Now: 2018-08-03 10:45:45 当前 IP:123.125.23.213 来自:北京市 联通Now: 2018-08-03 10:46:00 Now: 2018-08-03 10:46:11 当前 IP:123.125.23.213 来自:北京市 联通
可以看到,日志确实是输出了。
注意:容器的本地文件系统大小是有限制的,你可以将日志的输出写到stdout,这样新浪云的容器管理进程会接管你输出的日志,这样从日志中心就可以查看。
稍微修改一下supervisor的配置
/etc/supervisord.d/process.ini
[root@demo1 /data1/code/process]# cat /etc/supervisord.d/process.ini[program:process]command=php /data1/code/process/process.php stdout_logfile=/proc/1/fd/1 stderr_logfile=/proc/1/fd/2 stdout_logfile_maxbytes=0 stderr_logfile_maxbytes=0 autostart=true autorestart=true startsecs=5 priority=3 stopasgroup=true killasgroup=true
重启supervisor
supervisorctl reload
注意:修改了配置supervisor配置文件需要使用reload重启supervisord进程,如果是修改了PHP代码,使用
supervisorctl restart process即可,如果重启所有进程,使用supervisorctl restart all将日志写到 /proc/1/fd/1 这个路径即可。为什么需要配置stdoutlogfilemaxbytes,
请参考
https://stackoverflow.com/questions/25195880/supervisord-redirect-process-stdout-to-console。
现在从管理面板的日志中心就可以看到日志了,这样日志文件就不会占用容器的磁盘,如图:
MySQL has gone away的问题
在从写PHP的接口到写PHP的进程时基本所有人都会遇到这个错误:
MySQL error 2006: mysql server has gone away
这个是一个很常见的问题,而且不算是系统的bug,因为MySQL的服务器为了确保能及时回收无用的连接,设定了这个参数,即客户端连上MySQL后过了N秒没有任何活动,MySQL就主动断开连接,客户端再用这个连接去查询数据,就会报这个错误,在新浪云的共享型MySQL上,这个N是30秒,且不可修改。
因此客户端需要自己处理这个错误,怎么处理呢?其实很简单,就是执行完sql后判断下错误码,如果是2006,就重新连接MySQL,然后再执行一下sql即可。
以MySQL扩容为例,伪代码是这样的:
$link = mysql_connect(主机:端口,用户名,密码);mysql_select_db(数据库名, $link); $ret = mysql_query("SQL语句", $link);if (!$ret && mysql_errno($link) == 2006) { // 重新连接 $link = mysql_connect(主机:端口,用户名,密码); mysql_select_db(数据库名, $link); $ret = mysql_query("SQL语句", $link);}
注意:以上是伪代码描述,不能直接使用,实际使用中请结合你的MySQL操作封装修改逻辑。返回搜狐,查看更多
责任编辑: