CentOS7安装FastDFS

该文章将不在进行维护,文件存储服务建议使用别的,这里推荐使用minio

壹、前提须知

笔者环境介绍:服务器选择 :CentOS7.9

提前下载你的软件,其中#版本号表示笔者使用的版本号,本文将采用/usr/local/fastdfs作为文件的上传路径:

贰、安装libfastcommon

Ⅰ、环境安装

#安装GCC-c++
yum -y install gcc-c++
#安装libevent库
yum -y install libevent

Ⅱ、解压并安装

解压

tar -zxvf libfastcommon-1.0.60.tar.gz

进入解压的文件夹

cd /usr/local/fastdfs/libfastcommon-1.0.60/

安装并编译

./make.sh
./make.sh install

image

Ⅲ、复制libfastcommon.so

仅仅适用于低版本,高版本将不需要进行复制

现在需要将libfastcommon.so复制到/usr/lib/当中,为了确保你确实在这个文件夹下没有当前文件你可以先进行查看。

[root@musiro ~]#find / -name libfastcommon.so
> /usr/local/fastdfs/libfastcommon-1.0.60/src/libfastcommon.so
> /usr/lib/libfastcommon.so
> /usr/lib64/libfastcommon.so

笔者是高版本已经自动复制了,如果你是低版本请执行下面这句话来进行复制。

cp /usr/lib64/libfastcommon.so /usr/lib

叁、安装FastDFS

Ⅰ、解压并安装

解压

tar -zxvf fastdfs-6.08.tar.gz

进入解压的文件夹

cd /usr/local/fastdfs/fastdfs-6.08.tar.gz/

安装并编译,安装完成后解压的文件夹会被自动删除。

./make.sh
./make.sh install

image

重新解压并将没有添加的配置文件全部转过去。尤其是http.conf

tar -zxvf ../fastdfs-6.08.tar.gz
cp /usr/local/fastdfs/fastdfs-6.08/conf/ /etc/fdfs/

Ⅱ、修改配置文件

首先需要准备一个目录用于存储跟踪节点trackerd的文件。

mkdir -p /usr/local/fastdfs/tracker/

然后修改tracker的配置文件,修改内容如图。

vim /etc/fdfs/tracker.conf

image

Ⅲ、配置跟踪端tracker

根据我的参考文献的大佬建议,不是老油条别设置开机自启。如果出错了就开不了机了,必须重装。为了不折磨你和我,这里我也不CV过来了。

# 启动start 重启restart 关闭stop。修改末尾即可
fdfs_trackerd /etc/fdfs/tracker.conf start
# 查看是否启动
netstat -tnlp | grep trackerd

image

肆、配置存储端Storage

Ⅰ、开启防火墙和安全组

需要开放22122与23000端口,这是fastdfs默认的端口。可以通过配置文件进行修改。

  • 如果你不喜欢开启防火墙跳过
  • 如果你不是云服务器跳过
# 放开端口
firewall-cmd --zone=public --add-port=22122/tcp --permanent
firewall-cmd --zone=public --add-port=23000/tcp --permanent
# 重启防火墙
systemctl restart firewalld

Ⅱ、配置Storage

和tracker一样先创建一个存储的文件夹,这个是存储端。

mkdir -p /usr/local/fastdfs/storage/

配置,配置内容如图所示。如果嫌找不到,在命令模式输入/跟上需要查找的内容就可快速定位。

vim /etc/fdfs/storage.conf

image

Ⅲ、启动

启动

fdfs_storaged /etc/fdfs/storage.conf start

image

查看storage目录下data文件,如果不是如果所示那么你就出错了。可以查看storage下log日志查看错误原因。
image

Ⅳ、小葵花课堂

笔者笔者我启动没有创建目录怎么办?呜呜呜呜!!!就是下面这张图这样!!
image

哼! 防火墙配置开没? 安全组打开没? 开完重新启动下就行了fdfs_storaged /etc/fdfs/storage.conf restart

伍、配置客户端Client

这个不是必须配置的 如果你不使用服务器直接上传文件,其实这个可以不进行配置。如果需要测试啥的可以配置下。这个也很简单。

