linux查看占用端口程序 结束掉进程

前言

在OS X中使用GAE引擎来科学上网比如goagent或者wallproxy,可能会在启动过程中出现如下报错然后导致服务启动不成功。

原因

其实就是因为你曾启动过相同或者类似的服务占用了这个端口,一般来讲,在Mac上直接用Python启动的话,会导致退出不完整,你不能通过点击GUI的“退出”按钮来一步到位,后台的Python进程还是存在的,而它就是一直占用端口不释放的元凶。

解决办法

一个是改掉默认的80878086端口,另一个,就是干掉占用端口的程序。

前者立竿见影,但缺点是你总不能一天换一个的吧,如果说是因为其他应用占用端口还好说,那要是因为退出不完整呢?所以,后者才是治标治本的解决办法。但是想要找到这个占用端口的程序,就要引入下面的内容了:

lsof命令

简介

lsof(list open files)命令是一个列出当前系统打开文件的工具。在类UNIX环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。所以我们使用它来找出占用了端口的程序,看看它究竟是不是冲突是不是错误。

lsof -i 用以显示符合条件的进程情况

所以,我们使用如下命令即可查找出占用了某个端口的程序和其对应的PID

然后使用下面的命令干掉对应的进程:

替代crontab,统一定时任务管理系统cronsun简介

摘 要

cronsun 是一个分布式任务系统,单个节点和 Linux 机器上的 crontab 近似。是为了解决多台 Linux  机器上 crontab 任务管理不方便的问题,同时提供任务高可用的支持(当某个节点死机的时候可以自动调度到正常的节点执行)。支持界面管理机器上的任务,支持任务失败邮件提醒,安装简单,使用方便,是替换 crontab 一个不错的选择。

替代crontab,统一定时任务管理系统cronsun简介

 

一、背景

crontab 是 Linux 系统里面最简单易用的定时任务管理工具,相信绝大多数开发和运维都用到过。在咱们公司,很多业务系统的定时任务都是通过 crontab 来定义的,时间长了后会发现存在很多问题:

  • 大量的 crontab 任务散布在各台服务器,带来了很高的维护成本
  • 任务没有按时执行,甚至失败了很久才发现,需要重试或排查
  • crontab 分散在很多集群上,需要一台一台去看日志分析,头都大了
  • crontab 存在单点问题,对于不能重复执行的定时任务很伤脑筋
  • 我 X,crontab 被误删了,没备份?尼玛!
  • 我 Q,服务器要迁移,crontab 上的历史任务都是什么鬼?问了一圈居然都不知道

因此,我们非常需要一个集中管理定时任务系统,相信这也是的饱受 crontab 煎熬的运维或开发的心声。

二、选择

我们部门的开发人力一直都非常紧张,所以靠自己开发一套完善的定时任务管理系统不太现实。因此,希望找一个开源的系统来快速满足需求。

期间,我在网上看了不少相关文章,比如 http://ju.outofmemory.cn/entry/221885

发现这些系统对于我们的实际场景来说都过于臃肿,不太合适。偶然在 github 找了一个基于 Go 语言开源的定时任务集中管理系统—gocron,发现非常轻量,于是试用了一段时间。

不过最终我还是放弃了,因为 gocron 存在单点问题,项目地址:https://github.com/ouqiang/gocron

期间和作者有过一段时间的交流,提了不少改善建议,在和 gocron 作者交流期间,他针对我提到的单点问题,推荐了另一个开源项目:cronsun,也就是本文介绍的主角,通过试用,发现非常契合我们当前的使用场景,介绍如下:

cronsun 是一个分布式任务系统,单个节点和 Linux 机器上的 crontab 近似。是为了解决多台 Linux  机器上 crontab 任务管理不方便的问题,同时提供任务高可用的支持(当某个节点死机的时候可以自动调度到正常的节点执行)。支持界面管理机器上的任务,支持任务失败邮件提醒,安装简单,使用方便,是替换 crontab 一个不错的选择。

Github 地址:https://github.com/shunfei/cronsun

cronsun 的部署架构如下:替代crontab,统一定时任务管理系统cronsun简介

三、部署

本文主要介绍功能,这里就简单写下关键步骤:

1、安装 MongoDB,强烈建议使用集群模式

