crontab并发文件锁的使用
这是学习笔记的第 1907篇文章
前几天在做任务时间调度的时候,写了一个Shell脚本,是通过脚本来操作corntab的配置,在修改之前会做备份,文件是crontab_bak_file,然后修改配置,生成文件crontab_bak_file_tmp。看起来是一个操作可控的脚本了。但是在执行批量的任务调度时,发现事情远比想象的复杂。
本来是想crontab的修改频率不高,结果有一批实例是单机多实例,在调度的时候,可能在同一时间会有一批任务进来,会对同一台服务器的crontab产生并发的变更操作,结果上一次操作还没完,下一次操作的文件就会覆盖上一次的,最后导致变更结果不稳定,有一部分变更会被覆盖,从crontab -l的结果来看,是一些变更没有生效。
这里我们需要引入一种机制,即文件锁,这种操作其实和MySQL实例管理是类似的,如果存在一个lock文件,则不可以重复启停已存在的实例,属于保护机制,对于crontab的并发操作而言,这种情况是确实需要的。
Linux中本身有文件锁的支持,一般是和命令结合起来。这里不能原生调用,我们需要做一些转换。最后的实现可以举个通俗的例子,就好比一批人要通过一条河,只有一个独木桥,一次只能一人通过,那么我们就需要锁定一下,其他人只能等待,等待的时间周期是4秒钟,那么多个并发的执行时间可能是4秒钟,可能是10几秒钟。
部分代码参考如下,我对已有的逻辑也持续做了改进,保留了一些之前的代码,供参考。
cur_date=`date "+%Y%m%d_%H%M%S"`
crontab_bak_file="${bak_path}/crontab_${cur_date}.bak"
crontab_bak_file_tmp="${bak_path}/crontab_tmp_${cur_date}"
# 创建crontab任务函数
function create_crontab()
{
#if [ -f ${crontab_bak_file_tmp} ]; then
# sleep 1;
#else
${echo} > ${crontab_bak_file_tmp}
${crontab} -l > ${crontab_bak_file_tmp} 2>/dev/null
#fi
lock_flag=`flock -x ${crontab_bak_file_tmp} -c "sleep 2;echo 1"`
# echo $a
if [ $lock_flag == '1' ];then
task_command=$task_command" 2>&1 & ""#${task_code}"
#echo $task_command
crontab_task="${minute} ${hour} * * * ${task_command}"
if [ -f ${crontab_bak_file} ]; then
echo 'ok';
else
${crontab} -l > ${crontab_bak_file} 2>/dev/null
fi
# 要添加的crontab任务
jobcontent=`${grep} -w "${task_code}" ${crontab_bak_file_tmp}`
if [ ! -n "${jobcontent}" ];then
#${sed} -i "/.*xtrabackup_innodb_full_v6/d" ${crontab_bak_file_tmp} # 已存在任务时会被sed删除,防止重复添加
${echo} "${crontab_task}" >> ${crontab_bak_file_tmp}
crontab ${crontab_bak_file_tmp}
logEntry 'Job complete'
else
${sed} -i "/.*${task_code}/d" ${crontab_bak_file_tmp} # 已存在任务时会被sed删除,防止重复添加
#${sed} -i "/.*xtrabackup_innodb_full_v6/d" ${crontab_bak_file_tmp} # 已存在任务时会被sed删除,防止重复添加
${echo} "${crontab_task}" >> ${crontab_bak_file_tmp}
crontab ${crontab_bak_file_tmp}
logEntry 'Job complete'
fi
fi
}
相关链接: