【linux常见问题】OSS import单机模式部署--阿里云功能

发布时间 2023-11-27 23:03:22作者: Unfool
title:  OSSImport单机部署附问题解决
date:  2022-01-18  10:54:06 
updated: 2022-01-18 20:52:00
tags:
  - AWS
  - Ubuntu
  - Ossimport
categories:
  - Ossimport
description: OSSImport单机部署
abbrlink: 'use-ubuntu18.04-to-deploy-ossimport'
top_img:
cover: https://cdn.jsdelivr.net/gh/jerryc127/CDN@latest/cover/default_bg.png

ossimport需求:

需要安装Java 1.7及1.8版本。
安装java指定版本
apt install -y openjdk-8-jdk

java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-8u312-b07-0ubuntu1~18.04-b07)
OpenJDK 64-Bit Server VM (build 25.312-b07, mixed mode)

下载ossimport版本并解压

1、切换到指定目录
2、wget  https://gosspublic.alicdn.com/ossimport/standalone/ossimport-2.3.5.zip?spm=a2c4g.11186623.0.0.6d3b47acO75p3H&file=ossimport-2.3.5.zip
3、解压ossimport目录
unzip ossimport-2.3.5.zip

根据需求编辑conf/sys.properties、conf/local_job.cfg文件。

注意不要修改以下内容:

  • conf/sys.properties中的配置项workingDir、workerUserName、workerPassword、privateKeyFile。
  • conf/local_job.cfg的名称、位置、配置项jobName
cat /data/ossimporet-2.3.5
isIncremental=true                 开启增量同步
incrementalModeInterval=14400      此配置目前说明扫描时间间隔为四小时
#同步源类型,目前支持:
#1.local(本地文件,此选项只需要填写srcPrefix,不需要填写srcAccessKey,srcSecretKey,srcDomain,srcBucket)
srcType=local

srcAccessKey=    源aK值

srcSecretKey=    源SK

srcDomain=    #源endpoint,同步本地文件以及通过http地址同步的不需要填

srcBucket=    #源bucket名字,同步本地文件以及通过http地址同步的不需要填,不需要加上"/";微软blob填container名称

#源前缀,默认为空,如果srcType=local,则此目录是本地目录,如果是其他类型,则是源Bucket里需要同步的Object的前缀,注意如果是本地目录,需要完整目录路径(以'/'进行分割并且以'/'结尾,例: c:/example/)
srcPrefix=/mnt/efs/fs1/data_center/spreads/

##############################################################同步目的端设置################################################################
#目的 access key
destAccessKey=****************************   (此项填写阿里云的ak)

#目的 secret key
destSecretKey=**************************    (此项填写阿里云的sk)

#目的endpoint,请根据您的实际oss区域填写,默认为杭州的域名,如果用阿里云ecs虚拟机做迁移的,请使用internal域名,不计费且不受虚拟机带宽限制(非虚拟机无法使用);例:http://oss-cn-hangzhou-internal.aliyuncs.com
destDomain=https://oss-cn-hongkong.aliyuncs.com

#目的bucket,不需要加上"/"
destBucket=*****     填写bucket目录

#目标前缀,默认为空,直接放在bucket下(如果要将数据同步到oss的某个目录下,请以'/'结尾),注意:oss不支持以 '/' 作为文件的开头,所以destPrefix请不要配置以'/'做为开头
destPrefix=

appId=0

httpListFilePath=c:/example/http.list
httpPrefixColumn=1
relativePathColumn=2

jobName=local_test_1

#job类型(import/audit),import为同步数据到oss,audit为校验源端数据和oss数据是否一致
jobType=import

#只导入源文件最后修改时间大于该时间的数据,默认为0,这个时间为unix时间戳(秒数)
importSince=0

lastModify=0

#数据迁移时,是否跳过已经存在的文件。当设置为true时,根据文件的size和LastModifiedTime判断是否跳过;为false时,总是覆盖OSS上已有文件。jobType为audit时此项不生效。
isSkipExistFile=true