2、安装 Etcd3,强烈建议使用集群模式

3、部署 cronsun

①、下载 cronsun:https://github.com/shunfei/cronsun/releases  (选择最新版本即可)

②、解压后修改 conf 目录下的配置文件:db.json 和 etcd.json,分别修改 MongoDB 和 etcd 的实际地址。

③、启动 web:./cronweb -conf conf/base.json (若要后台运行则使用 nohup)

④、启动 node:./cronnode -conf conf/base.json (若要后台运行则使用 nohup)

⑤、访问前台:http://x.x.x.x:7079/ui/

4、部署鉴权组件 aProxy,cronsun 在鉴权方面做的非常粗糙,所以这里用到了 cronsun 团队开发的 aProxy 鉴权组件,实现的原理为基于 Go 语言,反向代理了后端 WEB,从而实现域名和页面地址的访问控制,介绍地址:https://www.cnblogs.com/QLeelulu/p/aproxy.html

我们这边是要用到生产环境,所以在部署上会着重考虑到可用性和可靠性,这里贴一下我们这边的部署架构图,供参考:
替代crontab,统一定时任务管理系统cronsun简介

Ps:目前新版本已支持历史日志定期清理。

这里,Etcd 和 MongoDB 复用了 5 台服务器(后续会继续复用其他公共组件),其中 MongoDB 采用分片+副本集的模式。

四、功能

部署完成后,访问前台就能看到 UI 比较简陋 cronsun 管理 WEB 了:
替代crontab,统一定时任务管理系统cronsun简介

Ps:右上方选择熟悉的语言之后,基本就可以按照页面标签进行任务添加操作了。

1、添加节点

cronsun 基于 etcd 实现了自动发现和注册的功能,所以添加节点非常简单,直接将 cronnode 和 conf 拷贝到客户端服务器启动之后,就能在前台->节点页面看到该服务器了,当然节点和 Etcd 以及 MongoDB 之间的网络必须畅通。替代crontab,统一定时任务管理系统cronsun简介

2、节点分组

添加了所需的节点服务器之后,我们可以将节点进行分组,从而方便定时任务的添加:替代crontab,统一定时任务管理系统cronsun简介

3、添加任务

节点和分组都搞定之后,我们就可以开始添加定时任务了。定时任务填写的信息略微复杂,不过按照提示还是可以轻松搞定的:替代crontab,统一定时任务管理系统cronsun简介

上图我简单的标注了一些需要特别说明的地方,其他的选项大家看中文描述都能自行搞定。当然,还有一点要说明的是,任务脚本必须要有执行权限,否则任务会执行失败。

4、任务列表

添加完成任务之后,在任务标签页就能看到所有添加的定时任务以及执行情况了,这里可以使用分组过滤或节点过滤来筛选关心的任务。替代crontab,统一定时任务管理系统cronsun简介

每一个任务的右侧有 3 个小按钮:

①、成功/失败:显示最近一个任务的执行是成功还是失败,点击后可以查看到任务详情,包括任务输出数据:替代crontab,统一定时任务管理系统cronsun简介

②、latest 按钮:点击后查看改任务的近期执行情况

③、刷新符号按钮:点击后可以弹出立即执行功能,方便调试任务替代crontab,统一定时任务管理系统cronsun简介

五、小结

通过一段时间的灰度试用,可以确定 cronsun 在中小型规模场景下,是 crontab 的一个比较好的替代品,它能够帮助运维人员脱离 crontab 难管理、难运维的苦海。

当然,作为一款开源产品,cronsun 很多功能细节还有很大的提升空间,目前我也和 cronsun 团队长期保持联系,将生产环境使用过程中遇到的一些问题和建议一一反馈,相信这款产品能够继续打磨优化,更加完善、完美。

六、问题及更新【持续】

问题记录:

1、告警配置

首先要清楚 cronsun 的告警是由 cronweb 发出的,而不是 cronnode(但是 cronnode 的 mail.json 也必须 Enable:true,否则还是无法发出告警)。

其次,编辑 cronweb 和 cronnode 的配置文件:mail.json,如下内容

Ps:LocalName 建议留空,HttpAPI 模式未使用到,这里省略之,请自行测试。

