Article / 文章中心

需要搭建一个高性能的文件系统?我推荐你试试它.....(上)

发布时间:2022-02-21 点击数:274
简介: 需求建立一个高性能的文件体系?我引荐你试试它.....(上)

前语


今天给咱们介绍的是FastDFS,一个开源的分布式文件体系,也是入职之后触摸到的一个技能,因为公司项目事务需求,服务器里存了上亿量级的文件,所以运用了这么一项技能来存储这些文件,我也就随之开端了解这项技能,并且在这儿和咱们一同从0到1地开端了解它。


FastDFS介绍


FastDFS是一个以C言语开发的开源轻量级分布式文件体系,由阿里巴巴开发并开源。它对文件进行办理,功用包含:文件存储、文件同步、文件拜访(上传、下载)等。处理了大容量存储和负载均衡的问题。特别合适以文件为载体的在线服务,如相册网站、视频网站等等。


FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等目标,运用FastDFS很容易建立一套高性能的文件服务器集群供给文件上传、下载等服务。


从0,自己的一些疑问:FastDFS过期了吗?


信任这也是许多同学想要问的一些问题,我还没有了解这个技能的时分,也相同有这样的疑问。


首要,现在有许多文件存储都会挑选像七牛云、阿里云OSS等云服务,为什么要自己搭一套文件服务器添加维护本钱呢?


其次,这并不是面试的热点,乃至在入职之前自己都没有触摸过,乃至乃至,没有听说过,反倒是那些抢手的技能,就算自己不主动去了解,当遇到的时分,大致也能知道是用来干嘛的。


那么我来说说我的理解,首要这个技能一定是还没有过期的,因为有些特别的文件,因为信息安全顾忌等原因,不会挑选公有云服务器,还有依据本钱考虑,还有许多的中型互联网公司仍然是依据FastDFS来做自己的文件服务器的。别的,FastDFS作为一个分布式服务器,对轻量级、横向扩展、容灾备份、高可用、高性能、负载均衡都有着充分的考虑,依旧是一个文件服务器的不贰之选。


那么为什么这样一项技能在现在却很少有人了解呢?


榜首,我以为是需求所致,与其它事务相比,需求存储许多文件的事务相对之下仍是比较少。假如文件存储量不大,依照传统的文件存储方法也不会有什么大的问题。


第二,现在有七牛云、阿里云OSS等公司供给对象存储,加之国内关于”上云“的追捧,就很少有人乐意自己搭服务器来做文件存储服务了。


当然关于一个技能人来说,各式各样的技能都得去学习,去适应,所以这篇文章期望能够协助到感兴趣的同学,或是在作业中遇到高量级文件存储的同学,FastDFS是不错的挑选。


传统文件存储方法


image.png


这是传统文件存储的方法,服务器上乃至不需求装任何的应用,只需求有SFTP服务,咱们就能够写对应的代码,完结文件的CRUD。


这样的优点便是很便利,只需求一台机器,几行代码就能搞定文件的存储,可是这种方法的瓶颈和缺点是很明显的。


首要,关于单体服务器来说,不考虑宕机的情况,单体文件服务器的带宽、磁盘容量是有上限的,那么当文件的体积占满了整个磁盘,咱们只能挑选扩展,可是这种单体服务器的方法,关于扩容就不太友好了,咱们能够想想,难道咱们要将原有的硬盘数据拷到一个更大的硬盘里,然后替换硬盘吗?


除了扩展以外,咱们还需求面对一个问题,便是文件的查找,假如咱们将一切文件都寄存到一同,文件的数量假如到了一定的数量,就会面对磁盘IO速度瓶颈,不知道咱们有没有遇到过下图中这种场景:


image.png


假如咱们需求在一个磁盘中找到某个文件,假如没有一个途径,或许途径下有许多文件,那么体系就会扫描磁盘,咱们都知道,计算机体系结构中,关于速度,CPU>内存>硬盘,假如在出产环境下,真的需求存储许多的文件,假定存储的是用户的头像,那么用户每次打开APP,就需求等待个十几秒,自己的头像才会显示,那这个app估计没有人会运用吧。


有同学可能会说,那咱们能够运用缓存啊,Redis的String类型是能够存储二进制数据的,并且Redis的String类型是一个Key对应一个值,查询功率会很高。确实这样在查询功率上能够到达,可是咱们依照一张图片1M来计算,缓存又能存多少张图片呢?很显然这是一个十分贵重的方法。