Ⅰ、配置Client

创建客户端文件路径

mkdir -p /usr/local/fastdfs/client/

修改配置文件,配置内容如下图。

vim /etc/fdfs/client.conf

image

Ⅱ、上传文件进行尝试

准备好一个文件,笔者准备一张图/home/123.jpg在这个目录下。

[root@musiro ~]#fdfs_test /etc/fdfs/client.conf upload  /home/123.jpg
> example file url: http://马赛克/group1/M00/00/00/ctklUmMhTpaAaJTxAADg_skRKOk898.jpg

ok,成功上传。之后我们可以通过http://马赛克/group1/M00/00/00/ctklUmMhTpaAaJTxAADg_skRKOk898.jpg进行访问。但是现在依然是访问不了的。why?因为fastdfs用的自己的协议,但是http协议他看不懂,需要一个翻译来给他翻译翻译。这个时候作者就提供了一个翻译官nginx-fastdfs。那么就需要配置nginx来进行翻译。

陆、配置解释器fastdfs-nginx

Ⅰ、修改fastdfs-nginx的nginx指令的作用位置

解压

tar -zxvf fastdfs-nginx-module-1.22.tar.gz

修改配置文件,修改内容如图。你可以手动修改也可以通过指令:%s/local\///g来快速快速修改。

vim /usr/local/fastdfs/fastdfs-nginx-module-1.22/src/config

image

Ⅱ、配置fastdfs-nginx

首先现将文件拷贝到总的配置文件夹下

cp /usr/local/fastdfs/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf /etc/fdfs/

修改配置文件,修改的内容如图所示。

vim /etc/fdfs/mod_fastdfs.conf

image

柒、配置Nginx

Ⅰ、安装Nginx

安装需要的依赖

#yum install -y pcre pcre-devel;yum install -y zlib zlib-devel;yum install -y openssl openssl-devel;
yum install -y pcre pcre-devel
yum install -y zlib zlib-devel
yum install -y openssl openssl-devel

解压nginx

tar -zxvf nginx-1.22.0.tar.gz
# 进入niginx文件夹
cd /usr/local/fastdfs/nginx-1.22.0/

添加模块并进行安装

#./configure --add-module=[你的fastdfs-nginx的src的绝对路径]
./configure --add-module=/usr/local/fastdfs/fastdfs-nginx-module-1.22/src

#安装
make &make install

配置环境

vim /etc/profile
# 添加如果两句话
export NGINX_HOME=/usr/local/nginx
export PATH=${NGINX_HOME}/sbin:$PATH

重新加在配置文件,从此你可以再任何位置启动nginx

source /etc/profile

启动nginx

nginx
# 查看是否正常启动nginx,如果你没有出现工作进程worker,那么请看下面问题解析找到你的问题。
[root@musiro ~]# netstat -tnlp | grep nginx
root     29292  0.0  0.0  28288  1608 ?        Ss   15:07   0:00 nginx: master process nginx
nobody   31107  0.0  0.0  31084  2532 ?        S    15:32   0:00 nginx: worker process

Ⅱ、配置NGINX

进入nginx配置文件,再server的括号中添加一下内容。注意server不是让你添加的,只是添加里面的内容。

server {
	# 如果访问路径为/group1/M00就将他直接转发给fastdfs-nginx处理而不是服务器处理
	location ~/group1/M00{
		ngx_fastdfs_module;
	}
}

重新加载nginx

nginx -s reload

此时你可以将之前的那个连接进行访问,嗯哼!成功了

Ⅲ、小葵花课堂

各路神仙问题将在这里汇总,最终解释权为cat /usr/local/nginx/log/error.log

我已经帮各位踩坑踩完了,理论上你不可能出现其他错误。请跟着序号一个一个尝试错误。

  • A:/etc/fdfs下有没有这些文件?

  • B:你的配置文件mod_fastdfs.conf是否配置正确,没有多或少符号?

  • C:你是否没有成功启动tracker和stroger。如果Client上传图片没问题,那么这里也不会有问题。

  • D:nginx端口是否冲突,默认80

  • E:防火墙安全组是否开启