最后启动 cronweb 即可实现邮件告警。

当然, 还需要在 web 上的单向任务界面开启告警才行,如下图所示:替代crontab,统一定时任务管理系统cronsun简介

Ps:cronweb 的 mail.json 配置中必须将 Enable 填为 true 才可以看到上图的告警开关按钮,否则不显示。

2、更新记录

详见 github 版本发布页面:https://github.com/shunfei/cronsun/releases

重要功能更新:

①、已支持脚本参数;

②、已支持历史日志定期清理;

③、3.1 版本开始使用 UUID 作为节点唯一标识。

 

 

https://zhangge.net/5129.html

linux centos 查看系统版本

查看系统版本

cat /etc/os-release

查看内核版本

方法1:

[root@linuxidc ~]# cat /proc/version
Linux version 3.10.0-327.18.2.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Thu May 12 11:03:55 UTC 2016

方法2:

[root@linuxidc ~]# uname -a
Linux linuxidc 3.10.0-327.18.2.el7.x86_64 #1 SMP Thu May 12 11:03:55 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

lnmp添加fileinfo扩展

开始编译

cd /root/oneinstack/src
tar zxvf php-5.6.20.tar.gz  # 解压已经安装的php版本
cd php-5.6.20/ext/fileinfo
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install
cd /usr/local/php/lib/php/extensions
ls  #看到no-debug-non-zts-20131226类似文件夹
cd no-debug-non-zts-20131226
ls  #查看有没有 fileinfo.so,如果有,证明编译成功
加载fileinfo
echo 'extension=fileinfo.so' > /usr/local/php/etc/php.d/ext-fileinfo.ini

lnmp为何没有fileinfo扩展

https://www.cnblogs.com/wamptao/p/6100534.html

如何查看已安装的CentOS版本信息

如何查看已安装的CentOS版本信息

1)[root@localhost ~]# cat /proc/version

Linux version 2.6.18-194.el5 (mockbuild@builder10.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)) #1 SMP Fri Apr 2 14:58:14 EDT 2010

2)

[root@localhost ~]# uname -a

Linux localhost.localdomain 2.6.18-194.el5 #1 SMP Fri Apr 2 14:58:14 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux

3)

[root@localhost ~]# uname -r

2.6.18-194.el5

2. 查看linux版本:

1) 列出所有版本信息,

[root@localhost ~]# lsb_release -a

LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch

Distributor ID: CentOS

Description:    CentOS release 5.5 (Final)

Release:        5.5

Codename:      Final

注:这个命令适用于所有的linux,包括RedHatSUSE、Debian等发行版。

2) 执行cat /etc/issue,例如如下:

[root@localhost ~]# cat /etc/issue

CentOS release 5.5 (Final)

Kernel r on an m

3) 执行cat /etc/redhat-release ,例如如下:

[root@localhost ~]# cat /etc/redhat-release

CentOS release 5.5 (Final)

查看系统是64位还是32位:

1、getconf LONG_BIT or getconf WORD_BIT

[root@localhost ~]# getconf LONG_BIT

64

2、file /bin/ls

[root@localhost ~]# file /bin/ls

/bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped

3、lsb_release  -a

[root@localhost ~]# lsb_release -a

LSB Version:    :core-3.1-amd64:core-3.1-ia32:core-3.1-noarch:graphics-3.1-amd64:graphics-3.1-ia32:graphics-3.1-noarch

Distributor ID: CentOS

Description:    CentOS release 5.5 (Final)

Release:        5.5

Codename:      Final

4、或者是使用查看文件的方法。

vim /ect/issue

更多CentOS相关信息见CentOS 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=14

本文永久更新链接地址http://www.linuxidc.com/Linux/2014-12/110748.htm

LNMP 1.4教程及注意事项和多PHP版本使用教程

LNMP 1.x版本基本都可以正常升级到1.4使用1.4的管理脚本和新的功能。

升级管理脚本:wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz && tar zxf lnmp1.4.tar.gz && cd lnmp1.4 && ./upgrade1.x-1.4.sh
有些功能是需要另外升级nginx、php版本或安装多php版本的,下面会进行单独的说明。

新的功能主要是两个添加SSL和多PHP版本选择。

添加SSL:

添加SSL有两种方式可以选择,1是自备证书和key,这个不需要多说,按提示分别填写上证书和key的完整路径和名称。2是使用Let’sEncrypt生成3个月有效期的SSL证书,另外按提示一个邮箱就可以。

已经添加过改域名的http站点,添加https站点直接运行:lnmp ssl add 按提示添加,可以参考新添加教程的提示说明。

新添加虚拟主机按:https://lnmp.org/faq/lnmp-vhost-add-howto.html

注意1:添加的SSL虚拟主机是默认http2的,如果是之前的版本未使用openssl 1.0.2进行编译或者Nginx低于1.9的话,建议升级到1.12.0,使用升级脚本:./upgrade.sh nginx 进行升级。
注意2:如果是对已有主机添加SSL,因为之前的1.3版本默认LNMP的虚拟主机里是禁止 . 开头的隐藏文件及目录的,所以访问http://abc.com/.well-known/acme-challenge/**** 这个链接的话返回403错误,所以必须要将对应虚拟主机配置文件里的
location ~ /\.
{
deny all;
}
这段配置删掉或注释掉或在这段配置前面加上
location ~ /.well-known {
allow all;
}
修改保存后重启nginx。
注意3:https网站里面的js、css、图片等资源的引用必须是https的,如果是http的会提示不安全也没有小绿锁。需要自行修改网站模板、网站内容里的图片等为https连接或者直接使用相对路径引用。

多PHP版本使用教程:
多PHP版本只支持LNMP模式,LNMPA、LAMP模式下不支持!
要使用多PHP先安装多PHP版本,在lnmp1.4源码目录下运行:./install.sh mphp 按提示选择要另外安装的PHP版本,不能多选,只能选一个,要安装多个需要安装完成后再运行前面的安装命令。
已经升级完LNMP管理脚本且已安装好多PHP版本的话,lnmp vhost add 时会在设置完日志名称后提示当前已经存在的PHP版本,按提示的数字选择就可以。

如果已经存在的虚拟主机要更改PHP为指定版本需要修改虚拟主机的配置文件,配置文件为 /usr/local/nginx/conf/vhost/域名.conf ,将里面的include enable-php.conf; 替换为 include enable-php7.1.conf; 前面的7.1为php版本,可以根据自己的需要进行修改,但必须要对应的多php版本已经安装,要不然会提示502错误。

修改后必须要重启nginx,否则无法生效。

如要使用新版里面的PHP模块组件安装工具需要升级一下PHP才能使用新版PHP组件安装工具。

多PHP版本PHP模块/组件
多PHP模块安装依然和以前一样只不过存在多PHP版本时会让你选择为哪个版本的PHP安装PHP模块/组件,教程参考:https://lnmp.org/faq/addons.html

 

https://lnmp.org/faq/upgrade1-4.html

crontab从入门到出坑

此篇技术博文主要介绍的是crontab,Linux下的计划任务管理工具。涉及内容包括crontab使用配置、常见坑的分析和编者总结的错误调试方法。非标题党文章,真正地帮您从入门到出坑。

category.png

我的理解,后台任务通常分为两种:常驻和定时。之前的文章《pm2进程管理工具使用总结》主要针对的是常驻任务。今天来谈谈crontab,主要针对的是定时任务。

实验环境:centos7

介绍crontab

crontab的服务进程名为crond,英文意为周期任务。顾名思义,crontab在Linux主要用于周期定时任务管理。通常安装操作系统后,默认已启动crond服务。crontab可理解为cron_table,表示cron的任务列表。类似crontab的工具还有at和anacrontab,但具体使用场景不同,可参见附录《让你学会Linux计划任务》一文了解更多。

关于crontab的用途很多,如

  • 定时系统检测;
  • 定时数据采集;
  • 定时日志备份;
  • 定时更新数据缓存;
  • 定时生成报表;

    等等任务

当然,更多使用场景是要以视具体情况而定了。毕竟是工具通常都是常用规则总结而成的产物。

确认crond服务已经安装与开启之后,下面开始具体说明

简单示例

