在前篇 高可用高性能分布式文件系统FastDFS进阶keepalived+nginx对多tracker进行高可用热备 中已介绍搭建高可用的分布式文件系统架构。

  那怎么在程序中调用,其实网上有很多栗子,这里在他们的基础上作个简单的介绍。

下载源码并加入本地仓库

官网Java客户端源代码:https://github.com/happyfish100/fastdfs-client-java

打开源码后 执行maven install 将代码打成jar到本地maven仓库(这步可自行 google)

示例源码

然后创建一个Demo工程,这里采用spring mvc模式创建。

在pom中加入引用 maven中依赖jar包

<!-- fastdfs上传下载图片 路径和上面的pom中对应 -->

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

fastdfs-client.properties

在resources的properties文件夹中创建配置文件fastdfs-client.properties

fastdfs.connect_timeout_in_seconds =
fastdfs.network_timeout_in_seconds =
fastdfs.charset = UTF-
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = fastdfs.tracker_servers = 10.0.11.201:,10.0.11.202:,10.0.11.203:

创建FastDFSClient工具类

package com.james.utils;

import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*; import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLDecoder; /**
* Created by James on 2015/11/14.
* FastDFS文件上传
*/
public class FastDFSClientUtils {
private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null; public FastDFSClientUtils(String conf) throws Exception {
if (conf.contains("classpath:")) {
String path = this.getClass().getResource("/").getPath();
conf = conf.replace("classpath:", URLDecoder.decode(path, "UTF-8"));
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
} /**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
*
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) {
String result = null;
try {
result = storageClient.upload_file1(fileName, extName, metas);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
} /**
* 上传文件,传fileName
*
* @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg
* @return null为失败
*/
public String uploadFile(String fileName) {
return uploadFile(fileName, null, null);
} /**
* @param fileName 文件的磁盘路径名称 如:D:/image/aaa.jpg
* @param extName 文件的扩展名 如 txt jpg等
* @return null为失败
*/
public String uploadFile(String fileName, String extName) {
return uploadFile(fileName, extName, null);
} /**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
*
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) {
String result = null;
try {
result = storageClient.upload_file1(fileContent, extName, metas);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
} /**
* 上传文件
*
* @param fileContent 文件的字节数组
* @return null为失败
* @throws Exception
*/
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
} /**
* 上传文件
*
* @param fileContent 文件的字节数组
* @param extName 文件的扩展名 如 txt jpg png 等
* @return null为失败
*/
public String uploadFile(byte[] fileContent, String extName) {
return uploadFile(fileContent, extName, null);
} /**
* 文件下载到磁盘
*
* @param path 图片路径
* @param output 输出流 中包含要输出到磁盘的路径
* @return -1失败,0成功
*/
public int download_file(String path, BufferedOutputStream output) {
//byte[] b = storageClient.download_file(group, path);
int result = -1;
try {
byte[] b = storageClient.download_file1(path);
try {
if (b != null) {
output.write(b);
result = 0;
}
} catch (Exception e) {
} //用户可能取消了下载
finally {
if (output != null)
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
} /**
* 获取文件数组
*
* @param path 文件的路径 如group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return
*/
public byte[] download_bytes(String path) {
byte[] b = null;
try {
b = storageClient.download_file1(path);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return b;
} /**
* 删除文件
*
* @param group 组名 如:group1
* @param storagePath 不带组名的路径名称 如:M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失败,0成功
*/
public Integer delete_file(String group, String storagePath) {
int result = -1;
try {
result = storageClient.delete_file(group, storagePath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
} /**
* @param storagePath 文件的全部路径 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
* @return -1失败,0成功
* @throws IOException
* @throws Exception
*/
public Integer delete_file(String storagePath) {
int result = -1;
try {
result = storageClient.delete_file1(storagePath);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return result;
}
}

Java客户端文件上传、下载、删除和元数据获取测试:

package com.james.fdfs;
import org.junit.Test;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import  com.james.utils.FastDFSClientUtils; public class FastDFSClientUtilsTest { /**
* 文件上传测试
*/
@Test
public void testUpload() {
File file = new File("C:\\Users\\James\\Pic\\share.jpg");
Map<String,String> metaList = new HashMap<String, String>();
metaList.put("width","1024");
metaList.put("height","768");
String fid = FastDFSClientUtils.uploadFile(file,file.getName(),metaList);
System.out.println("upload local file " + file.getPath() + " ok, fileid=" + fid);
//上传成功返回的文件ID: group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg
} /**
* 文件下载测试
*/
@Test
public void testDownload() {
int r = FastDFSClientUtils.download_file("group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg", new File("DownloadFile_fid.jpg"));
System.out.println(r == 0 ? "下载成功" : "下载失败");
} /**
* 文件删除测试
*/
@Test
public void testDelete() {
int r = FastDFSClientUtils.delete_file("group1/M00/00/00/wKgAyVgFk9aAB8hwAA-8Q6_7tHw351.jpg");
System.out.println(r == 0 ? "删除成功" : "删除失败");
}
}

如果没有什么问题将会看到打印的日志。

Net版本

net版本可参考另外一位网友代码:

https://github.com/huanzui/fastdfs.client.net

问题

现在分布式文件平台已经完成了搭建和代码测试,但实践过程中还是有几个问题:

1、上传到平台的文件名都是无规律的64base编码过的字符串,因此如果只作为如图片等文件存储是没有问题的,因为我们不关心其文件名,但如果作为要下载的内容,如附件,或安装包,下载时如果还是编码那无法直观的知道此文件是做什么的,是要转换为正确的文件名。

解决:关于这个问题,网上有方法是通过nginx,利用域名和FID拼出url,然后在url后面增加一个参数,指定原始文件名。

例如:http://121.14.161.48:9030/group2/M00/00/89/eQ6h3FKJf_PRl8p4AUz4wO8tqaA688.apk?attname=filename.apk

在Nginx上进行如下配置,这样Nginx就会截获url中的参数attname,在Http响应头里面加上字段 Content-Disposition “attachment;filename=$arg_attname”。

这里只提供了一个方案,具体内容其实还需要一个篇幅来介绍,有时间再写吧。

2、实际用的时候我们其实是想按业务还将不同文件放在不同的文件夹中的,比如聊天文件,文档文件,还有临时文件 有时需要定时清理的,但分布式文件平台是没法指定文件夹的。

解决:最常用的做法是自己实现一个文件对应库,将上传的文件名,时间,对应的业务等信息与最终的文件路径对应起来,这样就可以作任何逻辑了,但缺点是非常麻烦。

FastDFS没有看到保存到指定的2级目录的API,但可以保存到指定的group,可以指定某个group为哪个业务用。但这样会破坏整个FastDFS的分布式结构,造成某个group非常巨大,而且不容易扩容。实际使用时还会有其它业务的内容进入到此group。

3、大文件如何断点续传?

如果文件大于100M,则需要断点续传的功能了,FastDFS对于大文件来说是有点吃力的,但还是可以实现,根据网友提供的方案来看就是需要客户进行切片上传,并且切片字节大小小于等于storage配置的buff_size,默认是256k,这一块需要自己实现。

高可用高性能分布式文件系统FastDFS实践Java程序的更多相关文章

  1. 高可用高性能分布式文件系统FastDFS进阶keepalived+nginx对多tracker进行高可用热备

    在上一篇 分布式文件系统FastDFS如何做到高可用 中已经介绍了FastDFS的原理和怎么搭建一个简单的高可用的分布式文件系统及怎么访问. 高可用是实现了,但由于我们只设置了一个group,如果现在 ...

  2. 【FastDFS】如何打造一款高可用的分布式文件系统?这次我明白了!!

    写在前面 前面我们学习了如何基于两台服务器搭建FastDFS环境,而往往在生产环境中,需要FastDFS做到高可用,那如何基于FastDFS打造一款高可用的分布式文件系统呢?别急,今天,我们就一起来基 ...

  3. 使用FastDFS打造一款高可用的分布式文件系统

    FastDFS 介绍 参考: http://www.oschina.net/p/fastdfs FastDFS 是一个开源的分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文 ...

  4. 分布式文件系统FastDFS动态扩容

    当用户量越来越大,则集群中某个group总会到达其极限,这时就得扩展集群的容量了. FastDFS的扩容分为对group纵向扩容和横向扩容 纵向扩容 指在同一个group组中增加服务器,实现数据冗余, ...

  5. FastDFS是使用c语言编写的开源高性能分布式文件系统

    FastDFS是什么 FastDFS是使用c语言编写的开源高性能分布式文件系统 是由淘宝开发平台部资深架构师余庆开发,FastDFS孵化平台板块 他对文件进行管理,功能包括文件存储,文件同步,文件访问 ...

  6. [转]分布式文件系统FastDFS架构剖析

    [转]分布式文件系统FastDFS架构剖析 http://www.programmer.com.cn/4380/ 文/余庆 FastDFS是一款类Google FS的开源分布式文件系统,它用纯C语言实 ...

  7. 【转】分布式文件系统FastDFS架构剖析

    FastDFS是一款类Google FS的开源分布式文件系统,它用纯C语言实现,支持Linux.FreeBSD.AIX等UNIX系统.它只能通过专有API对文件进行存取访问,不支持POSIX接口方式, ...

  8. 分布式文件系统FastDFS详解

    上一篇文章<一次FastDFS并发问题的排查经历>介绍了一次生产排查并发问题的经历,可能有些人对FastDFS不是特别的了解,因此计划写几篇文章完整的介绍一下这个软件. 为什么要使用分布式 ...

  9. (转)淘淘商城系列——分布式文件系统FastDFS

    http://blog.csdn.net/yerenyuan_pku/article/details/72801777 商品添加的实现,包括商品的类目选择,即商品属于哪个分类?还包括图片上传,对于图片 ...

随机推荐

  1. openstack操作之二 restful api

    Restful api 是openstack各服务调用的接口,简单理解为可以通过网络去调用的函数.postman是一款前端调用工具,测试后端接口的时候往往是使用该工具去验证.在openstack的使用 ...

  2. express学习

    一.入门 实际开发中一般使用express应用生成器(express-generator),直接生成项目目录,npm安装后再安装需要的依赖: 项目目录:app.js定义并导出整个应用: /bin/ww ...

  3. pstree 命令详解

    作用: 以命令树状图的方式展现进程之间的派生关系, 显示效果比较直观. 选项: -a 显示每个程序的完整指令, 包含路径, 参数或者是常驻服务的标志 -c 不使用精简标示法 -h 列出树状图,特别标明 ...

  4. Linux第七节随笔 diff /uniq /stat

    linux第七讲(上)1.diff link 作用:diff命令能比较单个文件或者目录内容.如果指定比较的是文件,则只有当输入为文本文件时才有效.以逐行的方式,比较文本文件的异同处. 如果指定比较的是 ...

  5. sourcetree跳过注册的方法

    当前只有Win的版本,Mac自行百度(笑) 很多人用git命令行不熟练,那么可以尝试使用sourcetree进行操作. 然鹅~~sourcetree又一个比较严肃的问题就是,很多人不会跳过注册或者操作 ...

  6. Android SDK Manager配置

    Android SDK Manager就是一个Android软件开发工具包管理器,就像一个桥梁,连通本地和服务器,从服务器下载安卓开发所需工具到本地. 而AVD Manager是一个Android虚拟 ...

  7. 关于php中,记录日志中,将数组转为json信息记录日志时遇到的问题总结

    1 中文编码化,无法看到具体的中文,如:你好  =>  \u4F60\u597D 解决方案:可以使用 json_encode($arr,JSON_UNESCAPED_UNICODE) 转义中文[ ...

  8. tornado返回指定的http code

    最近做web api,需要在接口返回异常时,返回对应的http code. 查了下tornado的文档,是通过set_status方法来设置返回的http code,做个记录. self.set_st ...

  9. CSS样式表学习

    ---恢复内容开始--- 今天学习的主要内容是样式表和选择器. 1.样式表的分类 1.内联式样式表 特点:能实现精确控制,但是范围太小.页面显示的优先级高于其他样式表 2.内嵌式样式表 特点:必须在h ...

  10. jQuery 数据操作函数(九)

    .clearQueue() 从队列中删除所有未运行的项目. .data() 存储与匹配元素相关的任意数据. jQuery.data() 存储与指定元素相关的任意数据. .dequeue() 从队列最前 ...