之后就是一些可能

  • F:权限不够:可以尝试将nginx.conf中#user nobody修改为user root
  • G:使用非原生nginx,未添加fastdfs模块?

捌、Https转型

将传输的协议设置为加密协议,这里只讲解有证的,不知道从哪里摸来的证建议就跳过吧。

Ⅰ、设置防火墙与安全组

需要打开443端口

firewall-cmd --zone=public --add-port=443/tcp --permanent
systemctl restart firewalld

Ⅱ、证书安装

首先创建一个文件夹来存放你的证,然后拿着你的证上传到服务器上。

mkdir /usr/local/nginx/conf/cert

解压你的证

unzip 马赛克_nginx.zip

编辑nginx文件 配置内容如下

vim /usr/local/nginx/conf/nginx.conf

# ————————————————————————————此教程来源于阿里云官方教程————————————————————————————
# ————————————————————————————这些可以直接复制过去然后根据备注修改————————————————————————————
#以下属性中,以ssl开头的属性表示与证书配置有关。
server {
	#配置HTTPS的默认访问端口为443。
	#如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
	#【需要修改】如果您使用Nginx 1.15.0及以上版本,请使用listen 443 ssl代替listen 443和ssl on。
	listen 443 ssl;
	#【需要修改】需要将yourdomain替换成证书绑定的域名。
	server_name yourdomain;
	root html;
	index index.html index.htm;
	# 【需要修改】 注意cert-file-name修改成你的证书的完整名称 我的是 数字_域名_nginx
	ssl_certificate cert/cert-file-name.pem;  
	ssl_certificate_key cert/cert-file-name.key; 
	ssl_session_timeout 5m;
	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
	#表示使用的加密套件的类型。
	ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #表示使用的TLS协议的类型,您需要自行评估是否配置TLSv1.1协议。
	ssl_prefer_server_ciphers on;
	location / {
		root html;  #Web网站程序存放目录。
		index index.html index.htm;
	}
	# 这里是你的fastFDS服务
	# 如果访问路径为/group1/M00就将他直接转发给fastdfs-nginx处理而不是服务器处理
	location ~/group1/M00/{
		ngx_fastdfs_module;
	}
	# 这一坨我建议带上 这样可以重定向到一个默认的页面
	error_page  404              /404.html;
	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   html;
	}
}

# ————————————————————————————可选项————————————————————————————
# 如果您希望所有的HTTP访问自动跳转到HTTPS页面,则可以在需要跳转的HTTP站点下添加以下rewrite语句
# nginx自带一个80 我的建议是直接覆盖全部只留下这些
server {
	listen 80;
	# 【需要修改】需要将yourdomain替换成证书绑定的域名。
	server_name yourdomain;
	rewrite ^(.*)$ https://$host$1; #将所有HTTP请求通过rewrite指令重定向到HTTPS。
	location / {
		index index.html index.htm;
	}
}

重启nginx服务器

nginx -s reload

如果出错了可以查看下面关于这一节错误汇总

Ⅲ、修改tracker、storage、client配置文件

# 进入配置文件目录
cd /etc/fdfs/ 
# 修改 将http.server_port设置为443 这里不再阐述怎么修改
# 修改 tracker.conf 与 storage.conf 中 http.server_port 为 443
# 修改 client.conf 的 http.tracker_server_port 为 443
#重启服务
fdfs_trackerd /etc/fdfs/tracker.conf restart;fdfs_storaged /etc/fdfs/storage restart
# 查看是否开启
netstat -unltp|grep fdfs
# 看见两个都是开启的,尝试下上传文件
fdfs_test /etc/fdfs/client.conf upload /home/img/123.jpg
# 上传成功,配置没有问题。尝试访问返回的图片,将开头改成https://域名//group1....
# 完美显示

到这里你已经完美实现了搭建FastDFS服务。芜湖!!!!!!!!!!

Ⅳ、小葵花课堂

⒈、ngx_http_ssl_module报错

错误内容 the "ssl" parameter requires ngx_http_ssl_module
原因:您需要重新编译Nginx并在编译安装的时候加上--with-http_ssl_module配置。
回到之间安装nginx步骤重新进行编译

# 杀进程 重编译 重安装 启动。运行不影响之前的配置,仅仅修改nginx/sbin文件
nginx -s stop;./configure --add-module=/usr/local/fastdfs/fastdfs-nginx-module-1.22/src --with-http_ssl_module;make & make install;nginx

⒉、BIO_new_file:no such file错误

错误内容 "/cert/XXXXX_demo.aliyundoc.com.pem":BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('XXXXXXXXXX','r') error:2006D080:BIO routines:BIO_new_file:no such file)报错:您需要去掉证书相对路径最前面的/。
原因:nginx在配置ssl_certificate配置的时候路径写错了,只要是报这类错误都是路径写错了。

玖、安全模块的设置

指定能够有权限的上传下载删除服务器使用,而不能所有人都能够访问

#只需要将需要的能够通过的端口设置号就行了。
#首先打开tracker于storage的配置文件
cd /etc/fdfs
# 修改tranker.conf 于 storage 的 allow_hosts参数
# 后面跟上通过的IP地址即可 如果需要设置多个就多些几个参数
# java的服务通过脚本访问需要开放服务器IP才行,输入localhsot还是会阻止
allow_hosts = 服务器IP
allow_hosts = 电脑的WiFi IP
# 然后重启服务即可
fdfs_trackerd /etc/fdfs/tracker.conf restart;fdfs_storaged /etc/fdfs/storage.conf restart;netstat -unltp|grep fdfs

拾、删除FastDFS服务

开个玩笑,之前以为服务有问题删除了准备重装,谁知道是自己搞错了。写都写了懒得删了

# 停止服务
service fdfs_trackerd stop;service fdfs_storaged stop;
# 查看pid
ps -ef | grep fdfs
# 杀死进程 xxxx是你查询的结果
kill xxxx
# 删除本地存储的配置和日志路径 这个是你配置文件里面的路径。
# 注意删除的范围
rm -rf /home/fastDFS_data/*
# 剩下就是疯狂删除
# 删除默认的安装目录 即你的解压的文件在哪里。
rm -rf /etc/fdfs
# 剩下的几乎大家都是一样的,应该都没有动过。可以直接运行。直接删除全部
rm -rf /usr/bin/fdfs_*;rm -rf /usr/bin/stop.sh/rm -rf /usr/bin/restart.sh;rm -rf /usr/include/fastdfs;rm -rf /usr/include/fastcommon;rm -rf /usr/lib64/libfdfsclient*;rm -rf /usr/lib/libfdfsclient*;

拾壹、通过Java操作FastDFS

来到熟悉的代码环节,首先是依赖的注入。

官方的那个导不进去 另一个又各种安全漏洞。所以最后还是选这个

<!-- https://mvnrepository.com/artifact/net.oschina.zcx7878/fastdfs-client-java -->
<dependency>
    <groupId>net.oschina.zcx7878</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27.0.0</version>
</dependency>

首先需要准备一个配置文件。取名为xxxx.conf即可。我这里取名为fdfs.conf。配置的内容如下

# 超时时间
connect_timeout = 10
network_timeout = 30
# 编码字符集
charset = UTF-8
# tracker 服务器的 IP 和端口
tracker_server = 你的tracker地址:22122

配置号后将改文件放置在你的resources文件夹下即可
image

之后就是直接粘贴上我的工具包。直接通过调用方法使用即可

/**
 * 该类用于FastDFS服务的操作工具类
 * 需要依赖
 * <br/>
 * {@code
 * <groupId>net.oschina.zcx7878</groupId>
 * <artifactId>fastdfs-client-java</artifactId>
 * <version>1.27.0.0</version>
 *         }
 * @author musiro
 * @version 0.2
 * @date 2022/7/24
 */
@Slf4j
public final class FastDFSUtil {

	/**
     * 获取tracker服务
     */
	private static final TrackerServer trackerServer;

	/**
     * 获取storage服务
     */
	private static final StorageServer storageServer;

	/**
     * 防止Socket报错,导致上传成功却没有返回存储的路径
     */
	final static ReentrantLock writeLock = new ReentrantLock();

	/**
     * 上传文件[无法分段上传]
     * @param fileName 文件名--不需要带后缀
     * @param ext 文件后缀
     * @param bytes 二进制文件
     * @return 参数
     * <ul>
     *     <li>结果[0]: 组名 例如:group1</li>
     *     <li>结果[1]: 保存服务器的位置 例如:M01/00/00/rBNTRGGKX7aEG67qAAAAAIpTlYQ431.jpg</li>
     * </ul>
     * @throws InterruptedException
     * @throws MyException
     * @throws IOException
     */
	public static String[] upload(String fileName,String ext,byte[] bytes){
		return upload(fileName,ext,String.valueOf(bytes.length),(t,u)-> {
			try {
				return t.upload_file(bytes, ext, u);
			} catch (MyException | IOException e) {
				log.error("文件上传出错 : {}",e.getCause());
			}
			return null;
		});
	}


	/**
     * 此方法只适用于本地测试使用,Springboot方法可以使用另一个方法
     * @param path 图片路径
     * @param ext 文件
     * @param fileName 文件名称
     * @return
     * <ul>
     *     <li>结果[0]: 组名 例如:group1</li>
     *     <li>结果[1]: 保存服务器的位置 例如:M01/00/00/rBNTRGGKX7aEG67qAAAAAIpTlYQ431.jpg</li>
     * </ul>
     * @throws MyException
     * @throws IOException
     */
	public static String[] upload(String path,String ext,String fileName){
		long fileSize = new File(path).length();
		return upload(fileName,ext,Long.toBinaryString(fileSize),(t,u)-> {
			try {
				return t.upload_file(path,ext,u);
			} catch (MyException | IOException e) {
				log.error("文件上传出错 : {}",e.getCause());
			}
			return null;
		});
	}


	/**
     * 文件下载
     * @param groupName 组名 例如:group1
     * @param path 完整路径 例如:M01/00/00/rBNTRGGKX7aEG67qAAAAAIpTlYQ431.jpg
     * @return 文件流
     * @throws InterruptedException
     * @throws MyException
     * @throws IOException
     */
	public static byte[] download(String groupName,String path) throws InterruptedException, MyException, IOException {
		//获取连接
		StorageClient connection = getClientInfo();
		//下载文件
		return connection.download_file(groupName,path);
	}

	/**
     * 删除文件
     * @param groupName 组名 例如:group1
     * @param path 完整路径 例如:M01/00/00/rBNTRGGKX7aEG67qAAAAAIpTlYQ431.jpg
     * @throws InterruptedException
     * @throws MyException
     * @throws IOException
     */
	public static void delete(String groupName,String path) throws  MyException, IOException {
		//获取连接
		StorageClient connection = getClientInfo();
		//下载文件
		connection.delete_file(groupName,path);
	}

	//=====================私有方法====================

	/**
     * 初始化一些参数
     */
	static {
		try {
			ClientGlobal.init("fdfs.conf");
			TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
		} catch (IOException | MyException  e) {
			throw new RuntimeException(e);
		}
	}

	/**
     * 禁止实例化
     */
	private FastDFSUtil() {}

	/**
     * 获取客户端信息
     * @return 客户端信息
     * @exception NullPointerException 必须每次使用都创建,不然多线程下报错
     */
	private static StorageClient getClientInfo(){
		while (trackerServer == null || storageServer == null){
			//cas思想,就等着呗。
			//睡眠是防止CPU突然就高血压了
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				//出问题就直接退出
				break;
			}
		}
		return new StorageClient(trackerServer, storageServer);
	}

	/**
     * 上传方法
     * @param filename 文件名
     * @param ext 后缀
     * @param dataSize 文件大小
     * @param function 提供 client服务和描述数组,需要返回上传后的数据
     * @return 描述数据
     */
	private static String[] upload(String filename, String ext, String dataSize, BiFunction<StorageClient,NameValuePair[],String[]> function){
		//获取连接
		StorageClient connection = getClientInfo();
		//设置文件介绍
		NameValuePair[] pair = new NameValuePair[3];
		pair[0] = new NameValuePair("fileName",filename);
		pair[1] = new NameValuePair("fileExt",ext);
		pair[2] = new NameValuePair("fileSize",dataSize);
		//创建返回对象
		writeLock.lock();
		try {
			return function.apply(connection,pair);
		}finally {
			writeLock.unlock();
		}
	}
}

拾贰、后期遇到的一些问题汇总

Ⅰ、recv package size -1 != 10

问题复现:当IP地址被没有加入白名单然后进行上传文件出现此问题
原因:你的IP不是白名单用户
解决方案:将当前上传你的服务器的IP地址加入白名单,加入过程请查看上面安全问题模块的介绍。

Ⅱ、getStoreStorage fail, errno code: 2

问题复现:白名单用户被移除后再次加入会无法上传文件。且每次重复这么操作都能复现此操作。
原因:不知道
解决方法:删除storage下存储的任意一张图片就可以了
还有可能的原因:存储空间不足或者storage配置出错。存储空间不足可能性更高。

Ⅲ、NullPoint空指针异常

问题复现:在解决上面按个错误的时候发现我要是手刷新的快必有文件上传不上去,直接报错空指针异常。?刚学完JUC这不跑个多线程给他冲一冲

static LongAdder exCount = new LongAdder();
public void test2(int threadNum) throws InterruptedException {
	CountDownLatch countDownLatch = new CountDownLatch(10);
	for (int i = 0; i < threadNum; i++) {
		new Thread(()->{
			//上传文件的代码。不展示了
			upload();
			countDownLatch.countDown();
		}).start();
	}
	countDownLatch.await();
	log.info("空指针的次数:{}", exCount.intValue());
}

测试下来 threadNum只有在1时不会报错,就是没发生并发。只要操作1就会报错,要么就是Socket报错,要么就是空指针。偶尔会跳出来一个成功的结果。并发问题加锁?我不想这么复杂,直接度娘看看有没有号方法。看到大佬的文章试着重写了工具类。完美解决
原因:StorageClient设置成全局变量了,每个线程使用的时候会在结束的时候释放,然后使用时在创建。多线程情况下可能线程1结束了,线程2还在用然后一年懵逼然后吐槽报错。
解决方案:每次调用是都老老实实的new StorageClient(trackerServer, storeStorage);但是trackerServer的创建和storeStorage的创建可以变为公共变量

具体问题的分析流程请跳转到该文章。一次FastDFS并发问题的排查经历
这个问题遇到后已经修改上面提供的工具类

Ⅳ、Socket is closed || Socket write error

问题复现:并发情况下还有个问题,就是这个Socket报错。这个报错很烦,文件上传上去不返回上传信息。百度了几个方法都不行,最后只能选择加锁。
原因:每次上传文件正常会保存一个文件和一个-m的信息文件。在并发执行的时候就会无法保存这个文件的问题。具体原因不想追源码了按照看到的一片文章的可能,应该是flush()的时候流已经被关闭了。
解决方法:加锁加锁。但是有点浪费性能。说实话除非异步上传几乎不会出现这个情况。我疯狂点击上传的接口也不会出现这个情况,就多线程跑必出这个问题。

原因来源于这篇文章java.net.SocketException Connection reset by peer: socket write error 原因一例 但是不知道是不是和他说的是同一个问题。因为他的错误和这个错误一样,但是他是自己的代码报错了。

膜拜大佬<参考文献>

  1. 在Nginx或Tengine服务器上安装证书
  2. Fastdfs 卸载
  3. 手把手带你安装FastDFS及与SpringBoot整合【推荐食用】
  4. Centos7.x 搭建FastDFS并通过Nginx配置http或https访问
  5. 一次FastDFS并发问题的排查经历
  6. java.net.SocketException Connection reset by peer: socket write error 原因一例

本文作者:Ch1ee

本文链接:https://www.cnblogs.com/daimourentop/p/16512013.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Ch1ee  阅读(693)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起