先来个简单示例体验一下。

  • 目标:每分钟向/tmp/time.txt文件下写入当前时间
  • 新建crontab任务
    $ crontab -e      // 打开crontab任务编辑
    * * * * * date >> /tmp/time.txt
  • 静静等待几分钟
    $ cat /tmp/time.txt
    Do 29. Dez 22:45:01 CST 2016
    Do 29. Dez 22:46:01 CST 2016
    Do 29. Dez 22:47:01 CST 2016
  • 从上面结果看出,每分钟执行了date并写入到/tmp/time.txt。

简单示例演示成功。下面从细节深入说明crontab使用。

使用选项

上面的实验中使用了crontab命令的-e选项。我们来看看crontab命令中有哪些选项?

  • -e 选项 表示打开当前用户的crontab任务列表配置文件。当然也可以直接打开,路径通常是在/var/spool/cron/下,文件以用户名命名,如/var/spool/cron/root。不过,采用-e方式打开,福利是可以帮助我们自动检查任务配置符合规则。
  • -u 选项 指定某用户的任务列表,很好理解。比如我当前是root用户,想操作poloxue用户的任务列表。如下:
    $ crontab -u poloxue -e
  • -l 选项 列出某用户的所有任务列表
  • -r 选项 删除某用户的所有任务列表,这个选项使用小心为上,估计也只是自己实验时玩玩而已,正常不使用。

crontab命令的选项中,主要使用的就是以上几个,理解比较简单。

任务配置

说完了crontab的命令选项,下面开始真正的大戏,任务列表文件如何配置?

首先,看下crontab任务列表配置格式,示例文件如下:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# 更多细节 man 4 crontabs

# 计划任务定义的例子:
# .---------------- 分 (0 - 59)
# |  .------------- 时 (0 - 23)
# |  |  .---------- 日 (1 - 31)
# |  |  |  .------- 月 (1 - 12)
# |  |  |  |  .---- 星期 (0 - 7) (星期日可为0或7)
# |  |  |  |  |
# *  *  *  *  * 执行的命令
* * * * * date >> /time.txt 2>&1

从上面的示例文件可看出,crontab的任务列表主要由两部分组成:环境变量配置与定时任务配置。可能大家在工作中更多是只用到了任务配置部分。

环境变量配置部分

理解环境变量配置这部分可以帮助我们减少去踩一些不必要的坑。简单说明上面涉及的环境变量。

  • SHELL为/bin/bash,表示使用/bin/bash解释执行命令
  • PATH表示到哪些目录路径寻找命令程序,此环境变量的值说明了为什么我们在crontab中执行命令时,尽量要写命令全路径才能执行的原因。
  • MAILTO变量作用是当任务执行有输出时,内容发送到哪个用户的邮箱。禁用可以设置MAILTO=””。

当我们在使用crontab时,发现某些定时任务不能顺利执行,但shell控制台执行成功,环境变量是否正确是我们需要首先关注的点之一。具体详情可以看后面关于环境变量坑的说明。

定时任务配置部分

这部分是crontab配置核心。

  • 基本配置
    如下所示配置共6列,前5列是关于执行时间配置,最后1列是具体执行命令。

    .---------------- 分 (0 - 59)
    |  .------------- 时 (0 - 23)
    |  |  .---------- 日 (1 - 31)
    |  |  |  .------- 月 (1 - 12)
    |  |  |  |  .---- 星期 (0 - 6) (星期日可为0或7)
    |  |  |  |  |
    *  *  *  *  * 执行的命令

    第一列单位为分,表示每时第几分钟,范围为0-59;
    第二列单位为时,表示每天第几小时,范围为0-23;
    第三列单位为日,表示每月第几天,范围为1-31;
    第四列单位为月,表示每年第几月,范围为1-12;
    第五列单位为星期,表示每星期第几天,范围0-7,0与7表示星期日,其他分别为星期1-6;

  • 时间配置段类型
    根据时间列中值的不同设置方式,编者总结出以下五种类型:

    固定某值,指定固定值,如指定1月1日0时0分执行任务

    0 0 1 1 * command

    月日时分都指定了固定数值。

    <font color=red>注:*在crontab中表示任意值都满足条件。</font>

    列表值,时间值是一个列表,如指定一个月内2、12、22日零时执行任务

    0 0 2,12,22 * * command

    上述日指定多个值,2号、12号和22号,以逗号分隔;

    连续范围值,时间为连续范围的值,如指定每个月1至7号零时执行任务

    0 0 1-7 * * command

    上述日期为连续范围的值1-7时

    步长值,根据指定数值跳跃步长确定执行时间,如指定凌晨1时开始每割3个小时0分执行一次任务

    0 1-24/3 * * * command

    上述指定从凌晨1时每3个小时执行任务,如1点0分,4点0分,7点0分等。

    混合值,支持以上类型的组合,如指定每小时0至10分,22、33分以及0-60分钟每隔20分钟执行任务,如下

    0-10,22,33,*/20 * * * * command

    这里的分钟值采取了多种类型组合指定,包括连续范围值(0-7),列表值(22,33),步长值(*/20)。

    <font color=red>声明:这几种时间配置类型是编者自己总结,希望能帮助大家更好理解。有错误帮忙指出。</font>

