Fastdfs上传文件报错 recv package size -1!=10

异常描述

使用 Fastdfs 作为文件存储系统,Java 客户端单个上传文件没什么问题,在并发300的时候就会出现异常,部分上传失败。

客户端是自己封装的 spring-boot-starter-fastdfs,引用的核心库是 happyfish100大神的 java 版客户端,该库的 github 地址是 https://github.com/happyfish100/fastdfs-client-javaSpringBoot 的版本是 2.0.3.RELEASE

项目中引入编译好的 fastdfs-client-java jar lib。

<dependency>
    <groupId>org.csource</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27-SNAPSHOT</version>
</dependency>

fastdfs-client-java 没有实现连接池,故此,参考 Thirft 的连接池,本人写了一个连接池,提升性能。

spring-boot-starter-fastdfs 的仓库地址: https://github.com/FataliBud/spring-boot-starter-fastdfs

由于 fastdfs-client-java 加载的配置文件是 fastdfs.conf(也可以自己指定),在实际开发过程中,我们其实是根据不同的 spring.profile 区别环境的,整合在 spring 的配置文件则更方便,因此该项目只需要在 spring 的配置文件中配置 fastdfs 即可。

配置信息如下:

# 连接超时时间,单位秒
fastdfs.connect-timeout-in-seconds=10
# socket读取超时时间,单位秒
fastdfs.network-timeout-in-seconds=30
# 字符编码
fastdfs.charset=UTF-8
# token 防盗链功能
fastdfs.http-anti-steal-token=false
# 密钥
fastdfs.http-secret-key=FastDFS123456789
# TrackerServer port
fastdfs.http-tracker-http-port=80
# tracker server服务地址列表
fastdfs.tracker-server-list[0]=10.22.10.22:22122

java调用:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Main.class})
@Slf4j
public class Test {

    @Autowired
    private FastDFSClient fastDFSClient;

    @org.junit.Test
    public void test() {
        for (int i = 0; i < 500; i++) {
            new Thread(() -> {
                String path = "/Users/zhoujunwen/Desktop/20140102095833296.png";
                String fileId = fastDFSClient.upload(path, null);
            }).start();
        }
        try {
            TimeUnit.MINUTES.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

单个测试没发现问题,但是当多线程模拟上传时,发现有问题:

java.io.IOException: recv package size -1 != 10
        at org.csource.fastdfs.ProtoCommon.recvHeader(ProtoCommon.java:206)
        at org.csource.fastdfs.ProtoCommon.recvPackage(ProtoCommon.java:242)
        at org.csource.fastdfs.TrackerClient.getStoreStorage(TrackerClient.java:143)
        at org.csource.fastdfs.StorageClient.newWritableStorageConnection(StorageClient.java:1912)
        at org.csource.fastdfs.StorageClient.do_upload_file(StorageClient.java:702)
        at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:207)
        at org.csource.fastdfs.StorageClient.upload_file(StorageClient.java:225)
        at org.csource.fastdfs.StorageClient1.upload_file1(StorageClient1.java:112)

解决方法

该异常在网络超时之后,重新调用 upload 方法上传文件时,由于 socket 未连接造成的,我们可以在连接池的配置中开启 TestOnBorrow:

// 集成BaseObjectPoolConfig类,设置true即可
setTestOnBorrow(true);

同时,从连接池中 borrow TrackerServer 的时候,需要做校验,测试是否连接。

public TrackerServer borrowObject() {
        TrackerServer trackerServer = null;
        try {
            trackerServer = trackerServerPool.borrowObject();
            // 下面这段就是为了测试SOCKET是否已经连接
            ProtoCommon.activeTest(trackerServer.getSocket());
        } catch (Exception e) {
            log.warn("borrowObject出现异常", e);
        }
        return trackerServer;

默认情况下,fastdfs 仅仅支持最大连接数为 256, 所以在测试阶段发现只有 255 个成功,可以通过修改 tracker.conf 中的 max_connetion 即可增加连接数。同时记得修改 Linux 修通的 TCP 连接限制。

点击量:99

发表评论