分布式文件系统FastDFS

FastDFS


一、fastDFS

1.fastDFS概述

fastDFS是c语言编写的一款开源的分布式文件系统(余庆淘宝架构师)。为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,注重高可用、高性能等指标。可以很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。图床、网盘

  1. 冗余备份: 纵向扩容
  2. 线性扩容: 横向扩容
fastDFS框架中的三个角色具体说明
追踪器Tracker - 管理者(守护进程)管理存储节点
存储节点 - storage(守护进程)存储节点是有多个的
客户端 - 开发者编写的程序(非守护进程)文件上传、文件下载
2.fastDFS模块
  1. 追踪器:最先启动追踪器

  2. 存储节点:第二个启动的角色,存储节点启动之后, 会单独开一个线程

    • 汇报当前存储节点的容量, 和剩余容量
    • 汇报数据的同步情况
    • 汇报数据被下载的次数
  3. 客户端:最后启动

    • 上传文件:连接追踪器, 询问存储节点的信息

      • 我要上传1G的文件, 询问那个存储节点有足够的容量

      • 追踪器查询, 得到结果

      • 追踪器将查到的存储节点的 IP + port 发送给客户端

      • 通过得到IP和端口连接存储节点

      • 将文件内容发送给存储节点(Socket通信)

        在这里插入图片描述

    • 下载文件:连接追踪器, 询问存储节点的信息

      • 询问, 要下载的文件在哪一个存储节点

      • 追踪器查询, 得到结果

      • 追踪器将查到的存储节点的 IP + port 发送给客户端

      • 通过得到IP和端口连接存储节点

      • 下载文件(Socket通信)

        在这里插入图片描述

3.fastDFS集群

在这里插入图片描述

(1)追踪器集群:

为了避免单点故障,可以建立追踪器集群。多个Tracker追踪器通过轮训的方式来进行工作,可以通过修改配置文件的方式实现集群。

(2)存储节点集群:
  • fastDFS管理存储节点的方式:通过分组的方式完成的
  • 集群方式(扩容方式)
    • 横向扩容 - 增加容量
      • 添加一台新的主机 -> 容量增加了
      • 假设当前有两个组: group1, group2,需要添加一个新的分组 -> group3,新主机属于第三组
      • 不同组的主机之间不需要通信
    • 纵向扩容 - 数据备份
      • 假设当前有两个组: group1, group2
        • 将新的主机放到现有的组中
        • 每个组的主机数量从1 -> n
          • 这n台主机的关系就是相互备份的关系
          • 同一个组中的主机需要通信
          • 每组的容量 == 容量最小的这台主机

二、fastDFS使用

1.fastDFS的安装
  • libfastcommon-1.36.zip(fastdfs的基础库)
    • unzip xxx.zip
    • ./make.sh
    • ./make.sh install
  • fastdfs-5.10.tar.gz
    • tar zxvf xxx.tar.gz
    • ./make.sh
    • ./make.sh install
  • 测试
#fastDFS安装的所有的可执行程序: 
/usr/bin/fdfs_*
fdfs_test
2.fastDFS配置文件

配置文件默认位置: /etc/fdfs,

文件夹内容:client.conf.sample storage.conf.sample storage_ids.conf.sample tracker.conf.sample

  1. tracker 配置文件

    # 将追踪器和部署的主机的IP地址进程绑定, 也可以不指定
    # 如果不指定, 会自动绑定当前主机IP, 如果是云服务器建议不要写
    bind_addr=192.168.247.135
    # 追踪器监听的端口
    port=22122
    # 追踪器存储日志信息的目录, xxx.pid文件, 必须是一个存在的目录
    base_path=/home/yuqing/fastdfs
    
  2. storage 配置文件

    # 当前存储节点对应的主机属于哪一个组
    group_name=group1
    # 当前存储节点和所应该的主机进行IP地址的绑定, 如果不写, 有fastdfs自动绑定
    bind_addr=
    # 存储节点绑定的端口
    port=23000
    # 存储节点写log日志的路径
    base_path=/home/yuqing/fastdfs
    # 存储节点提供的存储文件的路径个数
    store_path_count=2
    # 具体的存储路径
    store_path0=/home/yuqing/fastdfs
    store_path1=/home/yuqing/fastdfs1
    # 追踪器的地址信息
    tracker_server=192.168.247.135:22122 
    tracker_server=192.168.247.136:22122 
    
  3. 客户端配置文件

    # 客户端写log日志的目录
    # 该路径必须存在
    # 当前的用户对于该路径中的文件有读写权限
    # 当前用户robin
    # 指定的路径属于root
    base_path=/home/yuqing/fastdfs
    # 要连接的追踪器的地址信息
    tracker_server=192.168.247.135:22122 
    tracker_server=192.168.247.136:22122 
    