定时语句解析工具

通常在使用crontab添加任务时,我们会依靠自己已有知识编写定时语句。当需要测试语句是否正确时,总需要一定时间等待证明其正确性。作为一名牛逼的程序员,这种方式就太不酷了。有没有一款工具,只要我们给出语句,其就能告诉具体执行时间呢?下面介绍一款老外开发的crontab在线解析工具。

工具地址:https://crontab.guru

下面是这个工具的截图

crontab_tool.png

从上面看出,我们输入的语句解析结果为每天的04:05执行任务。下面有这样一行文字“next at 2016-12-31 04:05:00”,告诉了我们最近一次的执行时间。

<font color=red>注明:百度搜索“crontab在线解析”获得的工具有坑,某些语句解析结果错误。为避免大家受骗,这里提供具体地址:http://tool.lu/crontab/</font>

使用有坑

crontab使用中常会遇到各种坑。下面列出编者在使用中曾遇到的一些问题。

时间配置误区

此处介绍两种坑,一种是由于基本功不足导致配置错误,而另一种则是多数人对crontab配置都存在的一个理解误区。

  • 整点时间设置错误
    其实这个错误不用单独说明,但是编者刚开始接触crontab时犯过,单独拿出来说明一下。

    如设定每天3点执行一次某任务
    下面列出错误方式,当我们听到每天3点执行一次某任务时,很多人会把重点放在3点,而忽略了执行一次的需求。

    下面是个错误的例子

    * 3 * * * command

    这里会导致在三点的每分钟都会执行一次任务,也就是执行了60次。
    正确方式如下,每天3点0时执行任务

    0 3 * * * command
  • 日与星期的关系误区
    这真的是个大误区,很多人都不知道的大误区。直接开始说明吧。

    好,首先做两个练习

    设置任务一:每月的1-7每天零时执行某任务,答案如下:

    0 0 1-7 * * date >> /tmp/date.txt

    设置任务二:每星期的星期一零时执行某任务,答案如下:

    0 0 * * 1 date >> /tmp/date.txt

    上面两个任务的设定都是正确的。
    下面提出第三个任务,设置每个月的第一个星期一零时执行某任务
    分解任务要求,首先,第一个星期就是每个月的1-7日,而星期一就是星期一。所以我们理解的crontab任务配置如下

    0 0 1-7 * 1 date >> /tmp/date.txt

    下面直接使用前面介绍的在线解析工具分析此语句,如下

    crontab_time.png

    解析结果显示语句执行时间为每月的1至7日和每星期一。可以看到最近执行时间是“next at 2017-01-01 00:00:00”,这个时间也并非星期一。

    这是crontab的一个特别容易误解之处,下面直接给出结论:

    当日和星期任一列包含时,日与星期两者为并且的关系;
    当日和星期列中不包含
    时,日与星期两者为或者的关系;

<font color=red>请注意,前面提到的那个百度搜索出来的工具分析结果显示的确是每月第一个星期一,这是错误的。如有朋友持怀疑态度,可自行验证,如有错误,随时告知。</font>

环境变量问题