方才咱们考虑的都是服务器不宕机的状况,那么假定服务器宕机,那么咱们就无法再供给数据存储服务;假如硬盘损坏,那么一切的数据都将丢掉。


分布式文件体系


上文中说了传统文件存储方法的一些缺点和坏处,这其实也是一切“单点“的坏处,无论是单点数据库、或许单点缓存、又或许是单点网关、单点注册中心,都在往分布式集群的方向开展。


总结一下,单点文件体系大致有这些缺点:


1. 磁盘容量存在瓶颈


2. IO速度存在瓶颈


3. 宕机、硬盘损坏数据丢掉的危险


那么关于文件体系,咱们怎么运用分布式的方法来处理上述的缺点呢?


  • 处理磁盘容量瓶颈
    上文中说到,单服务器文件体系存在磁盘容量瓶颈的原因是磁盘无法很便利的进行扩容,咱们一般需求从硬件的层面来考虑扩容硬盘,如:替换大容量硬盘。


这种方法显然是不现实的,因为替换硬盘意味着咱们需求关服务器,出产环境服务器关停三十秒都是很严重的出产事故,所以咱们只能运用服务器横向扩展的方法,假如不能替换硬盘,那么咱们就加服务器。


image.png


  • 这样咱们就能够运用多台服务器共同来构成咱们的文件体系了,每个文件服务器都是一个独立的节点,来存储不同的文件,依据特定的逻辑(这儿需求自己写),来决议文件需求存储到哪个文件服务器中。这样即便服务器容量满了,咱们也还能够持续横向扩展,理论上这样咱们的文件体系是没有容量上限的。


  • 处理IO速度瓶颈
    方才咱们处理了单点文件服务器容量瓶颈,可是假如某台或许某几台服务器上的文件数量过多(查询功率降低),或许有许多的用户拜访某一台服务器,仍是会形成IO速度瓶颈。那么要怎么处理这个问题。
    咱们能够想一想相似的事例——MySQL数据库。
    众所周知,MySQL的数据也是存在硬盘中的,而咱们在写SQL句子的时分,为了保证查询功率,一般会避免全表扫描,而是通过索引让其找到咱们对应的那条数据。
    所以咱们也能够通过这种方法,避免全盘扫描或许大范围扫描,而咱们都知道,操作体系关于文件是有一个天然的索引的,便是咱们的多级目录。FastDFS也正是利用了这个来添加咱们文件IO的功率的,这个暂且不提,下文中会展示。


  • 处理宕机、硬盘损坏数据丢掉的危险
    能否处理这个问题才是分布式文件体系和单机文件体系最底子的区别,因为无论是单机磁盘容量瓶颈仍是IO速度瓶颈,咱们都能够通过添加硬件装备来处理,只不过不太便利且本钱太高罢了。而单机形式是绝对无法处理宕机形成的文件服务失效,或许硬盘损坏形成的数据丢掉的,因为数据只存在一份。


那么咱们思考一下分布式文件体系是怎么来处理这些问题的。


image.png


  • 首要咱们需求处理宕机的问题,如上图,咱们有多个文件服务器节点,可是假如咱们自己写逻辑来决议某个文件应该存哪个服务器上,假定那个服务器此时宕机了,文件依旧是无法存入的,当然咱们能够持续写逻辑来决议假如宕机了之后应该怎么办,可是FastDFS中现已替咱们实现了,Tracker节点能够协助咱们挑选文件应该上传到哪个服务器上,并且还能够在某个节点宕机的时分挑选其从节点(备份节点)进行文件上传,防止因为宕机形成的无法操作文件。


那么依据上面这幅图,第二个问题也就很好理解了,假定某台服务器硬盘损坏了,那么数据依旧会存在备份,即便备份服务器也损坏了,数据也只会丢掉一部分,而不会全部丢掉。

FastDFS

上面说了这么多的关于分布式文件体系能够处理的一些实际问题,那么就直接切入今天的主题——FastDFS。


  • 全体架构


FastDFS文件体系由两大部分组成,客户端服务端
客户端一般指咱们写的程序(当然FastDFS也供给了客户端测试程序),例如咱们运用Java去衔接FastDFS、操作文件,那么咱们的Java程序便是一个客户端,FastDFS供给专有API拜访,目前供给了C、Java和PHP等编程言语的API,用来拜访FastDFS文件体系。




