FastDFS
FastDFS是一个开源的轻量级分布式文件系统,整体功能与MogileFS十分相似,由C编写,无论在性能,冗余备份,负载均衡等方面都比MogileFS提升了不少,整个文件系统也只可以通过API进行访问。
- Storage server
storage server以组为单位组织,一个group内包含多台storage机器,数据互为备份,存储空间以group内容量最小的storage机器为主。以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group内storage server数量即为该group的副本数),比如将不同应用数据存到不同的group就能隔离应用数据,同时还可以根据应用的访问特性来将应用的访问特性来将应用分配到不同的group来做负载均衡;缺点是group的容量受单机存储容量的限制,同时group内的机器坏掉时,数据恢复只能依赖group内的其他机器,使得恢复时间会很长。
group内的每个storage server的存储依赖于本地文件系统,storage可配置多个数据存储目录。storage server接受写文件的请求时,会根据配置好的规则,选择其中一个存储目录来存储文件,为了避免每个目录下的文件数过多,在storage第一次启动时,会在每个数据存储目录下创建2级子目录,每级256个,总共65535个文件,新写的文件以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地存储到该目录中。
- Tracker server
Tracker是FasrDFS的协调者,负责管理所有的storage server和group,每个storage server启动后会连接Tracker,告知自己所属的group等信息,并保持周期性的心跳,tracker根据storage server的心跳信息,建立group和storage server的映射表。
Tracker需要管理的元信息很少,会全部存储在内存中;另外tracker上的元信息都是由storage server汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。
- Client
客户端,业务请求发起方,通过专用接口基于tcp协议与tracker以及storage server进行交互,存储返回的file_id。
Upload file
选择tracker server
当集群中不止一个tracker server时,由于tracker之间完全对等的关系,客户端在upload文件时可以任意选择一个tracker选择存储group
当tracker受到uplode file的请求时,会为该文件分配一个可以存储文件的group:1.Round robin 2.Specified group 3.Load balance选择存储的storage server
当选定group后,tracker会在group内选择storage server给客户端:1.Round robin 2.First server ordered by ip 3.First server ordered by priority选择storage path
当分配好storage server后,客户端将storage发送写文件请求,storage将会为文件分配一个数据存储目录:1.Round robin 2.剩余空间最多优先生产Fileid
选定存储目录之后,storage会为文件生成Fileid,由storage server ip、文件创建时间、文件大小、文件的crc32和一个随机数拼接而成,然后将这个二进制进行base64编码,转换成可打印的字符。选择两级目录
当选定存储目录之后,storage会为文件分配一个field,每个存储目录下有两级256x256的子目录,storage会按照fileld进行两次hash,路由到其中一个子目录,然后将文件以field为文件名存储到该子目录下。生成文件名
当文件存储到某一个子目录下后,即为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、field、文件后缀名拼接而成。文件同步
写文件时,客户端将文件写至group内的一个storage server即为写文件成功,storage server写文件后,会由后台线程将文件同步至同group内的其他storage server,每个storage写文件后,同时会写一份binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式进行记录,所以最好能保证集群内所有server的时钟保持同步。 storage的同步进度会作为元数据的一部分汇报到tracker上,tracke在选择读storage的时候会以同步进度作为参考。
Download file
跟upload file一样,在download file时客户端可以选择任意tracker server。
tracker发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请求选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到时候,文件还没有同步到某些storage server上,为了尽量避免访问到这样的storage,tracker按照如下规则选择group内可读的storage。
- 该文件上传到的源头storage - 源头storage只要存活着,肯定包含这个文件,源头的地址被编码在文件名中。 2. 文件创建时间戳==storage被同步到的时间戳 且(当前时间-文件创建时间戳) > 文件同步最大时间(如5分钟) - 文件创建后,认为经过最大同步时间后,肯定已经同步到其他storage了。 3. 文件创建时间戳 < storage被同步到的时间戳。 - 同步时间戳之前的文件确定已经同步了 4. (当前时间-文件创建时间戳) > 同步延迟阀值(如一天)。 - 经过同步延迟阈值时间,认为文件肯定已经同步了。
FastDFS实例
- 10.211.55.24 nginx tracker
- 10.211.55.25 storage1
- 10.211.55.26 storage2
FastDFS下载链接:https://github.com/happyfish100/fastdfs
FastDFS依赖链接:https://github.com/happyfish100/libfastcommon.git
- 安装tracker
1 | ~]# git clone https://github.com/happyfish100/libfastcommon.git |
2 | ~]# cd libfastcommon |
3 | ~]# ./make.sh |
4 | ~]# ./make.sh install |
5 | ~]# git clone https://github.com/happyfish100/fastdfs |
6 | ~]# cd fastdfs |
7 | ~]# ./make.sh |
8 | ~]# ./make.sh install |
9 | ~]# cp /etc/fdfs/tracker.comf.sample /etc/fdfs/tracker.conf |
10 | ~]# cat /etc/fdfs/tracker.conf |
11 | disabled=false |
12 | bind_addr=0.0.0.0 |
13 | port=22122 |
14 | connect_timeout=30 |
15 | network_timeout=60 |
16 | base_path=/data/fdfs/tracker #设置tracker的数据目录和日志文件 |
17 | max_connections=256 |
18 | accept_threads=1 #接受请求的线程 |
19 | work_threads=4 #工作的线程 |
20 | min_buff_size = 8KB |
21 | max_buff_size = 128KB |
22 | store_lookup=2 #上传文件选择组的规则 0.轮询 1.指定组 2.选择最多空闲空间的组 |
23 | store_group=group2 #选择1时,指定的组 |
24 | store_server=0 #上传文件选择storage server 0.轮询 1.根据ip排序的第一台 2.根据优先级,越小越优先 |
25 | store_path=2 #上传文件选择的storage的挂载点 0.轮询 2.负载均衡,选择最大的容量的上传 |
26 | download_server=0 #下载文件选择storage server 0.轮询 1.上传到那台storage server,从那台下载 |
27 | reserved_storage_space = 10% #存储挂在点预留多少空间来为系统或者其他应用 |
28 | log_level=info |
29 | run_by_group=tracker #进程以哪个用户组运行 |
30 | run_by_user=tracker #进程以哪个用户运行 |
31 | allow_hosts=* #访问控制 |
32 | sync_log_buff_interval = 10 #同步日志的频率 |
33 | check_active_interval = 120 #检测storage server的存活频率 |
34 | thread_stack_size = 64KB |
35 | storage_ip_changed_auto_adjust = true |
36 | storage_sync_file_max_delay = 86400 |
37 | storage_sync_file_max_time = 300 |
38 | use_trunk_file = false #是否裁剪文件 |
39 | slot_min_size = 256 |
40 | slot_max_size = 16MB |
41 | trunk_file_size = 64MB |
42 | trunk_create_file_advance = false |
43 | trunk_create_file_time_base = 02:00 |
44 | trunk_create_file_interval = 86400 |
45 | trunk_create_file_space_threshold = 20G |
46 | trunk_init_check_occupying = false |
47 | trunk_init_reload_from_binlog = false |
48 | trunk_compress_binlog_min_interval = 0 |
49 | use_storage_id = false |
50 | storage_ids_filename = storage_ids.conf |
51 | id_type_in_filename = ip |
52 | store_slave_file_use_link = false |
53 | rotate_error_log = false |
54 | error_log_rotate_time=00:00 |
55 | rotate_error_log_size = 0 |
56 | log_file_keep_days = 0 |
57 | use_connection_pool = false |
58 | connection_pool_max_idle_time = 3600 |
59 | http.server_port=8080 |
60 | http.check_alive_interval=30 |
61 | http.check_alive_type=tcp |
62 | http.check_alive_uri=/status.html |
63 | ~]# service fdfs_trackerd start |
- 安装storage
1 | ~]# cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf |
2 | ~]# cat /etc/fdfs/storage.conf |
3 | disabled=false |
4 | group_name=group1 #定义组的名字 |
5 | bind_addr=0.0.0.0 |
6 | client_bind=true |
7 | port=23000 |
8 | connect_timeout=30 |
9 | network_timeout=60 |
10 | heart_beat_interval=30 #心跳信息频率 |
11 | stat_report_interval=60 #磁盘用量信息频率 |
12 | base_path=/data/fdfs/storage #日志目录 |
13 | max_connections=256 |
14 | buff_size = 256KB |
15 | accept_threads=1 |
16 | work_threads=4 |
17 | disk_rw_separated = true #读写分离 |
18 | disk_reader_threads = 1 |
19 | disk_writer_threads = 1 |
20 | sync_wait_msec=50 #当无法同步文件时,隔多久重试 |
21 | sync_interval=0 |
22 | sync_start_time=00:00 |
23 | sync_end_time=23:59 |
24 | write_mark_file_freq=500 |
25 | store_path_count=1 |
26 | store_path0=/data/fdfs/storage/0 #存储路径 |
27 | subdir_count_per_path=256 |
28 | tracker_server=10.211.55.24:22122 |
29 | log_level=info |
30 | run_by_group=storage |
31 | run_by_user=storage |
32 | allow_hosts=* |
33 | file_distribute_path_mode=0 #文件分布的模式 0.轮询 1.按照hash随机分布 |
34 | file_distribute_rotate_count=100 #当模式为0,分布的文件到达这个值,会会滚到下一个路径 |
35 | fsync_after_written_bytes=0 |
36 | sync_log_buff_interval=10 |
37 | sync_binlog_buff_interval=10 |
38 | sync_stat_file_interval=300 |
39 | thread_stack_size=512KB |
40 | upload_priority=10 #上传的优先级 |
41 | if_alias_prefix= |
42 | check_file_duplicate=0 |
43 | file_signature_method=hash |
44 | key_namespace=FastDFS |
45 | keep_alive=0 |
46 | use_access_log = false |
47 | rotate_access_log = false |
48 | access_log_rotate_time=00:00 |
49 | rotate_error_log = false |
50 | error_log_rotate_time=00:00 |
51 | rotate_access_log_size = 0 |
52 | rotate_error_log_size = 0 |
53 | log_file_keep_days = 0 |
54 | file_sync_skip_invalid_record=false |
55 | use_connection_pool = false |
56 | connection_pool_max_idle_time = 3600 |
57 | http.domain_name= |
58 | http.server_port=8888 |
59 | ~]# service fdfs_storaged start |
- 查看状态
1 | ~]# fdfs_monitor /etc/fdfs/storage.conf |
2 | [2017-06-10 19:50:47] DEBUG - base_path=/data/fdfs/storage, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0 |
3 | |
4 | server_count=1, server_index=0 |
5 | |
6 | tracker server is 10.211.55.24:22122 |
7 | |
8 | group count: 1 |
9 | |
10 | Group 1: |
11 | group name = group1 |
12 | disk total space = 50268 MB |
13 | disk free space = 42976 MB |
14 | trunk free space = 0 MB |
15 | storage server count = 2 |
16 | active server count = 2 |
17 | storage server port = 23000 |
18 | storage HTTP port = 8888 |
19 | store path count = 1 |
20 | subdir count per path = 256 |
21 | current write server index = 0 |
22 | current trunk file id = 0 |
23 | |
24 | Storage 1: |
25 | id = 10.211.55.25 |
26 | ip_addr = 10.211.55.25 (node1) ACTIVE |
27 | http domain = |
28 | version = 5.11 |
29 | join time = 2017-06-10 18:22:00 |
30 | up time = 2017-06-10 18:22:00 |
31 | total storage = 50268 MB |
32 | free storage = 42976 MB |
33 | upload priority = 10 |
34 | store_path_count = 1 |
35 | subdir_count_per_path = 256 |
36 | storage_port = 23000 |
37 | storage_http_port = 8888 |
38 | current_write_path = 0 |
39 | source storage id = 10.211.55.25 |
40 | if_trunk_server = 0 |
41 | connection.alloc_count = 256 |
42 | connection.current_count = 1 |
43 | connection.max_count = 1 |
44 | total_upload_count = 0 |
45 | success_upload_count = 0 |
46 | total_append_count = 0 |
47 | success_append_count = 0 |
48 | total_modify_count = 0 |
49 | success_modify_count = 0 |
50 | total_truncate_count = 0 |
51 | success_truncate_count = 0 |
52 | total_set_meta_count = 0 |
53 | success_set_meta_count = 0 |
54 | total_delete_count = 0 |
55 | success_delete_count = 0 |
56 | total_download_count = 0 |
57 | success_download_count = 0 |
58 | total_get_meta_count = 0 |
59 | success_get_meta_count = 0 |
60 | total_create_link_count = 0 |
61 | success_create_link_count = 0 |
62 | total_delete_link_count = 0 |
63 | success_delete_link_count = 0 |
64 | total_upload_bytes = 0 |
65 | success_upload_bytes = 0 |
66 | total_append_bytes = 0 |
67 | success_append_bytes = 0 |
68 | total_modify_bytes = 0 |
69 | success_modify_bytes = 0 |
70 | stotal_download_bytes = 0 |
71 | success_download_bytes = 0 |
72 | total_sync_in_bytes = 0 |
73 | success_sync_in_bytes = 0 |
74 | total_sync_out_bytes = 0 |
75 | success_sync_out_bytes = 0 |
76 | total_file_open_count = 0 |
77 | success_file_open_count = 0 |
78 | total_file_read_count = 0 |
79 | success_file_read_count = 0 |
80 | total_file_write_count = 0 |
81 | success_file_write_count = 0 |
82 | last_heart_beat_time = 2017-06-10 19:50:43 |
83 | last_source_update = 1969-12-31 19:00:00 |
84 | last_sync_update = 1969-12-31 19:00:00 |
85 | last_synced_timestamp = 1969-12-31 19:00:00 |
86 | Storage 2: |
87 | id = 10.211.55.26 |
88 | ip_addr = 10.211.55.26 (node2) ACTIVE |
89 | http domain = |
90 | version = 5.11 |
91 | join time = 2017-06-11 11:45:12 |
92 | up time = 2017-06-11 11:45:12 |
93 | total storage = 50268 MB |
94 | free storage = 46044 MB |
95 | upload priority = 10 |
96 | store_path_count = 1 |
97 | subdir_count_per_path = 256 |
98 | storage_port = 23000 |
99 | storage_http_port = 8888 |
100 | current_write_path = 0 |
101 | source storage id = 10.211.55.26 |
102 | if_trunk_server = 0 |
103 | connection.alloc_count = 256 |
104 | connection.current_count = 1 |
105 | connection.max_count = 1 |
106 | total_upload_count = 0 |
107 | success_upload_count = 0 |
108 | total_append_count = 0 |
109 | success_append_count = 0 |
110 | total_modify_count = 0 |
111 | success_modify_count = 0 |
112 | total_truncate_count = 0 |
113 | success_truncate_count = 0 |
114 | total_set_meta_count = 0 |
115 | success_set_meta_count = 0 |
116 | total_delete_count = 0 |
117 | success_delete_count = 0 |
118 | total_download_count = 0 |
119 | success_download_count = 0 |
120 | total_get_meta_count = 0 |
121 | success_get_meta_count = 0 |
122 | total_create_link_count = 0 |
123 | success_create_link_count = 0 |
124 | total_delete_link_count = 0 |
125 | success_delete_link_count = 0 |
126 | total_upload_bytes = 0 |
127 | success_upload_bytes = 0 |
128 | total_append_bytes = 0 |
129 | success_append_bytes = 0 |
130 | total_modify_bytes = 0 |
131 | success_modify_bytes = 0 |
132 | stotal_download_bytes = 0 |
133 | success_download_bytes = 0 |
134 | total_sync_in_bytes = 0 |
135 | success_sync_in_bytes = 0 |
136 | total_sync_out_bytes = 0 |
137 | success_sync_out_bytes = 0 |
138 | total_file_open_count = 0 |
139 | success_file_open_count = 0 |
140 | total_file_read_count = 0 |
141 | success_file_read_count = 0 |
142 | total_file_write_count = 0 |
143 | success_file_write_count = 0 |
144 | last_heart_beat_time = 2017-06-10 19:50:37 |
145 | last_source_update = 1969-12-31 19:00:00 |
146 | last_sync_update = 1969-12-31 19:00:00 |
147 | last_synced_timestamp = 1969-12-31 19:00:00 |
- 上传文件
1 | ~]# cat /etc/fdfs/client.conf |
2 | connect_timeout=30 |
3 | network_timeout=60 |
4 | base_path=/data/fdfs/client |
5 | tracker_server=10.211.55.24:22122 |
6 | log_level=info |
7 | use_connection_pool = false |
8 | connection_pool_max_idle_time = 3600 |
9 | load_fdfs_parameters_from_tracker=false |
10 | use_storage_id = false |
11 | storage_ids_filename = storage_ids.conf |
12 | http.tracker_server_port=80 |
13 | ~]# fdfs_upload_file /etc/fdfs/client.conf /etc/fstab |
14 | group1/M00/00/00/CtM3MFk8h1mACqW3AAADXPbJpH84824215 |
15 | ~]# fdfs_file_info /etc/fdfs/client.conf group1/M00/00/00/CtM3MFk8h1mACqW3AAADXPbJpH84824215 |
16 | source storage id: 0 |
17 | source ip address: 10.211.55.25 |
18 | file create timestamp: 2017-06-10 19:57:13 |
19 | file size: 860 |
20 | file crc32: 4140409983 (0xF6C9A47F) |
21 | ~]# ll /data/fdfs/storage/0/data/00/00/CtM3MFk8h1mACqW3AAADXPbJpH84824215 |
22 | -rw-r--r--. 1 root root 860 Jun 10 19:57 /data/fdfs/storage/0/data/00/00/CtM3MFk8h1mACqW3AAADXPbJpH84824215 |
- 在storage安装nginx
1 | ~]# git clone https://github.com/happyfish100/fastdfs-nginx-module |
2 | ~]# tar xf nginx-1.12.0.tar.gz |
3 | ~]# cd nginx-1.12.0 |
4 | ~]# ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-module=../fastdfs-nginx-module/src --user=www |
5 | ~]# make -j 4 && make install |
6 | ~]# cd |
7 | ~]# cp fastdfs/conf/{http.conf,mime.types} /etc/fdfs |
8 | ~]# cp fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs |
9 | ~]# cd /etc/fdfs |
10 | ~]# cat mod_fastdfs.conf |
11 | connect_timeout=2 |
12 | network_timeout=30 |
13 | base_path=/data/fdfs/storage |
14 | load_fdfs_parameters_from_tracker=true |
15 | storage_sync_file_max_delay = 86400 |
16 | use_storage_id = false |
17 | storage_ids_filename = storage_ids.conf |
18 | tracker_server=10.211.55.24:22122 |
19 | storage_server_port=23000 #本地storage的端口 |
20 | group_name=group1 #本地的group |
21 | url_have_group_name = true #开启 |
22 | store_path_count=1 |
23 | store_path0=/data/fdfs/storage/0 |
24 | log_level=info |
25 | log_filename= |
26 | response_mode=proxy |
27 | if_alias_prefix= |
28 | flv_support = true |
29 | flv_extension = flv |
30 | group_count = 0 |
31 | ~]# vim /usr/local/nginx/conf/nginx.conf |
32 | location /group1/M00 { |
33 | root /data/fdfs/storage/data; |
34 | ngx_fastdfs_module; |
35 | } |
36 | ~]# ln -s /data/fdfs/storage/data/ /data/fdfs/storage/data/M00 |
37 | ~]# cd /usr/local/nginx/sbin |
38 | ~]# ./nginx -t && ./nginx |
- 测试
1 | ~]# echo "hello fastdfs" > index.html |
2 | ~]# fdfs_text /etc/fdfs/client.conf index.html |
3 | This is FastDFS client test program v5.11 |
4 | |
5 | Copyright (C) 2008, Happy Fish / YuQing |
6 | |
7 | FastDFS may be copied only under the terms of the GNU General |
8 | Public License V3, which may be found in the FastDFS source kit. |
9 | Please visit the FastDFS Home Page http://www.csource.org/ |
10 | for more detail. |
11 | |
12 | [2017-06-10 21:14:42] DEBUG - base_path=/data/fdfs/client, connect_timeout=30, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0 |
13 | |
14 | tracker_query_storage_store_list_without_group: |
15 | server 1. group_name=, ip_addr=10.211.55.25, port=23000 |
16 | server 2. group_name=, ip_addr=10.211.55.26, port=23000 |
17 | |
18 | group_name=group1, ip_addr=10.211.55.25, port=23000 |
19 | storage_upload_by_filename |
20 | group_name=group1, remote_filename=M00/00/00/CtM3MFk8mYKAdz3jAAAADplm3rU73.html |
21 | source ip address: 10.211.55.25 |
22 | file timestamp=2017-06-10 21:14:42 |
23 | file size=14 |
24 | file crc32=2573655733 |
25 | example file url: http://10.211.55.25/group1/M00/00/00/CtM3MFk8mYKAdz3jAAAADplm3rU73.html |
26 | storage_upload_slave_by_filename |
27 | group_name=group1, remote_filename=M00/00/00/CtM3MFk8mYKAdz3jAAAADplm3rU73_big.html |
28 | source ip address: 10.211.55.25 |
29 | file timestamp=2017-06-10 21:14:42 |
30 | file size=14 |
31 | file crc32=2573655733 |
32 | example file url: http://10.211.55.25/group1/M00/00/00/CtM3MFk8mYKAdz3jAAAADplm3rU73_big.html |
33 | ~]# curl http://10.211.55.25/group1/M00/00/00/CtM3MFk8mYKAdz3jAAAADplm3rU73_big.html |
34 | hello fastdfs |