3.fastDFS的启动
  1. 第一个启动追踪器 - 守护进程

    # 启动程序在 /usr/bin/fdfs_*
    # 启动
    fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf) 
    # 关闭
    fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf)  stop
    # 重启
    fdfs_trackerd 追踪器的配置文件(/etc/fdfs/tracker.conf) restart
    
  2. 第二个启动存储节点 - 守护进程

    # 启动
    fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf)
    # 关闭
    fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf) stop
    # 重启
    fdfs_storaged 存储节点的配置文件(/etc/fdfs/stroga.conf) restart
    
  3. 最后启动客户端 - 普通进程

    # 上传
    fdfs_upload_file 客户端的配置文件(/etc/fdfs/client.conf) 要上传的文件
    # 得到的结果字符串: group1/M00/00/00/wKj3h1vC-PuAJ09iAAAHT1YnUNE31352.c
    # 下载
    fdfs_download_file 客户端的配置文件(/etc/fdfs/client.conf) 上传成功之后得到的字符串(fileID)
    
  4. fastDFS状态检测

    fdfs_monitor /etc/fdfs/client.conf
    
    # FDFS_STORAGE_STATUS:INIT      :初始化,尚未得到同步已有数据的源服务器
    # FDFS_STORAGE_STATUS:WAIT_SYNC :等待同步,已得到同步已有数据的源服务器
    # FDFS_STORAGE_STATUS:SYNCING   :同步中
    # FDFS_STORAGE_STATUS:DELETED   :已删除,该服务器从本组中摘除
    # FDFS_STORAGE_STATUS:OFFLINE   :离线
    # FDFS_STORAGE_STATUS:ONLINE    :在线,尚不能提供服务
    # FDFS_STORAGE_STATUS:ACTIVE    :在线,可以提供服务
    

Storage Server的7种状态:https://blog.csdn.net/u014723529/article/details/46048411

4.对file_id的解释

在这里插入图片描述

  • group1

    • 文件上传到了存储节点的哪一个组
    • 如果有多个组这个组名可变的
  • M00 - 虚拟目录

    • 和存储节点的配置项有映射

      store_path0=/home/yuqing/fastdfs/data -> M00
      store_path1=/home/yuqing/fastdfs1/data -> M01

  • 00/00

    • 实际的路径
    • 可变的
  • wKhS_VlrEfOAdIZyAAAJTOwCGr43848.md

    • 文件名包含的信息
    • 采用Base64编码:包含的字段包括
      • 源storage server Ip 地址

      • 文件创建时间

      • 文件大小

      • 文件CRC32效验码 :循环冗余校验

      • 随机数

三、上传下载代码实现

1.使用多进程方式实现

在这里插入图片描述

获取最终上传的文件id:file_id的程序,

  • exec函数族函数

    • execl
    • execlp
  • 子进程 -> 执行execlp(“fdfs_upload_file” , “xx”, arg, NULL), 有结果输出, 输出到终端

    • 不让它写到终端 -> 重定向dup2(old, new),old-> 标准输出、new -> 管道的写端
    • 文件描述符
    • 数据块读到内存 -> 子进程
    • 数据最终要给到父进程
    • 进程间通信:pipe -> 读端, 写端
    • 在子进程创建之前创建就行了
  • 父进程

    • 读管道 -> 内存
    • 内存数据写入数据库
2.使用fastDFS 提供的API实现

将fastDFS 提供的API,进行针对业务的修改,也能实现文件的上传操作:

/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdfs_client.h"
#include "logger.h"

static void usage(char *argv[]) {
	printf("Usage: %s <config_file> <local_filename> " \
	       "[storage_ip:port] [store_path_index]\n", argv[0]);
}

int main(int argc, char *argv[]) {
	char *conf_filename;
	char *local_filename;
	char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
	ConnectionInfo *pTrackerServer;
	int result;
	int store_path_index;
	ConnectionInfo storageServer;
	char file_id[128];

	if (argc < 3) {
		usage(argv);
		return 1;
	}

	log_init();
	g_log_context.log_level = LOG_ERR;
	ignore_signal_pipe();

	conf_filename = argv[1];
	if ((result=fdfs_client_init(conf_filename)) != 0) {
		return result;
	}

	pTrackerServer = tracker_get_connection();
	if (pTrackerServer == NULL) {
		fdfs_client_destroy();
		return errno != 0 ? errno : ECONNREFUSED;
	}

	local_filename = argv[2];
	*group_name = '\0';
	if (argc >= 4) {
		const char *pPort;
		const char *pIpAndPort;

		pIpAndPort = argv[3];
		pPort = strchr(pIpAndPort, ':');
		if (pPort == NULL) {
			fdfs_client_destroy();
			fprintf(stderr, "invalid storage ip address and " \
			        "port: %s\n", pIpAndPort);
			usage(argv);
			return 1;
		}

		storageServer.sock = -1;
		snprintf(storageServer.ip_addr, sizeof(storageServer.ip_addr), \
		         "%.*s", (int)(pPort - pIpAndPort), pIpAndPort);
		storageServer.port = atoi(pPort + 1);
		if (argc >= 5) {
			store_path_index = atoi(argv[4]);
		} else {
			store_path_index = -1;
		}
	} else if ((result=tracker_query_storage_store(pTrackerServer, \
	                   &storageServer, group_name, &store_path_index)) != 0) {
		fdfs_client_destroy();
		fprintf(stderr, "tracker_query_storage fail, " \
		        "error no: %d, error info: %s\n", \
		        result, STRERROR(result));
		return result;
	}

	result = storage_upload_by_filename1(pTrackerServer, \
	                                     &storageServer, store_path_index, \
	                                     local_filename, NULL, \
	                                     NULL, 0, group_name, file_id);
	if (result == 0) {
		printf("%s\n", file_id);
	} else {
		fprintf(stderr, "upload file fail, " \
		        "error no: %d, error info: %s\n", \
		        result, STRERROR(result));
	}

	tracker_disconnect_server_ex(pTrackerServer, true);
	fdfs_client_destroy();

	return result;
}

补充:Linux下进行源码安装

  1. 找可执行文件 configure
    • 执行这个可执行文件
      • 检测安装环境
      • 生成 makefile
  2. 执行make命令
    • 编译源代码
      • 生成动态库
      • 生成静态库
      • 可执行程序
  3. 安装 make install (需要管理员权限)
    • 将第三步生成的动态库/动态库/可执行程序拷贝到对应的系统目录
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值