分布式文件系统FastDFS
FastDFS是一个开源的轻量级分布式文件系统,开发语言为C,适合以小型文件为载体的在线服务,如相册网站、图片服务器等等。
github地址:https://github.com/happyfish100/fastdfs
架构图如下
几个重要的概念:tracker、storage、client
client就是调用方,tracker负责元数据,要上传文件、下载文件先从tracker获取相应的storage,然后client和storage交互,进行实际的文件上传、下载等操作。
FastDFS 没有实现自己的存储,而是使用操作系统的文件系统进行存储的,实际存储是按两级目录来保存文件的。
一、安装
实际安装的是5.11版本,安装目录设置为 /opt
1、安装libfastcommon
fastdfs依赖这个库
cd /opt
wget https://github.com/happyfish100/libfastcommon/archive/master.zip
unzip libfastcommon-master.zip
cd libfastcommon-master
make.sh
/make.sh install
2、安装FastDFS
cd opt
wget https://github.com/happyfish100/fastdfs/archive/master.zip
unzip fastdfs-master.zip
cd fastdfs-master
./make.sh
./make.sh install
3、配置
#配置拷贝
cd /etc/fdfs/
ls
client.conf.sample storage.conf.sample tracker.conf.sample
cp client.conf.sample client.conf
cp storage.conf.sample storage.conf
cp tracker.conf.sample tracker.conf
tracker中一些重要的参数如下
base_path
max_connections
connect_timeout
network_timeout
work_threads
sync_log_buff_interval
storage一些重要参数:
connect_timeout
network_timeout
heart_beat_interval
base_path
max_connections
work_threads
tracker_server(可以设置多行)
这里不具体详述每个参数的意义,具体可以参考官方文档。
二、使用
1、php
安装扩展,代码在FastDFS 的php_client目录,按标准的扩展安装即可。
安装完在php.ini加上如下,路径根据自己安装目录调整
fastdfs_client.base_path=/opt/fastdfs
fastdfs_client.tracker_group_count = 1
fastdfs_client.tracker_group0 = /etc/fdfs/client.conf
示例代码如下
<?php
//上传文件
function uploadFile(){
$fdfs = new FastDFS();
$tracker = $fdfs->tracker_get_connection();
$storager = $fdfs->tracker_query_storage_store('group1', $tracker);
$localFileName = '/home/liujh/projects/xman/url.txt';
$fileRes = $fdfs->storage_upload_by_filename($localFileName, "txt", ["image" => "url"], "group1", $tracker, $storager);
var_dump($fileRes);
$fdfs->tracker_close_all_connections();
}
//获取文件信息
function getFile(){
$fileName = 'M00/00/00/rBVq5F1DyCOAURnnAAAPAnkf924742.txt';
$fdfs = new FastDFS();
$buf = $fdfs->storage_download_file_to_buff('group1', $fileName);
var_dump($buf);
}
//获取文件元信息
function getMeta(){
$fileName = 'M00/00/00/rBVq5F1DyCOAURnnAAAPAnkf924742.txt';
$fdfs = new FastDFS();
$buf = $fdfs->storage_get_metadata('group1', $fileName);
var_dump($buf);
}
//删除文件
function delete(){
$fileName = 'M00/00/00/rBVq5F1DyCOAURnnAAAPAnkf924742.txt';
$fdfs = new FastDFS();
$buf = $fdfs->storage_delete_file('group1', $fileName);
var_dump($buf);
}
getFile();
2、Java
先在init方法进行初始化
public class FastDFSClintFactor{
@Value("#{'${connectTimeout}'}")
private String connectTimeout;
@Value("#{'${tracker_server}'}")
private String trackerServers;
//初始化
private void init(){
// 链接超时
if(connectTimeout != null && connectTimeout.length > 0){
ClientGlobal.setG_connect_timeout(Integer.valueOf(connectTimeout));
} else {
ClientGlobal.setG_connect_timeout(ClientGlobal.DEFAULT_CONNECT_TIMEOUT);
}
// 服务器
if((trackerServers!= null && trackerServers.length > 0!)){
InetSocketAddress[] addresss = this.getTrackerServerArray(trackerServers);
ClientGlobal.setG_tracker_group(new TrackerGroup(addresss));
} else {
throw new NullPointerException("the value of item "tracker_server" is null. ");
}
}
}
再创建trackerServer
// 链接服务器
trackerServer = new TrackerClient().getConnection();
最后是创建client及使用
public StorageClient getStorageClient(){
return new StorageClient(trackerServer, null);
}
// 文件属性
List<NameValuePair> nvpList = new ArrayList<NameValuePair>();
nvpList.add(new NameValuePair(FILENAME_KEY, fileSrcName));
nvpList.add(new NameValuePair(FILEEXTNAME_KEY, fileExtName));
NameValuePair[] metas = nvpList.toArray(new NameValuePair[0]);
// 上传文件
try {
StorageClient sc = fastDFSManager.getStorageClient();
String[] result = sc.upload_file(bytes, fileExtName, metas);
}catch (Exception e) {
logger.error("上传文件到FastDFS服务器异常,文件名:" + fileName, e);
return null;
}
三、使用踩坑
刚上线时有时候一些文件写入时大小为0,看了代码目前是长连接的实现方式,在MSHUT_DONW中才关闭连接,实际生产环境php-fpm的max_request会配置较大,造成服务端关闭连接但客户端还没关闭,因而许多连接取不到数据,修复方案改为短连接,修改文件fastdfs_client.c,代码如下:
//启用
zend_module_entry fastdfs_client_module_entry = {
STANDARD_MODULE_HEADER,
"fastdfs_client",
fastdfs_client_functions,
PHP_MINIT(fastdfs_client),
PHP_MSHUTDOWN(fastdfs_client),
NULL,//PHP_RINIT(fastdfs_client),
PHP_RSHUTDOWN(fastdfs_client),//PHP_RSHUTDOWN(fastdfs_client),
PHP_MINFO(fastdfs_client),
"1.00",
STANDARD_MODULE_PROPERTIES
};
PHP_RSHUTDOWN_FUNCTION(fastdfs_client)
{
FDFSConfigInfo *pConfigInfo;
FDFSConfigInfo *pConfigEnd;
if (!g_use_connection_pool){
if (config_list != NULL)
{
pConfigEnd = config_list + config_count;
for (pConfigInfo=config_list; pConfigInfo<pConfigEnd;
pConfigInfo++)
{
if (pConfigInfo->pTrackerGroup != NULL)
{
tracker_close_all_connections_ex(
pConfigInfo->pTrackerGroup);
}
}
}
}
return SUCCESS;
}
四、写在最后
从架构图来看,FastDFS是高可用的,但故障发生时会丢失数据吗?答案是会丢,因为storage之间的文件同步是异步的,所以在client上传文件完后,storage已经返回响应给client了,如果这个时候文件还没有同步到其它的storage,则这个文件就丢了。
这里还有个问题,如果storage cluster有2个实例 st1, st2,如果client将文件上传到st1上,这个时间如果文件还没有同步到st2,这个时间client访问到st2了,这个时间就取不到数据了。针对这个问题,可以安装nginx模块
fastdfs-nginx-module来解决,不过这样一来运维成本也增加了,系统的复杂性也增加了。
总的来说,FastDFS是一个勉强能用的分布式文件系统,离真正的高可用、不丢数据、运维方便还有些距离。
- 基数排序与桶排序,计数排序【详解】
- SG函数和SG定理【详解】
- 密码学经典之生日悖论与生日攻击【详解】
- POJ 1659 Frogs' Neighborhood(可图性判定—Havel-Hakimi定理)【超详解】
- BZOJ 1192: [HNOI2006]鬼谷子的钱袋(新生必做的水题)
- 快速傅里叶变换(FFT)算法【详解】
- Codeforces Round #416 (Div. 2)(A,思维题,暴力,B,思维题,暴力)
- 作为程序员的你在外行人眼里是一个怎样的群体?
- 高斯消元法(Gauss Elimination)【超详解&模板】
- [快学Python3]读写Excel - openpyxl库
- HDU 2147 kiki's game(规律,博弈)
- HDU 1847 Good Luck in CET-4 Everybody!(规律,博弈)
- [network][udp]你不要偷偷发包,我跟你讲
- [快学Python3]HTTP处理 - urllib模块
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 严格模式
- 闭包与高阶函数
- IDEA设置maven修改settings.xml配置文件无法加载仓库
- 在Linux下如何根据域名自签发OpenSSL证书与常用证书转换 修改openssl.cnf配置文件创建根证书自签发泛域名证书将crt转pem格式生成 p12 格式的
- CAS 原子操作
- FlutterDojo设计之道—状态管理之路(七)
- Kubernetes K8S之存储ConfigMap详解 通过目录创建通过文件创建通过命令行创建通过yaml文件创建当前存在的ConfigMap使用ConfigMap
- Material Components——Shape的处理
- pandas系列 - (一)明细数据汇总简单场景应用
- Spring系列 SpringMVC的请求与数据响应
- PHP代码审计03之实例化任意对象漏洞
- 最简单入门深度学习
- Redis 字典结构细谈
- 终于弄明白 i = i++和 i = ++i 了
- 更简易的机器学习-pycaret的安装和环境初始化