• FastDFS(分布式文件管理系统)


    一、简介

     

    解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡。

    FastDFS服务端只有两个角色,tracker serverstorage server。

    所有同角色服务器集群节点都是平等的,不存在主从关系(Master-Slave)。

    存储服务器采用分组方式,同组内存储服务器上的文件完全相同(备份);不同分组的存储服务器管理不同的文件(扩容 RAID)。

    不同组的storage server之间不会相互通信。

    由storage server主动向tracker server报告状态信息,tracker server之间不会相互通信。

    二、搭建环境

    (1)拉取镜像

    docker pull delron/fastdfs

    (2)创建tracker service宿主机目录

    mkdir -p /opt/fdfs/tracker

    (3)创建tracker service容器,默认端口号22122

    docker run -d --network=host --name tracker -v /opt/fdfs/tracker:/var/fdfs delron/fastdfs tracker

    (4)创建storage service宿主机目录

    mkdir -p /opt/fdfs/storage

    (5)创建storage service并启动容器,默认端口号23000

    docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.146.130:22122 -v /opt/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage

    (6)重启问题解决

    rm -rf /opt/fdfs/tracker/data/*.pid

    rm -rf /opt/fdfs/storage/data/*.pid

    三、文件上传

    (1)导入依赖

           
                cn.bestwu
                fastdfs-client-java
                1.27
           

           
                org.apache.commons
                commons-lang3
                3.4
           

    (2)在src/main/resources目录中创建properties类型配置文件,命名不限。如:fdfs.properties

    fastdfs.connect_timeout_in_seconds=10
    fastdfs.network_timeout_in_seconds=30
    fastdfs.charset=UTF-8
    # tracker服务器地址,多个服务器,逗号分隔
    fastdfs.tracker_servers=192.168.130.146:22122
    # tracker服务器中配置文件tracker.conf中的http端口配置。必须相同。
    fastdfs.http_tracker_http_port=8080

    (3)创建工具类com.bjsxt.utils.FastDFSUtils

    1. /**
    2. * FastDFS Java客户端工具
    3. */
    4. public final class FastDFSUtils {
    5. /**
    6. * 定义静态属性,Properties和StorageClient
    7. */
    8. private final static Properties PROPERTIES;
    9. private final static StorageClient STORAGE_CLIENT;
    10. /**
    11. * 静态初始化代码块,初始化静态属性
    12. * 静态初始化代码块有异常如何处理?
    13. * 处理的时候,try。。catch。。 抛出一个Error,终止虚拟机。
    14. */
    15. static{
    16. try {
    17. PROPERTIES = new Properties();
    18. // 读取配置文件
    19. PROPERTIES.load(
    20. FastDFSUtils.class
    21. .getClassLoader()
    22. .getResourceAsStream("fdfs.properties")
    23. );
    24. // 使用ClientGlobal初始化FastDFS客户端配置
    25. ClientGlobal.initByProperties(PROPERTIES);
    26. // 创建Tracker客户端对象
    27. TrackerClient trackerClient = new TrackerClient();
    28. // 基于Tracker客户端对象,获取Tracker服务器对象
    29. TrackerServer trackerServer = trackerClient.getConnection();
    30. // 基于Tracker服务器和客户端对象,获取Storage服务器对象
    31. StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
    32. // 创建Storage客户端对象
    33. STORAGE_CLIENT = new StorageClient(trackerServer, storageServer);
    34. }catch (Exception e){
    35. throw new ExceptionInInitializerError(e);
    36. }
    37. }
    38. /**
    39. * 删除文件
    40. * int delete_file(String 卷名, String 路径及文件名);
    41. * 返回值: 0代表成功,其他数字代表错误编码
    42. */
    43. public static int remote(String group, String remote){
    44. try {
    45. return STORAGE_CLIENT.delete_file(group, remote);
    46. }catch (Exception e){
    47. e.printStackTrace();
    48. return -1;
    49. }
    50. }
    51. /**
    52. * 查询某文件的元数据
    53. * @param group 卷名
    54. * @param remote 路径及文件名
    55. * @return 返回文件的元数据数组。发生错误返回null
    56. */
    57. public static NameValuePair[] getMetaData(String group, String remote){
    58. try{
    59. return STORAGE_CLIENT.get_metadata(group, remote);
    60. }catch (Exception e){
    61. e.printStackTrace();
    62. return null;
    63. }
    64. }
    65. /**
    66. * 下载文件工具方法
    67. * 下载方法
    68. * byte[] download_file(String 卷名, String 路径及文件名)
    69. * 返回要下载的文件内容
    70. * @param group 卷名
    71. * @param remote 路径及文件名
    72. * @return 返回下载的文件内容,发生错误返回null
    73. */
    74. public static byte[] download(String group, String remote){
    75. try {
    76. return STORAGE_CLIENT.download_file(group, remote);
    77. }catch (Exception e){
    78. e.printStackTrace();
    79. return null;
    80. }
    81. }
    82. /**
    83. * 上传文件的工具方法
    84. * 一定保存文件到FastDFS,一定保存至少一个元数据(文件原始名称)
    85. * @param inputStream 要上传的文件的输入流
    86. * @param fileName 上传文件的原始名称
    87. * @param metaProperties 上传文件的元数据,成对提供,如: 名,值,名,值
    88. * @return
    89. */
    90. public static String[] uploadFile(InputStream inputStream, String fileName, String... metaProperties){
    91. try {
    92. int length = inputStream.available();
    93. byte[] datas = new byte[length];
    94. inputStream.read(datas, 0, length);
    95. // 处理元数据
    96. NameValuePair[] nameValuePairs = null;
    97. if (metaProperties.length % 2 == 0) {
    98. // 参数数量满足要求,开始处理
    99. nameValuePairs = new NameValuePair[metaProperties.length / 2 + 1];
    100. for (int i = 0; i < nameValuePairs.length; i = i + 2) {
    101. nameValuePairs[i / 2] = new NameValuePair(metaProperties[i], metaProperties[i + 1]);
    102. }
    103. } else {
    104. nameValuePairs = new NameValuePair[1];
    105. }
    106. nameValuePairs[nameValuePairs.length - 1] = new NameValuePair("fileName", fileName);
    107. // 获取文件后缀
    108. String extName = getExtName(fileName);
    109. // 上传文件到FastDFS
    110. String[] result = STORAGE_CLIENT.upload_file(datas, extName, nameValuePairs);
    111. return result;
    112. }catch (Exception e){
    113. // 发生任何异常,上传文件失败。返回null
    114. e.printStackTrace();
    115. return null;
    116. }
    117. }
    118. /**
    119. * 截取文件后缀
    120. * @param fileName
    121. * @return
    122. */
    123. private static String getExtName(String fileName){
    124. if(fileName.lastIndexOf(".") > -1){
    125. // 文件名称中包含字符 .
    126. return fileName.substring(fileName.lastIndexOf(".") + 1);
    127. }else{
    128. // 文件名称中不包含字符 .
    129. return "";
    130. }
    131. }
    132. /**
    133. * 提供获取Storage客户端对象的工具方法
    134. */
    135. public static StorageClient getStorageClient(){
    136. return STORAGE_CLIENT;
    137. }
    138. private FastDFSUtils(){}
    139. }

    (4)service层

    1. @Override
    2. public boolean upload(MultipartFile file) {
    3. try {
    4. //将文件存入到Storage service中,返回值为长度为2的数组,一个为存储的仓库,一个为存储的文件路径
    5. String[] strings = FastDFSUtils.uploadFile(file.getInputStream(), file.getOriginalFilename(), "owner", "admin");
    6. if(strings==null){
    7. return false;
    8. }
    9. //将文件信息存储到数据库中
    10. MyFile myFile = new MyFile();
    11. myFile.setFileName(file.getOriginalFilename());
    12. myFile.setGroupName(strings[0]);
    13. myFile.setRemoteName(strings[1]);
    14. myFile.setLength(file.getSize());
    15. myFile.setCreateTime(new Date());
    16. int insert = uploadMapper.insert(myFile);
    17. if(insert != 1){
    18. return false;
    19. }
    20. } catch (IOException e) {
    21. e.printStackTrace();
    22. }
    23. return true;
    24. }

    四、文件下载

    (1)service层

    1. /**
    2. * 文件上传service
    3. * @param groupName 存储的主机
    4. * @param remoteName 存储的文件路径及文件名
    5. * @return
    6. */
    7. @Override
    8. public Map download(String groupName, String remoteName) {
    9. HashMap map = new HashMap<>();
    10. //获取文件二进制数组
    11. byte[] download = FastDFSUtils.download(groupName, remoteName);
    12. //获取文件元数据
    13. NameValuePair[] metaData = FastDFSUtils.getMetaData(groupName, remoteName);
    14. if(download != null && metaData != null){
    15. map.put("data",download);
    16. for (NameValuePair metaDatum : metaData) {
    17. if(metaDatum.getName().equals("fileName")){
    18. map.put("fileName", metaDatum.getValue());
    19. break;
    20. }
    21. }
    22. }
    23. return map;
    24. }

    (2)controller

    1. @RequestMapping("/download")
    2. public void download(String groupName, String remoteName, HttpServletResponse response) throws IOException {
    3. Map download = uploadService.download(groupName, remoteName);
    4. // 设置响应头
    5. response.setContentType("application/octet-stream");
    6. // 设置下载文件的附件名称
    7. response.setHeader("content-disposition", "attachment;filename="+download.get("fileName").toString());
    8. // 输出要下载的文件内容到客户端
    9. byte[] datas = (byte[]) download.get("data");
    10. response.getOutputStream().write(datas, 0, datas.length);
    11. }

    五、文件删除

    1. @Override
    2. public boolean delete(MyFile file) {
    3. //删除数据库文件
    4. int delete = uploadMapper.delete(file);
    5. //删除文件
    6. int remote = FastDFSUtils.remote(file.getGroupName(), file.getRemoteName());
    7. return delete>0&&remote==0;
    8. }

     六、文件预览

    (1)Nginx简介

    Nginx (engine x) 是一个高性能的HTTP和反向代理服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。

    Nginx 是一个很强大的高性能Web和反向代理服务,它具有很多非常优越的特性:在连接高并发的情况下,Nginx是Apache服务不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。

    (2)代理方式

    正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。

    反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

    两者间的区别

    位置不同 正向代理,架设在客户机和目标主机之间; 反向代理,架设在服务器端;

    代理对象不同 正向代理,代理客户端,服务端不知道实际发起请求的客户端; 反向代理,代理服务端,客户端不知道实际提供服务的服务端;

    (3)Nginx常用场景

    Http协议代理

    只要支持HTTP协议访问的内容,都可以由Nginx进行代理。Nginx只支持HTTP协议的代理,其他协议不支持。

    搭建虚拟主机

    Nginx可以监听所安装的主机的某个端口,对外支持这个端口的HTTP访问。当接收到外部HTTP请求后把本机中资源返回给客户端。今天的课程内容就是使用Nginx的搭建虚拟主机功能,外部请求图片时,把图片信息响应给请求发。

    负载均衡

    Nginx可以代理多个主机,内置负载均衡策略。

    (4)使用

    使用http请求,ip+存储主机+存储路径及文件名

  • 相关阅读:
    Elasticsearch:使用不同的 CA 更新安全证书 (一)
    解码器 | 基于 Transformers 的编码器-解码器模型
    Android Studio(项目打包成APK)
    AI算法如何快速部署?来极星平台找答案!|极讲堂首期重磅发布
    Spring的基本使用
    08——驾校科目一考试——布局按钮
    使用springcloud-seata解决分布式事务问题-2PC模式
    SpringBoot - 在IDEA中如何引入本地JAR包?
    Springboot 集成 WebSocket
    vue框架学习-----vue简介&vue.js安装&第一个vue程序&部分vue指令
  • 原文地址:https://blog.csdn.net/weixin_53455615/article/details/127965474