fpsync - 脚本的学习

前言

fpsync是基于fpartrsync包装的一个迁移工具,由shell脚本编写。

fpsync底层利用原生的rsync来做数据的备份工作,利用fpart来做待备份目录的解析。

源码的实现上,整体逻辑非常清晰,分为了两大部分。一部分:用来做参数的解析和环境合法性检测;另一部分:结合fpartrsync来做备份操作,由多个备份作业同时进行

下面,主要介绍fpsync做多个作业并发备份的实现思想。

fpsync

首先介绍fpartrsync的基本使用,以及两个第三方工具必须依赖的参数信息。

一、 rsync
fpsync内部原生的rsync备份命令。

# 不使用-r参数,代表只拷贝单个文件
# 1. -l 链接 -p 权限 -t 时间 -g 属组 -o owner -D same as --devices --specials
# 2. 打印详细信息
# 3. don't map uid/gid values by user/group name
$ rsync -lptgoD -v --numeric-ids /mnt/Rsync-src /mnt/Rsync-dest

二、fpart
fpsync内部原生的fpart切分目录命令。

# 进入到待备份目录中
# -o ${FPART_PARTSTMPL} fpart生成的打包文件放置的共享目录位置
# -0 如果使用-o选项,那么在每一个生成的文件末尾后面添加/
# -e 在目录中添加/
# -L 启动实时模式
# -W 调用回调函数
# ${FPART_POSTHOOK} 执行rsync的回调函数
$ cd /mnt/Rsync-dest 
$ fpart -o ${FPART_PARTSTMPL} -0 -e ${OPT_FPART} ${FPART_MODEOPTS} -L -W ${FPART_POSTHOOK} .

若需要,在fpart解析目录的同时并发执行rsync,做多个任务迁移工作。可以使用如下方法:

fpart -L -f 10000 -x '.snapshot' -x '.zfs' -zz -o /tmp/part.out -W \
'/usr/local/bin/sem -j 3 "rsync -av --files-from=${FPART_PARTFILENAME}" /mnt/Rsync-source/ /mnt/Rsync-dest/'

而在fpsync脚本中,相对使用了温文尔雅的方式替换了parallel,来实现并发。

fpsync代码逻辑

fpsync后台拥有了2个进程,一个是fpart负责将待备份的目录进行解析,并将备份作业放入到作业队列中;另一个是job_queue_loop,取出作业队列备份作业来执行真正的备份。

fpsync流程图
fpsync默认情况下,会在/tmp/fpsync目录下放置4个子文件夹,来存储备份作业的信息。

$ pwd
/tmp/fpsync
$ ll
total 0
drwxr-xr-x. 3 root root 30 Dec  8 00:08 log				# 主进程日志
drwxr-xr-x. 3 root root 30 Dec  8 00:08 parts           # fpart解析目录生成的bag
drwxr-xr-x. 3 root root 30 Dec  8 00:08 queue			# 存放备份任务的任务队列
drwxr-xr-x. 3 root root 30 Dec  8 00:08 work            # 已经执行和正在执行备份任务的信息
几个主要函数

一、主函数,启动job_queue_loopfpart

# 1. 启动进程job_queue_loop,等待queue中的备份任务
job_queue_loop&		
# When not resuming a previous job, start fpart
# 不是恢复先前的工作,则开始fpart

# 2. 启动进程fpart, 用来解析源目录卷,并生成待备份任务放置到queue中。
# 重点是,-W回调中,实际是将待备份rsync的命令重定向到queue中
if [ -z "${OPT_JOBNAME}" ]
then
    echo_log "1" "===> Analyzing filesystem..."
    # Start fpart from src_dir/ directory and produce jobs within
    # ${JOBS_QUEUEDIR}/

    #echo "FPART_LOGFILE: ${FPART_LOGFILE}"
    #echo "OPT_FPMAXPARTFILES ${OPT_FPMAXPARTFILES}"    ===> 2000
    #echo "FPART_PARTSTMPL ${FPART_PARTSTMPL}"          ===> /tmp/fpsync/parts/16ID/part
    #echo "FPART_BIN ${FPART_BIN}"                      ===> fpart命令
    # -0  使用选项-o时,文件名以空(\0)字符结尾
    # -e  在目录中添加/
    #echo "FPART_MODEOPTS ${FPART_MODEOPTS}"            ===> -zz

    # -W 将rsync的命令重定向到JOBS_QUEUEDIR/FPART_PARTNUMBER当中
    cd "${OPT_SRCDIR}" && \
        ${SUDO} "${FPART_BIN}" \
        $([ ${OPT_FPMAXPARTFILES} -gt 0 ] && echo -f "${OPT_FPMAXPARTFILES}") \
        $({ { is_num "${OPT_FPMAXPARTSIZE}" && [ ${OPT_FPMAXPARTSIZE} -gt 0 ] ;} || is_size "${OPT_FPMAXPARTSIZE}" ;} && echo -s "${OPT_FPMAXPARTSIZE}") \
        -o "${FPART_PARTSTMPL}" -0 -e ${OPT_FPART} ${FPART_MODEOPTS} -L \
        -W "${FPART_POSTHOOK}" . 2>&1 | \
        tee -a "${FPART_LOGFILE}"
fi

# 3. fpart进程接续,在queue队列中放置fp_done标志fpart结束
# Tell job_queue_loop that crawling has finished
job_queue_fp_done

# Wait for job_queue_loop to terminate
# Use an active wait to allow signal processing (^T)

# 4. 等待所有迁移任务的结束
echo_log "1" "===> Waiting for sync jobs to complete..."
while [ ! -f "${JOBS_QUEUEDIR}/sl_done" ]
do
    sleep 0.2
done

# Display final status
# 展示最终的结束状态
[ ${OPT_VERBOSE} -ge 1 ] && siginfo_handler

二、迁移函数,job_queue_loop

# Main jobs' loop: pick up jobs within the queue directory and start them
# 循环执行job的主函数,查询出队列目录中的jobs然后启动
job_queue_loop () {
    echo_log "2" "===> [QMGR] Starting queue manager"

    # trap 用来捕捉信号
    # Trap SIGINT
    trap 'job_queue_loop_sigint_handler' 2
    # Ignore SIGINFO from within loop, handled by the parent (master) process
    trap '' 29

    # WORK_NUM OPT_JOBS
    # echo "WORK_NUM ${WORK_NUM}"         ===> 0
    # echo "OPT_JOBS ${OPT_JOBS}"         ===> 3
    local _NEXT=""
	# 1. fp_done表示fpart进程结束, sl_stop表示rsync进程结束
	# 补充:_NEXT按照时间倒序读取queue中的文件,所以读到fp_done时,代表所有的备份工作都已经执行完成了
    while [ "${_NEXT}" != "fp_done" ] && [ "${_NEXT}" != "sl_stop" ]
    do
        local _PID=""
        # 2. 当前执行备份作业没有超过上限时,启动一个备份作业
        # OPT_JOBS限制执行rsync的个数
        if [ ${WORK_NUM} -lt ${OPT_JOBS} ]
        then
            # 3. 获取下一个待要执行的任务, 并将备份任务移动到work中
            _NEXT="$(job_queue_next)"
            echo "NEXT ${_NEXT}"
            if [ -n "${_NEXT}" ] && \
                [ "${_NEXT}" != "fp_done" ] && \
                [ "${_NEXT}" != "sl_stop" ]
            then
                # 本地执行
                if [ -z "${OPT_WRKRS}" ]
                then
                    echo_log "2" "=> [QMGR] Starting job ${JOBS_WORKDIR}/${_NEXT} (local)"
                    # 4. 启动备份作业
                    # 后台执行 jobs_workdir下的任务
                    /bin/sh "${JOBS_WORKDIR}/${_NEXT}" &
                    # 后台进程pid 任务名 local 加入到work list中
                    work_list_push "$!:${_NEXT}:local"
                # 忽略,ssh模式 
                else
                    local _NEXT_HOST="$(work_list_pick_next_free_worker)"
                    work_list_trunc_next_free_worker
                    echo_log "2" "=> [QMGR] Starting job ${JOBS_WORKDIR}/${_NEXT} -> ${_NEXT_HOST}"
                    "${SSH_BIN}" "${_NEXT_HOST}" '/bin/sh -s' \
                        < "${JOBS_WORKDIR}/${_NEXT}" &
                    work_list_push "$!:${_NEXT}:${_NEXT_HOST}"
                fi
            fi
        fi
      work_list_refresh
      sleep 0.2
    done

    if [ "${_NEXT}" = "fp_done" ]
    then
        echo_log "2" "<=== [QMGR] Done submitting jobs. Waiting for them to finish."
    else
        echo_log "2" "<=== [QMGR] Stopped. Waiting for jobs to finish."
    fi
    wait
    echo_log "2" "<=== [QMGR] Queue processed"

    # Set the 'sl_done' (sync done) flag to let the master process go
    # 5. 用来标志rsync全部结束
    job_queue_sl_done
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值