环境信息
- 操作系统:
CentOS 7.9
- Bash See:
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)
背景
我正在通过shell 脚本进行S3对象迁移(从curl
迁移到本地Minio端点).
此脚本生成多个工作器(通过后台进程&
),使用FIFO作为作业(job)队列,flock
控制从队列中读取作业(job),然后下载对象,上传对象......等
脚本的一部分如下所示:
# ...
# read params, show info ...
# setting up locks, fifo ...
# define the job() function run by worker.
#
# ...
# the FIFO (job queue) is FD 3
# the FIFO lock is FD 4
function work () {
wid=$1
# setup FD and locks
# ...
while true; do
flock 4 # get the fifo lock
read -r -su 3 job_id obj
read_status=$?
flock -u 4 # release the fifo lock
if [[ $read_status -eq 0 ]]; then
# if read job from queue, run job in a subprocess.
fi
done
# clean up FDs
}
echo "Spawning workers..."
for ((i=1;i<="${WORKERS:-4}";i++)); do
printf "%s" "_"
work $i &
done
echo
function append_job() {
job_id=$1
target_object=$2
printf "\r(%d s) Append job [# %s] %.110s\e[K" "$(( $(date +%s) - ts_start ))" "${job_id}" "${target_object}"
echo "${job_id}" "${target_object}" 1>&3
}
while read -r obj_name ; do
append_job $i "${obj_name}"
i=$((i+1))
done < <(the_function_that_list_all_objects_from_bucket ${TARGET_BUCKET})
echo
遇到的问题
该脚本运行良好,直到一个存储桶的对象超过7,000个(它只追加恰好7,000个作业(job)).
因此,工人们只从一个桶里迁移了7000件物品并完成了工作.
我所期待的
它应该可以毫无问题地完成所有迁移作业(job)(>;7,000).
我认为(可能是错误的):
- 传递给While循环(
<(the_function_that_list_all_objects_from_bucket ${TARGET_BUCKET})
)的stdin会将所有对象的列表存储在内存中的某个位置,目前与FIFO无关. - 即使FIFO也有最大大小,循环不断地向其中追加作业(job),一旦其中一个工作进程从FIFO读取作业(job),此时FIFO大小应该会减小.
- 假设stdin非常大(
<(gen_huge_result)
),比如>;16 GB,但操作系统仍然会处理它,我不需要担心这一点.所以循环仍然有效,只是需要时间.
我已经try
我判断了对象结果的长度和大小:
# the_function_that_list_all_objects_from_bucket ${TARGET_BUCKET} | wc -l
8043
# the_function_that_list_all_objects_from_bucket ${TARGET_BUCKET} | wc -c
434387
据我所知,我可以通过cat /proc/sys/fs/pipe-max-size
号得到管道的最大尺寸
# cat /proc/sys/fs/pipe-max-size
1048576
这8,043个物体在迁移时应该没问题.
我还试图迫使追加作业(job)放慢速度,但仍"完成"了7,000个对象.
我猜追加作业(job)在达到FIFO最大大小时会停止,但我不知道是如何停止的,也不知道为什么.
最新情况:
1. Some experiments
正如@pt在 comments 中提到的那样
- 字节限制还是行限制?
我将作业(job)参数增加了四倍:
work() {
# ...
while true; do
## try to read the queue
flock 4 # obtain the fifo lock
read -r -su 3 work_id work_item tmp1 tmp2 tmp3 tmp4 tmp5 tmp6 # read into work_id and work_item
read_status=$? # save the exit status of read
# ...
}
append_job() {
# ...
echo "${work_id}" "$work_item" "${work_id}" "$work_item" "${work_id}" "$work_item" "${work_id}" "$work_item" 1>&3 ## the fifo is fd 3
}
我看到它超过了2000,然后是CTRL+C
.如果它达到了某个线路限制,它应该在1750(7,000/4)结束
- 有毒的工作?
这看起来不像是一份有毒的工作.没有来自乔布斯的标准,我甚至把工作设定为true
分;仍然是一样的.
我认为这应该是对发送工作的一些限制.
2. I can not reproduce this issue today.
我试着用"移动"的方法(复制和删除)来做迁移,而不是仅仅用"复制",来完成昨天的工作.
由于此环境是我公司的一个虚拟机,因此我请求INFRA团队帮助我恢复快照,该快照正好在迁移工作开始之前.通过这种方式,我可以测试下面@pt提供的脚本,试图找到一些根本原因.
启动后,我再次运行相同的脚本(上面),希望确保它在7,000停止.
然后显示追加作业(job)(对象):8,043.
也许是重新启动(恢复虚拟机映像)刷新了操作系统上的一些限制.
因为我不能复制这个问题,所以我只会在这里留下最新消息.
如果我下一次点击这个,我会try 下面的脚本.
非常感谢!