当我们刚使用crontab时,有人会告知所有命令尽量都使用绝对路径,以防错误。为什么?这就和我们下面要谈的环境变量有关了。

  • 首先,获取控制台环境变量看下
    $ env
    XDG_SESSION_ID=10
    HOSTNAME=localhost.localdomain
    SHELL=/bin/bash
    PERL_MB_OPT=--install_base /root/perl5
    USER=root
    MAIL=/var/spool/mail/root
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php5/bin
    PWD=/var/mail
    SHLVL=1
    HOME=/root
    LOGNAME=root
    XDG_RUNTIME_DIR=/run/user/0
    _=/usr/bin/env

    <font color=red>考虑篇幅,输出有删减。</font>

  • 然后,获取crontab环境变量信息
    * * * * * /usr/bin/env > /tmp/env.txt

    输出结果,如下

    $ cat /tmp/env.txt
    XDG_SESSION_ID=732
    SHELL=/bin/sh
    USER=root
    PATH=/usr/bin:/bin
    PWD=/root
    LANG=de_DE.UTF-8
    SHLVL=1
    HOME=/root
    LOGNAME=root
    XDG_RUNTIME_DIR=/run/user/0
    _=/usr/bin/en
  • 对比分析两者输出
    对比crontab与控制台输出,我们发现两者的环境变量差异很大。如果命令在控制台执行成功,而在crontab执行失败,我们需要考虑是否命令涉及的环境变量在crontab和控制台间存在差异。
  • 明白crontab使用绝对路径执行命令原因了吗?
    我们知道命令默认查找路径是由PATH指定的。

    从上面输出结果可知,控制台的PATH值为

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin

    crontab的PATH值为

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/php/bin

    crontab的PATH值为

    PATH=/usr/bin:/bin

    /usr/local/php/bin/下面存在php命令,在控制台执行成功

    $ php index.php

    因在crontab的PATH变量无/usr/local/php/bin/,其执行php命令则会失败。

  • 解决方式
    已知哪个环境变量导致问题,可以直接在crontab配置中加入变量配置。
    不知哪个环境变量导致问题,终极大招是引入控制台环境变量,如下

    * * * * * source /$HOME/.bash_profile && command

    当然,对于某特定环境变量或有特定的处理方式,如PATH,命令使用绝对路径亦可解决。

特殊符号%

%在crontab是特殊符号,具体含义如下:

  • 第一个%表示标准输入的开始
    * * * * * cat >> /tmp/cat.txt 2>&1 % stdin input

    执行成功之后,查看/tmp/cat.txt

    $ cat /tmp/cat.txt
    stdin input

    我们看到标准输入写入到了/tmp/cat.txt文件。

    <font color=red>理解上面示例,首先需知cat >> /tmp/cat.txt ,作用是将标准输入重定向至/tmp/cat.txt。</font>

  • 其余%表示换行符

    示例如下

    * * * * * cat >> /tmp/cat_line.txt 2>&1 % stdin input 1 % stdin input 2 % stdin input 3

    查看输出

    $ cat /tmp/cat_line.txt
    stdin input 1
    stdin input 2
    stdin input 3

    有三行输出

  • 解决方式

    既然是特殊字符,自然而然就想到了使用\进行转义,如下:

    * * * * * cat >> /tmp/cat_special.txt 2>&1 % per cent is \%. 2>&1

    查看输出

    $ cat /tmp/cat_special.txt
    per cent is %.

    执行成功了。自此,你就顺利爬出了%特殊字符问题的坑。

关于这个问题的具体说明,可以参看附录中的《Crontab and %》。

关于输出重定向

当我们不做输出重定向时,如任务有大量输出,或许有些无法解释的问题。

  • 输出写入邮件
    crontab任务输出默认写入到执行用户的邮件中,如下演示:

    * * * * * date

    命令输出当前日期,下面查看当前用户的邮件

    $ cat /var/spool/mail/$USER
    ...
    
    Sat Dec 31 17:45:01 CST 2016

    由此可见,任务输出的日期信息写入到了用户邮件中。

    如任务有大量输出,会占用磁盘资源。但编者测试显示,如磁盘容量不足,任务也会执行,但输出不会写入邮件;

  • 关闭邮件功能
    如何关闭?设置MAILTO环境变量为空。如下

    MAILTO=""
    * * * * * date

    是不是关闭邮件写入就好了?附录《Linux中的crontab与sendmail》博文表明,关闭mail功能,输出内容将写入到/var/spool/clientmqueue中,可能占满分区的inode资源,导致任务无法执行。inode资源使用情况可通过如下命令获取

    $ df -i
    Filesystem Inodes   IUsed  IFree    IUse% Mounted on
    /dev/sda1  512000   378    511622   1%    /boot
    /dev/sda2  92672000 185351 92486649 1%    /

    抱歉!这种情况编者并未测出!但在公司的生产环境发现过未重定向则任务不执行的情况,加上后解决了问题。百度也搜索到了类似问题,如有朋友了解,欢迎指教,万分感谢。

    当然,为了避免此类问题发生,建议任务都加上输出重定向,如下

    * * * * * date >> /dev/null/ 2>&1

    输出到/dev/null中,标准输入和标准错误都应处理。

    如大家对重定向有疑惑,可参见附录中的《Linux重定向》,对文解释不错。