服务端由两个部分组成,分别是跟踪器(Tracker)存储节点(Storage)
跟踪器(Tracker):主要做调度作业,相似微服务注册中心,在内存中记载集群存储节点的storage的状况信息,是客户端和服务端存储节点storage的枢纽,因为相关信息全部在内存中,每个Storage在发动后会衔接Tracker,奉告自己所属的group等信息,并周期性发送心跳,TrackerServer的性能十分高,假定咱们有上百个Storage节点,咱们只需求3台左右的Tracker就足够了。


存储节点(Storage)用于存储文件,包含文件和文件属性(metaData)都保存到服务器磁盘上,完结文件办理的一切功用:文件存储、文件同步和文件拜访等。



Storage以group为组织单位,一个group内能够包含多台Storage机器,数据互为备份,总存储空间以group内容量最小的storage为准(木桶),所以主张一个group内的机器存储空间巨细应该尽量相同,以免形成空间的糟蹋。Storage在榜首次发动时,会在每一个存储目录里创立二级目录,合计256 * 256个目录,咱们上传的文件会以Hash的方法被路由到其间某个子目录下。


image.png


  • 作业流程


  • 上传


image.png


下载


image.png


  1. 客户端发送下载恳求,Tracker依据文件信息,回来Storage地址和端口(客户端也能够通过自己存储的文件方位直接拜访Storage)。


  1. 客户端拜访Storage,Storage依据file_id(组名、虚拟磁盘、二级目录、文件名)查找到文件,回来文件数据。


  1. 当客户端建议上传恳求时,会先拜访Tracker,因为Storage定时向Tracker发送状况信息,所以Tracker中存有一切Storage Group的信息。


  1. Tracker依据本地的Storage Group信息,为客户端上传的文件分配Storage Group,并回来给客户端。


  1. 客户端拿到Storage Group地址和端口后,上传文件到指定的Storage Group中。


  1. Storage回来文件的途径信息和文件名。


  1. Client将文件信息存储到本地。


  • 单机装置


  • 装置前准备
  • 装置
    装置FastDFS需求两个源码包,分别是libfastcommon-1.0.43.tar.gz和fastdfs-6.06.tar.gz。
    这儿附上作者的github地址:fastdfs,libfastcommon,咱们能够到这儿下载对应的包。


下载完结后,将其上传到咱们的linux服务器中


[root@localhost SoftwareInstallPackage]# ll 总用量 971800 -rw-r--r--. 1 root root    809328 9月   9 23:10 fastdfs-6.06.tar.gz -rw-r--r--. 1 root root    166526 9月   9 23:10 libfastcommon-1.0.43.tar.gz


  • 分别运转tar -zxvf fastdfs-6.06.tar.gz和tar -zxvf libfastcommon-1.0.43.tar.gz对其进行解压,解压后进入libfastcommon-1.0.43目录中运转sh make.sh,运转完毕后运转sh make.sh install,然后进入fastdfs-6.06目录中执行相同的操作,即可完结装置。
    装置成功后进入/usr/bin目录下,假如存在许多fdfs开头的命令,则证明装置成功。


[root@localhost bin]# ll|grep fdfs -rwxr-xr-x. 1 root root    362208 9月   9 23:17 fdfs_appender_test -rwxr-xr-x. 1 root root    361984 9月   9 23:17 fdfs_appender_test1 -rwxr-xr-x. 1 root root    348872 9月   9 23:17 fdfs_append_file -rwxr-xr-x. 1 root root    348480 9月   9 23:17 fdfs_crc32 -rwxr-xr-x. 1 root root    348904 9月   9 23:17 fdfs_delete_file -rwxr-xr-x. 1 root root    349640 9月   9 23:17 fdfs_download_file -rwxr-xr-x. 1 root root    349592 9月   9 23:17 fdfs_file_info -rwxr-xr-x. 1 root root    364912 9月   9 23:17 fdfs_monitor -rwxr-xr-x. 1 root root    349128 9月   9 23:17 fdfs_regenerate_filename -rwxr-xr-x. 1 root root   1280096 9月   9 23:17 fdfs_storaged -rwxr-xr-x. 1 root root    372080 9月   9 23:17 fdfs_test -rwxr-xr-x. 1 root root    367200 9月   9 23:17 fdfs_test1 -rwxr-xr-x. 1 root root    512312 9月   9 23:17 fdfs_trackerd -rwxr-xr-x. 1 root root    349832 9月   9 23:17 fdfs_upload_appender -rwxr-xr-x. 1 root root    350848 9月   9 23:17 fdfs_upload_file


  • 而/etfc/fdfs目录中寄存了一切的FastDFS的装备文件:


然后进入/etc/fdfs,这儿寄存了一切fastDFS的装备文件