# 每个子任务最大的文件个数限制,这个会影响到任务执行的并行度,一般配置为总的文件数/120
taskObjectCountLimit=1000

#每个子任务下载的最大文件大小限制(bytes)
taskObjectSizeLimit=10000000000

#并行扫描文件列表的线程数,只影响扫描文件的效率,没有特殊需求不要修改
scanThreadCount=1

#最大允许并行扫描目录的深度,默认为1就是只能在顶级目录间并行扫描,没有特殊需求不要修改,随意配置的过大会导致任务无法正常运行
maxMultiThreadScanDepth=1

#大于该值的文件使用分片上传,否则使用普通上传,请配置大于1MB以上;有效配置值如:50m/1024m/5g
multipartUploadThreshold=150m

#分配上传时分片大小,请配置大于100k的数据,否则无效,采用默认值50MB;有效配置值如:500k/50m/2g
multipartUploadPartSize=50m

#单个大文件分片上传并发数,默认超过150MB为大文件,分片为50MB,srcType=local时有效,其它情况该配置项无效
#uploadThreadNumPerLargeFile大于1时,workerRecordMd5无效
uploadThreadNumPerLargeFile=3

#存储在OSS上的数据否加密,默认不加密
isServerSideEncryption=false

#local模式时,链接文件是否上传,默认不上传;该选择仅支持链接文件不包括链接目录
isAllowSymbolicLink=false

# 七牛云存储获取Meta的方式,有效值head和stat,默认使用stat;head通过HTTP HEAD请求获取,stat通过BucketManager.stat
getObjectMetaMode=stat

#数据迁移后是否进行数据的正确性校验,默认校验
isAuditAfterImport=true

#数据校验方式,有效值为simple/general/detailed,默认值general;simple只校验文件的size,general校验文件的size/lastModify/header,detailed检验文件的CRC或MD5,开发中
auditMode=general


此配置文件中的注释均为文件内自带注释,详细可自行安装查看

import.sh

cat /data/ossimport-2.3.4/import.sh 
#!/bin/bash
# One Key Import for Linux

#######################################################
# Define function
#######################################################

function yes_or_no()
{
    while [ true ]
    do
       echo -n "$*, Yes or No: "
       read x
       case "$x" in
         y | Y | yes | Yes | YES ) return 0;;
         n | N | no | No | NO ) return 1;;
         * ) echo "Answer yes or no"
       esac
    done
}