<font color=red>程序员的感悟:在技术的世界,当我们不按常理做事,事情也不会按常理犯错。</font>

调试大招

最后的福利,编者根据自己的总结而梳理出一套快速定位crontab错误的思路。两个角度:

  • 任务是否执行
  • 命令是否正确
任务是否执行?
  • 调试思路

    首先,通过日志确认任务是否执行
    然后,如未执行则分析定时语句,
    最后,定时没有问题,检查crond服务是否开启

    下面说明具体分析步骤。

  • 日志确认
    调试错误,日志通常是个利器,crontab也有日志。
    编者的服务器中crontab日志文件位置为/var/log/cron

    查看日志
    日志中包含任务执行记录,配置错误提示,任务配置编辑重载记录,服务开启等记录。

    下面是日志的部分内容,

    $ vim /var/log/cron
    ...
    Dec 31 19:17:01 localhost crond[1455]: (CRON) bad day-of-week (/var/spool/cron/root)
    Dec 31 19:17:01 localhost CROND[4409]: (root) CMD (date)
    ...

    这里截取了对调试比较重要的两条记录,如下介绍

    执行记录

    Dec 31 19:17:01 localhost CROND[4409]: (root) CMD (date)

    显示12月21 19时17分1秒执行了date命令

    配置错误

    Dec 31 19:17:01 localhost crond[1455]: (CRON) bad day-of-week (/var/spool/cron/root)

    上面显示/var/spool/cron/root的任务配置有错,也就是root任务配置有错。错误原因:bad day-of-week,星期配置有错。

    语句是这样的

    * * * * date >> /dev/null 2>&1

    明显缺少了星期时间段。

  • 确认定时语句

    通过上面的日志分析,如任务没有执行,使用定时语句在线分析工具分析定时是否正确,非常简单。

  • 确认服务开启
    如果定时语句也正确,检查服务是否开启。检测命令如下

    Systemd方式(centos7及以上)

    $ systemctl status crond.service

    SysVinit方式(centos7以下)

    $ service crond status

    查看命令输出,如未开启,执行如下命令开启

    Systemd方式(centos7及以上)

    $ systemctl start crond.service

    SysVinit方式(centos7以下)

    $ service crond start

确认任务成功后,如问题仍未解决,继续往下看。

命令是否正确

确认命令成功与否,这里总结步骤大致如下

  • 获取命令执行输出
    crontab中的命令执行出错,多数人都不知道如何调试。我们知道在控制台执行命令时,可通过输出获取错误信息调试问题。这种方式在crontab同样适用,方法就是利用重新向获取输出,进行分析。示例如下

    * * * * * php /root/index.php >> /tmp/debug.log 2>&1

    这条任务总是执行失败,我们把输出重定向到/tmp/debug.log。
    查看debug.log,如下

    $ cat /tmp/debug.log
    /bin/sh: php: command not found
    /bin/sh: php: command not found

    显示php命令没有找到,很明显的就可以确定是环境变量的问题。这种方式定位问题非常有效。

  • 具体问题具体分析
    有了命令执行的输出,下面就是具体问题具体分析了。或许是前面提到的各种坑,也或许是命令本身所独有的问题。

调试的方法到这里就说完了。但还是实践为王,需持续总结,同时也希望大家不要在同样的坑中重复犯错。


作者:波罗学
链接:http://www.jianshu.com/p/8bf8f6529108
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。