FastDFS的简单实践--(与Spring Boot整合)

因为项目的需要,这两天在项目中整合了FastDFS,用于大批量的上传图片。按照惯例我们先介绍整合,然后再介绍一下FastDFS的相关情况。

FastDFS 与Spring Boot的整合

相关配置

  1. 在pom文件中添加依赖
<!-- fastdfs -->
      <dependency>
          <groupId>org.csource</groupId>
          <artifactId>fastdfs-client-java</artifactId>
          <version>1.2.RELEASE</version>
      </dependency>
      <!--对象池-->
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-pool2</artifactId>
          <version>2.4.2</version>
      </dependency>
  1. 配置属性文件,命名为fastdfs_client.conf,放在resources下
## fastdfs为前缀的是FastDFS的配置
connect_timeout = 2
network_timeout = 30
charset = utf-8
# TrackerServer port
http.tracker_http_port = 80
# token 防盗链功能
http.anti_steal_token = no
# 密钥
http.secret_key = FastDFS1234567890
# 文件服务器地址
http.access.url=你fastdfs的服务器
# Tracker Server
tracker_server = 你tracker的服务器
tracker_server = 你tracker的服务器

文件上传

  1. 操作文件的工具类FastDfsUtil
public class FastDfsUtil implements Serializable{

    private static final Logger log = LoggerFactory.getLogger(FastDfsUtil.class);

    private static final long serialVersionUID = -4230645563489067923L;

    /**
     * 文件上传
     * @param is
     * @param fileName
     * @return
     */
    public static String uploadFile(InputStream is, String fileName){
        String path = null;
        TrackerServer trackerServer = TrackerServerPool.borrowObject();
        StorageClient1 storageClient = new StorageClient1(trackerServer, null);
        try {
            try {
                //读取流
                byte[] content = new byte[is.available()];
                is.read(content, 0, content.length);
                //文件扩展名
                String ext = FilenameUtils.getExtension(fileName);
                //mata list是表文件的描述
                NameValuePair[] mata_list = new NameValuePair[1];
                mata_list[0] = new NameValuePair("fileName",fileName);
                // 上传
                path = storageClient.upload_file1(content, ext, mata_list);
            } finally {
                if (is != null) {
                    is.close();
                }
            }
        } catch (Exception e) {
            log.error("上传图片到fastDFS失败={}",e.getMessage());
        }
        // 返还对象
        TrackerServerPool.returnObject(trackerServer);
        return path;
    }
}

此处用到了工厂模式以及对象池
4. 对象池类TrackerServerPool

/**
 * TrackerServer 对象池
 * <p>
 *
 * @author xiang.wei
 * @version 1.0
 */
public class TrackerServerPool {
    /**
     * org.slf4j.Logger
     */
    private static Logger logger = LoggerFactory.getLogger(TrackerServerPool.class);

    /**
     * TrackerServer 配置文件路径
     */
    private static final String FASTDFS_CONFIG_PATH = "fastdfs_client.conf";

    /**
     * 最大连接数 default 8.
     * 需要在application.properties中配置
     */
    @Value("${max_storage_connection}")
    private static int maxStorageConnection;

    /**
     * TrackerServer 对象池.
     * GenericObjectPool 没有无参构造
     */
    private static GenericObjectPool<TrackerServer> trackerServerPool;

    private TrackerServerPool(){};

    private static synchronized GenericObjectPool<TrackerServer> getObjectPool(){
        if(trackerServerPool == null){
            try {
                // 加载配置文件
                ClassPathResource resource = new ClassPathResource(FASTDFS_CONFIG_PATH);
                ClientGlobal.init(resource.getClassLoader().getResource(FASTDFS_CONFIG_PATH).getPath());

            } catch (IOException e) {
                logger.info("加载fastDFS配置文件出错={}",e.getMessage());
            } catch (Exception e) {
                logger.info("加载fastDFS配置文件出错={}",e.getMessage());
            }
            // Pool配置
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
            poolConfig.setMinIdle(2);
            if(maxStorageConnection > 0){
                poolConfig.setMaxTotal(maxStorageConnection);
            }

            trackerServerPool = new GenericObjectPool<>(new TrackerServerFactory(), poolConfig);
        }
        return trackerServerPool;
    }

    /**
     * 获取 TrackerServer
     * @return TrackerServer
     * @throws FastDFSException
     */
    public static TrackerServer borrowObject(){
        TrackerServer trackerServer = null;
        try {
            trackerServer = getObjectPool().borrowObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return trackerServer;
    }

    /**
     * 回收 TrackerServer
     * @param trackerServer 需要回收的 TrackerServer
     */
    public static void returnObject(TrackerServer trackerServer){
        getObjectPool().returnObject(trackerServer);
    }
}
  1. 工厂类 TrackerServerFactory
public class TrackerServerFactory extends BasePooledObjectFactory<TrackerServer> {

    @Override
    public TrackerServer create() throws Exception {
        // TrackerClient
        TrackerClient trackerClient = new TrackerClient();
        // TrackerServer
        TrackerServer trackerServer = trackerClient.getConnection();

        return trackerServer;
    }

    @Override
    public PooledObject<TrackerServer> wrap(TrackerServer trackerServer) {
        return new DefaultPooledObject<TrackerServer>(trackerServer);
    }
}

以上就配置完了,可以传入有效的图片测试下。

FastDFS 的介绍

FastDFS是一个开源的高性能分布式文件系统(DFS)。它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载均衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size < 500MB) 为载体的在线服务。
FastDFS系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client) 。
Tracker Server: 跟踪服务器,主要做调度工作,起到均衡的作用;负责管理所有的storage servergroup,每个storage在启动后会连接Tracker,告知自己所属group等信息,并保持周期性心跳。
Storage Server:存储服务器,主要提供容量和备份服务;以group为单位,每个group内有多台storage server,数据互为备份。
Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。

FastDFS的架构图

FastDFS的存储策略

为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的。所有卷的文件容量雷佳就是存储系统中的文件容量。一个卷可以由一台或者多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就可以扩大了存储系统的容量。

FastDFS的上传过程

FastDFS向使用者提供基本文件访问接口,不如upload,download等等,以客户端库的方式提供给用户使用。
storage server会定期的向Tracker Server发送自己的存储信息。当Tracker Server Cluster中的Tracker Server不止一个时,各个Tracker之间的关系是对等的。所以客户端上传时可以选择任意一个Tracker
Tracker收到客户端上传文件的请求时,会为该文件分配一个可以存储文件的group,当选定了group后就要决定给客户端分配group中的哪一个storage server。当分配好storage server后,客户端向stroage发送写文件请求,storage 将会为文件分配一个数据存储目录。然后为文件分配一个 field,最后根据以上的信息生成文件名存储文件。
上传时序图

FastDFS的文件同步

写文件时,客户端将文件写至group内一个storage server即认为写文件成功,storage server写完文件后,会由后台线程将文件同步至同group内其他的storage server。
每个storage写文件后,同时会写一份 binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式记录,所以最好能保持集群内所有server的时钟保持同步。
storage的同步进度会作为元数据的一部分汇报到tracker上,tracker在选择读storage的时候以同步进度作为参考。

FastDFS的文件下载

客户端uploadfile成功后,会拿到一个storage生成的文件名,接下来客户端更加这个文件名即可访问到该文件。
下载时序图

引用

https://www.cnblogs.com/chiangchou/p/fastdfs.html#_label0_0

猜你喜欢

转载自blog.csdn.net/u014534808/article/details/79742626
今日推荐