function get_java_heap_max()
{
    if [ -e ${import_sys_conf} ]; then
        java_heap_line=$(grep "javaHeapMaxSize=" ${import_sys_conf} | tr -d '\r')
        if [ -n "$java_heap_line" ]; then
            java_heap=${java_heap_line#javaHeapMaxSize*=}
            if [ -z "$java_heap" ]; then
                java_heap="1024m"
            fi
            java_heap_max="-Xmx${java_heap}"
        fi
    else
        echo "Error: ossimport system configuration:${import_sys_conf} not found."
        exit 2
    fi
}

function start_import_service()
{
    get_java_heap_max
    nohup java ${java_heap_max} ${import_opts} -jar ${import_jar} -c ${import_sys_conf} start > ${work_dir}/logs/ossimport2.log 2>&1 &
    sleep 1s
    echo "Start import service completed."
}

function stop_import_service()
{
    ps axu | grep "ossimport2.jar.* start" | grep -v grep | awk '{print "kill -9 "$2}' | bash > /dev/null 2>&1
    sleep 1s
    echo "Stop import service completed."
}

function submit_job()
{
    java -jar ${import_jar} -c ${import_sys_conf} submit $work_dir/conf/local_job.cfg > ${work_dir}/logs/submit.log 2>&1              此处的local_job.cfg即为上面的配置文件,统一即可
    submit_result=$(grep "Error:" ${work_dir}/logs/submit.log)
}

function clean_job()
{
    java -jar ${import_jar} -c ${import_sys_conf} clean ${job_name}
    echo "Clean job:${job_name} completed."
}

function stat_job()
{
    java -jar ${import_jar} -c ${import_sys_conf} stat detail > ${work_dir}/logs/job_stat.log 2>&1
    cat ${work_dir}/logs/job_stat.log
}

function retry_failed_tasks()
{
    java -jar ${import_jar} -c ${import_sys_conf} retry ${job_name} > ${work_dir}/logs/retry.log 2>&1
    retry_result=$(cat ${work_dir}/logs/retry.log)
    if [ -z "$retry_result" ]; then
        echo "None failed tasks for job:${job_name}."
    else
        cat ${work_dir}/logs/retry_result.log
        echo "Retry has been submitted."
    fi
}

#######################################################
# Start of main
#######################################################

work_dir=
job_name="local_test_1"     只需修改jobname与目录中的文件指定job相同即可
submit_result=
java_heap_max="-Xmx1024m"
import_opts=
import_jar=
import_sys_conf=

# get work dir
osname=$(uname)
if [ "$osname" = "Linux" ]; then
    work_dir=$( dirname $(readlink -f $0) )
else
    work_dir=$( cd "$( dirname "$0" )" && pwd )
fi

import_jar=${work_dir}/bin/ossimport2.jar
import_sys_conf=${work_dir}/conf/sys.properties

# cd to the root dir of ossimport
cd ${work_dir}

# submit job
while [ 0 ]; do
    submit_job
    if [ -z "$submit_result" ]; then
        # successful
        cat ${work_dir}/logs/submit.log
        break
    else
        # failed
        yes_or_no "Clean the previous job"
        is_clean_job=$?
        if [ $is_clean_job == 0 ]; then
            stop_import_service
            clean_job
        else
            exit 1
        fi
    fi
done


# start service
start_import_service

# stat
while [ 0 ]; do
    sleep 5s
    stat_job

    # job failed
    is_job_failed=$(grep "JobState:Failed" ${work_dir}/logs/job_stat.log)
    if [ -n "$is_job_failed" ]; then
        yes_or_no "Retry the failed tasks"
        is_retry=$?
        if [ $is_retry == 0 ]; then
            retry_failed_tasks
        else
            exit 2
        fi
    fi

    # job successful
    is_job_completed=$(grep "JobState:Succeed" ${work_dir}/logs/job_stat.log)
    if [ -n "$is_job_completed" ]; then
        break
    fi
done
echo "Import to oss completed."

# stop service
yes_or_no "Stop import service"
is_stop_service=$?
if [ $is_stop_service == 0 ]; then
    stop_import_service
fi

exit 0

运行ossimport进行迁移

Linux终端中执行bash import.sh命令。

cd /data/ossimport-2.3.4
bash import.sh 

单机模式下配置多任务

1、添加多job配置文件(只需修改上面对应的配置文件中的注释参数即可)

ll /data/ossimport-2.3.4/conf/
-rw-r--r-- 1 root root 8453 1月  17 08:05 job1.cfg
-rw-r--r-- 1 root root 8457 1月  17 06:44 local_job.cfg

2、修改import.sh文件(修改指定cfg文件和jobname)

ll /data/ossimport-2.3.4/
-rwxr-xr-x 1 root root     3987 1月  14 10:12 import_1.sh*
-rwxr-xr-x 1 root root     4000 1月  14 09:06 import.sh*

单机模式执行多任务的情况中出现的问题

注:个人遇到的问题:
1、查看jobstat日志或者说在执行import.sh的时候出现stop service(终止java进程)
这种情况在我看来应该是目录权限问题,我是直接更改属主之后重新执行就可以了
下面的为网上收集到的问题罗列

1. UnsupportedClassVersionError异常

执行命令时异常:

Exception in thread "main" java.lang.UnsupportedClassVersionError: com/aliyun/ossimport2/OSSImport2 : Unsupported major.minor version 51.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
        at com.simontuffs.onejar.JarClassLoader.defineClass(JarClassLoader.java:693)
        at com.simontuffs.onejar.JarClassLoader.findClass(JarClassLoader.java:599)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at com.simontuffs.onejar.Boot.run(Boot.java:300)
        at com.simontuffs.onejar.Boot.main(Boot.java:159)

原因:Java版本过低,更新到1.7或以上版本。

2. InvocationTargetException异常

使用submit命令提交任务报异常:

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.simontuffs.onejar.Boot.run(Boot.java:306)
        at com.simontuffs.onejar.Boot.main(Boot.java:159)
Caused by: java.lang.NullPointerException
        at com.aliyun.ossimport2.config.JobConfig.load(JobConfig.java:44)
        at com.aliyun.ossimport2.OSSImport2.doSubmitJob(OSSImport2.java:289)
        at com.aliyun.ossimport2.OSSImport2.main(OSSImport2.java:120)
        ... 6 more

原因:检查是否将配置文件中原有的项删除或者注释掉了,不需要配置的项请在等号后面填空,不需要删除。

3. too many open files

原因:ulimit -n 查看系统句柄。

  • 如果值小于一万以下的,可以通过 ulimit -n 65536 调大后,重启进程即可;
  • 如果本来就设置的比较大,那就用 sudo losf -n 排查是哪些进程打开了句柄。

4. windows启动后秒退

原因:大部分情况是java没装或者版本低于1.7导致的,或配置文件错误导致。

5. no jobs is running or finished

submit 命令提交完任务后,用 stat 查看任务状态一直显示:

bash console.sh stat
[WARN]   List files dir not exist : /home/<user>/ossimport/workdir/master/jobs/
no jobs is running or finished.

原因:

  • Job 刚提交,Master需要先去扫描文件列表,这时 Task 还没有真正生成和分发,打印该日志是正常的;
  • 很长一段时间后依旧打印该错误,一般是没有使用 start 命令启动进程或者进程启动后有异常退出。没有启动服务的情况,只需使用 start 就可以了;否则看下 logs/ossimport.log,找到异常原因并解决,然后再启动服务进程。

6. stat命令一直显示scanFinished:false

观察Task的总数是否在增加:

  • 如果在变多,那就是 Job 的文件列表还没 List 完,还在 List 新的文件;
  • 一直没变化,如果 Job 配置的是增量模式, scanFinished 永远不会为 true ,会根据用户配置的间隔时间,定期去扫描文件列表,检查有无新增或修改的文件;
  • 如果不是增量模式,Task数也不会增多,检查日志是否有异常。

7. 服务进程挂掉,日志却没有输出异常

原因:如果机器的可用内存是少于 *2GB* 的,大概率是内存不足被杀掉了,检查下 dmsg 日志是否有内存不足被杀的记录。

8. 进程挂掉或者杀掉进程后,重启服务需要做什么操作

直接调用 start 命令启动服务即可,已经提交的Job不需要重新提交,只要不调用clean命令,所有提交过的Job都有断点记录,不会重做已经完成的工作。

9. 任务完成OSS控制台显示的数据量比源数据量小

Job全部成功上传完后OSS控制台里没有看到bucket的大小有变化,或者和本地用 du统计的大小相差很大。
原因:OSS控制台的bucket数据量是延迟1小时更新的。du 命令统计的是块大小,会比实际文件要大,可以参考如下命令统计本地目录的真实大小: ls -lR <目录绝对路径> | grep "\-rw" | awk '{sum+=$5}END{print sum}'

10. stat显示的失败任务如何处理

一般应该使用 retry 命令进行重试。

11. 有些失败任务后反复retry都无法成功

原因:查看文件$work_dir/master/jobs/$jobName/failed_tasks/$taskName/error.list 拿到失败文件的相对路径,检查该文件是否有权限访问,是否被删除,是否是软连接,是否是乱码的文件名等。

12. 文件名乱码的文件如何上传到OSS

需要首先使用export LANG="", ls 查看该文件名不乱码之后,用 clean 命令清掉原来的Job,再用 submit 命令重新提交Job。

13. java.nio.file.AccessDeniedException

报异常:启动服务时报java.nio.file.AccessDeniedException。
原因:没有权限访问配置文件目录。

14. Task状态显示0个,但Job显示完成

Task状态显示0个,但Job显示完成,如下所示:

[2015-12-28 16:12:35]   [INFO]  JobName:dir_data
[2015-12-28 16:12:35]   [INFO]  Pending Task Count:0
[2015-12-28 16:12:35]   [INFO]  Dispatched Task Count:0
[2015-12-28 16:12:35]   [INFO]  Succeed Task Count:0
[2015-12-28 16:12:35]   [INFO]  Failed Task Count:0
[2015-12-28 16:12:35]   [INFO]  Is Scan Finished:true
[2015-12-28 16:12:35]   [INFO]  JobState:SUCCEED

原因:

  • srcPrefix填写错误,导致 List 不出来文件;
  • srcPrefix下只有目录,没有文件,因为目录概念是OSS模拟出来的,不会被真正上传。

15. The bucket you are attempting to access must be addressed using the specified endpoint

日志报异常:

Exception:com.aliyun.oss.OSSException: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
<Error>
  <Code>AccessDenied</Code>
  <Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message>
  <RequestId>56EA98DE815804**21B23EE6</RequestId>
  <HostId>my-oss-bucket.oss-cn-qingdao.aliyuncs.com</HostId>
  <Bucket>my-oss-bucket</Bucket>
  <Endpoint>oss-cn-hangzhou.aliyuncs.com</Endpoint>
</Error>

原因:bucket的srcDomaindestDomain 填写错误,请按照 域名列表 填写正确的域名。

16. The request signature we calculated does not match the signature you provided

日志报异常:

Exception:com.aliyun.oss.OSSException: The request signature we calculated does not match the signature you provided. Check your key and signing method.
[ErrorCode]: SignatureDoesNotMatch
[RequestId]: xxxxxxx
[HostId]: xxx.oss-cn-shanghai.aliyuncs.com

原因:检查destAccessKeydestSecretKey是否填错,详细说明请参看 访问控制

17. InvocationTargetException

submit命令提交任务时报异常:

submit job:/disk2/ossimport2/local_job.cfg
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at com.simontuffs.onejar.Boot.run(Boot.java:306)
        at com.simontuffs.onejar.Boot.main(Boot.java:159)
Caused by: java.lang.NullPointerException
        at com.aliyun.ossimport2.OSSImport2.doSubmitJob(OSSImport2.java:289)
        at com.aliyun.ossimport2.OSSImport2.main(OSSImport2.java:120)
        ... 6 more

原因:检查 conf/sys.properties 中的配置项 workingDir 是否配置,配置是否正确;检查配置文件路径是否路径正确。

18. 是否支持设置代理

不支持

19. OSS迁移到OSS为什么还会产生费用

参考 访问域名 里的域名帮助,配置内网域名后,将不收取流量费用,但访问次数的费用是依旧计费的。

20. 同步的过程中显示源端的文件不存在

原因:Master是先 List 出文件列表,之后按照文件列表做数据迁移。当 List 完之后,源端某些文件被删除,就会出现源端文件不存在的情况。这种文件会被跳过,并把文件输出在错误列表里。

21. 开启增量模式,本地删除后OSS上会不会被删

开启增量模式,本地删除后OSS上会不会被删,删除操作不会被同步。

22. 开启增量模式,有些新增的文件没有被同步

增量模式是采用对比文件最后修改来判断文件是否为增量的,Linux的 mv ,Windows的 cpmv 以及 rsync-t或者-a参数等操作是不会修改文件的最后修改时间的,这些操作修改的文件是不会被扫描到的。

23. 又拍迁移的任务数一直显示0

原因:又拍的比较复杂,主要分两种情况:

  • [2016-07-21 10:21:46] [INFO] [name=YoupaiList, totalRequest=1729925, avgLatency=38, recentLatency=300000],这条日志如果recentLatency=30000这种一般就是在正常 List 的,又拍 List 比较慢一般都是跑满30秒超时,30秒 List 出几个文件就返回几个文件过来,这种情况等任务慢慢
    List 出来就正常了;
  • recentLatency很小,这种情况一般就是账号密码填错之类的,因为又拍的sdk出错只返回 null ,并不返回错误结果,所以只能通过抓包的方式获得又拍返回的错误码排查。

24. 又拍迁移时srcAccessKeysrcSecretKey填写什么

填写又拍的 操作员账号密码

25. 又拍迁移时一直显示http 429错误

又拍对sdk访问间隔做了限制,如果访问稍微快一点,会进行限速,请联系又拍的客服放开限制。OssImport本身会对这种情况进行重试的。

26. 执行时unknown command "java", unknown command "nohup"之类的提示

原因:使用的命令没有安装,请用 yumapt-getzypper 等命令安装相应的命令。

27. 任务与配置文件不符

Job配置文件看上去是对的,但跑的时候看上去明显和Job配置文件配置的不一样。只有sys.properties是改完之后重启就生效的,Job的配置文件一旦提交后,修改是不会生效的,需要 clean 掉原有的Job,然后重新 submit 新的配置文件。

28. The bucket name "xxx/xx" is invalid

日志报异常:

java.lang.IllegalArgumentException: The bucket name "xxx/xx" is invalid. A bucket name must: 1) be comprised of lower-case characters, numbers or dash(-); 2) start with lower case or numbers; 3) be between 3-63 characters long.

