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

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

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


FastDFS 与Spring Boot的整合


相关配置

在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>


配置属性文件,命名为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的服务器


文件上传

操作文件的工具类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){
        TrackerServer trackerServer = TrackerServerPool.borrowObject();
        StorageClient1 storageClient = new StorageClient1(trackerServer, null);
        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);
            // 上传
            String path  = storageClient.upload_file1(content, ext, mata_list);
            return path;
        } catch (Exception e) {
            log.error("上传图片到fastDFS失败={}", e.getMessage());
            throw new UploadException("上传图片到fastDFS失败");
        } finally{
            // 返还对象
            TrackerServerPool.returnObject(trackerServer);
        }
    }
}


此处用到了工厂模式以及对象池

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);
    }
}


工厂类 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 server和group,每个storage在启动后会连接Tracker,告知自己所属group等信息,并保持周期性心跳。

Storage Server:存储服务器,主要提供容量和备份服务;以group为单位,每个group内有多台storage server,数据互为备份。

Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。

49180aa114dd9b526e07df6ec67e9b78_70.png



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,最后根据以上的信息生成文件名存储文件。

1f9c325a18f581d2e761ffa23d4f9bd6_SouthEast.png

生成文件名:

当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、fileid、文件后缀名拼接而成。

例如:

group1/M00/02/1E/wKjScFs8PP6AOeKAAAFQYpr9pVQ027.jpg
组名  磁盘    目录   文件名


FastDFS的文件同步

写文件时,客户端将文件写至group内一个storage server即认为写文件成功,storage server写完文件后,会由后台线程将文件同步至同group内其他的storage server。

每个storage写文件后,同时会写一份 binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式记录,所以最好能保持集群内所有server的时钟保持同步。

storage的同步进度会作为元数据的一部分汇报到tracker上,tracker在选择读storage的时候以同步进度作为参考。


FastDFS的文件下载

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

12525b2b996c64fdf6f10eb762b848ed_SouthEast.png


引用

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

https://blog.csdn.net/u013378306/article/details/74852355


相关文章
|
6月前
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,日期时间格式化是前后端交互的常见痛点。本文详细解析了 **@DateTimeFormat** 和 **@JsonFormat** 两个注解的用法,分别用于将前端传入的字符串解析为 Java 时间对象,以及将时间对象序列化为指定格式返回给前端。通过完整示例代码,展示了从数据接收、业务处理到结果返回的全流程,并总结了解决时区问题和全局配置的最佳实践,助你高效处理日期时间需求。
696 0
|
6月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
173 0
|
3月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
118 0
|
6月前
|
Java 开发者 微服务
Spring Cloud OpenFeign详解与实践
总结起来说,Spring Cloud OpenFeign提供了一种简单易懂且高效的方式去实现微服务之间通信.它隐藏了许多复杂性,并且允许开发者以声明式方式编写HTTP客户端代码.如果你正在开发基于Spring Cloud 的微服务架构系统,Spring Cloud Open Feign是一个非常好用且强大工具.
397 33
|
6月前
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,处理前后端日期交互是一个常见问题。本文通过 **@DateTimeFormat** 和 **@JsonFormat** 两个注解,详细讲解了如何解析前端传来的日期字符串以及以指定格式返回日期数据。文章从实际案例出发,结合代码演示两者的使用场景与注意事项,解决解析失败、时区偏差等问题,并提供全局配置与局部注解的实践经验。帮助开发者高效应对日期时间格式化需求,提升开发效率。
1536 2
|
8月前
|
前端开发 Java Nacos
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
1246 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
|
9月前
|
搜索推荐 NoSQL Java
微服务架构设计与实践:用Spring Cloud实现抖音的推荐系统
本文基于Spring Cloud实现了一个简化的抖音推荐系统,涵盖用户行为管理、视频资源管理、个性化推荐和实时数据处理四大核心功能。通过Eureka进行服务注册与发现,使用Feign实现服务间调用,并借助Redis缓存用户画像,Kafka传递用户行为数据。文章详细介绍了项目搭建、服务创建及配置过程,包括用户服务、视频服务、推荐服务和数据处理服务的开发步骤。最后,通过业务测试验证了系统的功能,并引入Resilience4j实现服务降级,确保系统在部分服务故障时仍能正常运行。此示例旨在帮助读者理解微服务架构的设计思路与实践方法。
424 17
|
9月前
|
人工智能 自然语言处理 Java
Spring Cloud Alibaba AI 入门与实践
本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个在线聊天和在线画图的 AI 应用。
2183 7
|
10月前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
427 4