[root@localhost fdfs]# ll 总用量 32 #客户端衔接装备 -rw-r--r--. 1 root root  1909 9月   9 23:17 client.conf.sample #存储节点装备 -rw-r--r--. 1 root root 10246 9月   9 23:17 storage.conf.sample -rw-r--r--. 1 root root   620 9月   9 23:17 storage_ids.conf.sample #追寻器装备 -rw-r--r--. 1 root root  9138 9月   9 23:17 tracker.conf.sample


  • 最后一步,咱们需求进入FastDFS装置包解压后的conf目录下,找到http.conf和mime.types将其复制到/etc/fdfs目录下。


[root@localhost conf]# pwd /WorkSpace/Software/fastdfs-6.06/conf [root@localhost conf]# cp http.conf /etc/fdfs/ [root@localhost conf]# cp mime.types /etc/fdfs/


  • 这样咱们就完结了FastDFS的装置。
  • 装备文件详解
    装置完结后需求先把装备文件装备好才能够正常发动,这儿会贴上tracker.conf、storage.conf、client.conf的一切装备项,就当作一个装备模板吧,装备的时分能够直接copy。
    首要是tracker.conf:


# 这个装备文件是否 不收效(这儿笔者个人以为,改成是否收效会比较好),true代表不收效,false代表收效 disabled = false # 是否绑定ip,假如不填就代表一切的ip都供给服务,常用于服务器有多个ip但只期望一个ip供给服务 bind_addr = # Tracker的端口号 port = 22122 # 衔接超时的时刻 单位为s connect_timeout = 5 # Tracker的网络超时,单位为秒。发送或接纳数据时,假如在超时时刻后还不能发送或接纳数据,则本次网络通信失利。 network_timeout = 60 # Tracker服务的数据寄存地址,这个目录有必要是存在的 base_path = /home/yuqing/fastdfs # 体系供给的最大衔接数 max_connections = 1024 # 接纳线程数  主张为1 accept_threads = 1 # 作业线程数 引荐设置为CPU线程数 work_threads = 4 # 最小网络缓存  默许值为8KB min_buff_size = 8KB # 最大网络缓存 默许值为128KB max_buff_size = 128KB # 上传文件挑选group的方法 # 0:轮询 # 1:指定一个group # 2:负载均衡,挑选一个最多闲暇空间的group来上传文件 store_lookup = 2 # 当store_lookup设置为1时,有必要在这个参数中设置一个group用来上传文件 # 当store_lookup设置不为1时,这个参数无效 store_group = group2 # 挑选group中的哪一个storage服务器用来上传文件 # 0:轮询 # 1:依照ip地址排序,ip最小的那个服务器用来上传文件 # 2:依据优先级进行排序,上传优先级在storage装备文件中进行装备,装备项为upload_priority store_server = 0 # 挑选storage服务器中的哪一个目录进行上传,一个storage中能够有多个寄存文件的base_path(能够理解为磁盘分区) # 0:轮询 # 2:负载均衡,挑选剩余空间最多的一个途径来上传文件 store_path = 0 # 挑选哪个storage服务器作为下载文件的服务器 # 0:轮询 # 1:文件上传到哪个storage服务器就去哪个storage服务器上下载 download_server = 0 # storage服务器上为其他应用保存的空间 # 能够用绝对值或许百分比:10G或许1024M或许1024K或许XX.XX% # 假如同组中的服务器硬盘巨细相同 以最小的为准,到达最小的那个值,则无法再进行上传 reserved_storage_space = 20% # 规范日志级别从小到大顺次:debuglog_level = info # 操作体系运转FastDFS的用户组,不填默许便是发动FastDFS的用户组 run_by_group= # 操作体系运转FastDFS的用户,不填默许便是发动FastDFS的用户 run_by_user = # 能够衔接到此Tracker Server的IP范围 # 比如: # allow_hosts=10.0.1.[1-15,20] # allow_hosts=host[01-08,20-25].domain.com # allow_hosts=192.168.5.64/26 allow_hosts = * # 同步日志缓存到硬盘的时刻 # 默许十秒一次(Tracker的日志默许是先写在内存里的) sync_log_buff_interval = 10 # 查看storage服务器存活状况的距离时刻 check_active_interval = 120 # 线程栈巨细 需求大于64KB # 默许值256KB # 线程栈越大 work_thread能发动的就越少 thread_stack_size = 256KB # 当storage server IP地址改动时,集群是否自动调整。注:只有在storage server进程重启时才完结自动调整。 # 默以为true storage_ip_changed_auto_adjust = true # storage 同步文件最大延迟时刻 # 默以为一天 86400秒 # 注:本参数并不影响文件同步进程。本参数仅在下载文件时,判别文件是否现已被同步完结的一个阈值(经验值) storage_sync_file_max_delay = 86400 # 存储服务器同步一个文件需求消耗的最大时刻,缺省为300s,即5分钟。 # 注:本参数并不影响文件同步进程。本参数仅在下载文件时,作为判别当前文件是否被同步完结的一个阈值(经验值) storage_sync_file_max_time = 300 # 是否运用小文件兼并,默以为false # trunk_file能够理解为一个容器,专门用来寄存小文件的 # 含有许多个slot(槽),每个槽寄存一个小文件 use_trunk_file = false # trunk file给小文件分配的最小字节数。比如文件只有16个字节,体系也会分配slot_min_size个字节。 slot_min_size = 256 # 只有文件巨细<=这个参数值的文件,才会兼并存储。假如一个文件的巨细大于这个参数值,将直接保存到一个文件中(即不选用兼并存储方法)。 slot_max_size = 1MB # 兼并存储的trunk file巨细,至少4MB,缺省值是64MB。不主张设置得过大。 trunk_alloc_alignment_size = 256 # 兼并后trunk file的接连可用空间(槽)是否兼并,默以为true(防止产生碎片) trunk_free_space_merge = true # 删去没有运用的trunk_files delete_unused_trunk_files = false # trunk file的最大巨细,有必要要大于4MB trunk_file_size = 64MB # 是否提早创立trunk file 默以为false trunk_create_file_advance = false # 创立trunk file的起始(榜首次)时刻点 默以为2:00 trunk_create_file_time_base = 02:00 # 创立trunk file的时刻距离 默以为1天 86400秒 trunk_create_file_interval = 86400 # 提早创立trunk_file时,需求到达的闲暇trunk巨细 trunk_create_file_space_threshold = 20G # trunk初始化时,是否查看可用空间是否被占用 trunk_init_check_occupying = false # 是否无条件从trunk binlog中加载trunk可用空间信息 # FastDFS缺省是从快照文件storage_trunk.dat中加载trunk可用空间, # 该文件的榜首行记载的是trunk binlog的offset,然后从binlog的offset开端加载 trunk_init_reload_from_binlog = false # 紧缩trunk binlog日志的最小时刻距离,0代表从不紧缩 trunk_compress_binlog_min_interval = 86400 # 紧缩trunk binlog日志的时刻距离 0代表从不紧缩 trunk_compress_binlog_interval = 86400 # 首次紧缩trunk binlog的时刻 trunk_compress_binlog_time_base = 03:00 # trunk binlog的最大备份 0代表无备份 trunk_binlog_max_backups = 7 # 是否运用storage_id作为区别storage的标识 use_storage_id = false # use_storage_id 设置为true,才需求设置本参数 # 在文件中设置组名、server ID和对应的IP地址,拜见源码目录下的装备示例:conf/storage_ids.conf storage_ids_filename = storage_ids.conf # 文件名中存储服务器的id类型,值为: # ip:存储服务器的ip地址 # id:存储服务器的服务器id # 此参数仅在use_storage_id设置为true时有用 # 默许值为id id_type_in_filename = id # 是否运用符号链接的方法 # 假如设置为true 一个文件将占用两个文件 符号链接指向原始文件 store_slave_file_use_link = false # 是否定时切割error.log true只支撑一天一次 rotate_error_log = false # error.log切割时刻 error_log_rotate_time = 00:00 # 是否紧缩旧error_log日志 compress_old_error_log = false # 紧缩几天前的errorlog,默许7天前 compress_error_log_days_before = 7 # error log按巨细切割 # 设置为0表示不按文件巨细切割,否则当error log到达该巨细,就会切割到新文件中 rotate_error_log_size = 0 # 日志寄存时刻 # 0表示从不删去旧日志 log_file_keep_days = 0 # 是否运用衔接池 use_connection_pool = true # 衔接池最大闲暇时刻 connection_pool_max_idle_time = 3600 # 本tracker服务器的默许HTTP端口 http.server_port = 8080 # 距离几秒查看storage http服务器的存活 # <=0代表从不查看 http.check_alive_interval = 30 # 查看storage的存活状况的类型 # tcp:衔接上就能够,但不发送恳求也不获取响应 # http storage有必要回来200 http.check_alive_type = tcp # 查看storage状况的uri http.check_alive_uri = /status.html