原因:检查配置项destBucket是否填写正确,bucket是不带 */* 以及其它路径的。

29. com.aliyun.oss.ClientException: Unknown

日志报异常:

com.aliyun.oss.ClientException: Unknown
[ErrorCode]: NonRepeatableRequest
[RequestId]: Cannot retry request with a non-repeatable request entity.  The cause lists the reason the original request failed.

以及SocketTimeoutException,一般都是网络打满的时出现的,OssImport内部会重试,如果重试完后依旧失败,可以在任务完成后调用 *retry* 命令再次重试。

30. Connect to xxx.oss-cn-beijing-internal.aliyuncs.com:80 timed out

日志报异常:

Unable to execute HTTP request: Connect to xxx.oss-cn-beijing-internal.aliyuncs.com:80 timed out
[ErrorCode]: ConnectionTimeout
[RequestId]: Unknown

原因:非ieECS的机器不能使用带 *internl* 的域名。

31. The specified bucket is not valid

日志报异常:

com.aliyun.oss.OSSException: The specified bucket is not valid.
[ErrorCode]: InvalidBucketName
[RequestId]: 57906B4DD0EBAB0FF553D661
[HostId]: you-bucket.you-bucketoss-cn-hangzhou-internal.aliyuncs.com

原因:配置文件里的 destDomian 配置的域名不能带bucket名称。

32. 配置文件里的srcPrefix能单独指定文件吗

不可以,srcPrefix只支持目录或者前缀级别,单个文件上传可以用别的更简单的工具。

33. Unable to execute HTTP request: The Difference between ... is too large.

日志报异常:

Unable to execute HTTP request: The Difference between the request time and the current time is too large.
[ErrorCode]: RequestTimeTooSkewed
[RequestId]: xxxxxxx

原因:

  • 本地机器时间不对,与服务器时间相差15分钟以上,该情况居多;
  • 可能是并发太高,尤其是CPU占用率很高,导致在并发上传慢。

34. No route to host

日志里显示错误 No route to host,一般是本地防火墙或者 iptables 等原因导致网络不通。

35. Unknown http list file format

使用 http 模式日志显示该错误,是因为指定的http列表文件格式不对:

  • 从其它系统上拷过来的文件,可以用mac2unix,dos2unix等相关命令转化文件格式;
  • 文件里有某些行不符规则,比如某行少于两列。

36. The boject key "/xxxxx.jpg" is invalid

日志报异常:

Exception:java.lang.IllegalArgumentException: The boject key "/xxxxx.jpg" is invalid. An object name should be between 1 - 1023 bytes long when encoded as UTF-8 and cannot contain LF or CR os unsupported chars in XML1.0, and cannot begin with "/" or "\".

原因:

  • 检查 srcPrefix 是否是作为目录的但没有以 */* 结尾;
  • 检查 destPrefix 是否以 */* 或者 ** 开头了。