Saeweedfs是一個由golang語言開發的分布式對象存儲系統,很適合做圖片服務器,性能很好,安裝操作都很簡單,並且可兼容掛載提供路徑訪問的方式,可以較為便捷的將nginx+nfs此類的文件服務器轉換成nginx+seweedfs並提供api接口並不影響原有訪問url的模式
參考鏈接
https://github.com/chrislusf/seaweedfs/wiki/Getting-Started 官網
http://www.importnew.com/3292.html 論文
https://www.jianshu.com/p/2ff61b56f37b 安裝
https://blog.csdn.net/u012618915/article/details/83415955 參數
https://www.jianshu.com/p/51d6d444303d 問題
首先我們下載weed
在https://github.com/chrislusf/seaweedfs/releases/我們可以看到已有版本及歷史,寫此文檔時最新的長期支持版本為1.34,我們下載解壓后可以看見一個可執行文件weed,因為是golang編譯好的,我們可以直接使用它
1 [root@seaweedfs-bj-zw-vm1~]# wget https://github.com/chrislusf/seaweedfs/releases/download/1.34/linux_amd64.tar.gz 2 [root@seaweedfs-bj-zw-vm1~]# tar -zxf linux_amd64.tar.gz 3 [root@seaweedfs-bj-zw-vm1 ~]# ll 4 -rwxr-xr-x. 1 root root 48548500 5月 29 17:29 weed 5 [root@seaweedfs-bj-zw-vm1 ~]# ./weed -h # 查看幫助
master節點
master的作用僅僅是管理文件卷與服務器磁盤的映射,連文件的元數據也不管理,因此不需要額外的磁盤存儲,性能上也是極好的
1 [root@seaweedfs-bj-zw-vm1 ~]# tail -30 master.out 2 I0604 18:46:39 5872 node.go:224] topo:zw:openstack-bj-zw-bgp6 adds child 172.16.100.138:8082 3 I0604 18:46:39 5872 master_grpc_server.go:67] added volume server 172.16.100.138:8082 4 I0604 18:46:39 5872 master_grpc_server.go:95] master see new volume 23 from 172.16.100.136:8081 5 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.111:25608: url:"172.16.100.136:8081" public_url:"172.16.100.136:8081" new_vids:23 6 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.107:15594: url:"172.16.100.136:8081" public_url:"172.16.100.136:8081" new_vids:23 7 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.106:40120: url:"172.16.100.136:8081" public_url:"172.16.100.136:8081" new_vids:23 8 I0604 18:46:39 5872 node.go:224] topo:zw:openstack-bj-zw-bgp6 adds child 172.16.100.138:8081 9 I0604 18:46:39 5872 master_grpc_server.go:67] added volume server 172.16.100.138:8081 10 I0604 18:46:39 5872 master_grpc_server.go:95] master see new volume 24 from 172.16.100.138:8081 11 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.111:25608: url:"172.16.100.138:8081" public_url:"172.16.100.138:8081" new_vids:24 12 I0604 18:46:39 5872 master_grpc_server.go:95] master see new volume 22 from 172.16.100.138:8082 13 I0604 18:46:39 5872 master_grpc_server.go:95] master see new volume 25 from 172.16.100.138:8082 14 I0604 18:46:39 5872 master_grpc_server.go:95] master see new volume 28 from 172.16.100.138:8082 15 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.111:25608: url:"172.16.100.138:8082" public_url:"172.16.100.138:8082" new_vids:22 new_vids:25 new_vids:28 16 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.107:15594: url:"172.16.100.138:8081" public_url:"172.16.100.138:8081" new_vids:24 17 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.107:15594: url:"172.16.100.138:8082" public_url:"172.16.100.138:8082" new_vids:22 new_vids:25 new_vids:28 18 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.106:40120: url:"172.16.100.138:8082" public_url:"172.16.100.138:8082" new_vids:22 new_vids:25 new_vids:28 19 I0604 18:46:39 5872 master_grpc_server.go:107] master send to filer172.16.100.106:40120: url:"172.16.100.138:8081" public_url:"172.16.100.138:8081" new_vids:24 20 I0604 18:46:39 5872 node.go:224] topo:zw:openstack-bj-zw-bgp5 adds child 172.16.100.136:8082 21 這是我使用過產生的日志,在master的輸出日志中我們可以直觀看出master see new volume 22 from 172.16.100.138:8082這類日志,這就是卷及其映射,代表22號卷在172.16.100.138的8082端口可訪問 22 我們啟動一個master,並設置一些參數,參數有很多都是默認的,可以不設置 23 # mdir 存儲元數據的數據目錄 24 # port 監聽端口 25 # peers 主節點ip:端口 26 # defaultReplication 備份策略 27 # ip 服務器ip 28 # garbageThreshold 清空和回收空間的閾值 29 # maxCpu 最大cpu數量,0是所有 30 # pulseSeconds 心跳檢測的時間間隔單位為秒 31 # ip.bind 綁定ip 32 # volumeSizeLimitMB volumes超載量,最大30G,即一個卷可以存多少數據,當然一個卷不代表一個磁盤,這點在下面的volume節點上再寫 33 [root@seaweedfs-bj-zw-vm1 ~]# /root/weed master -mdir=/data/seaweedfs -port=9333 -peers=172.16.100.107:9333,172.16.100.111:9333,172.16.100.106:9333 -defaultReplication="000" -ip="172.16.100.107" -garbageThreshold=0.3 -maxCpu=0 -pulseSeconds=5 -ip.bind=0.0.0.0 -volumeSizeLimitMB=30000 >>/root/master.out & 34 [root@seaweedfs-bj-zw-vm1 ~]# tree /data/ # 這個目錄里其實沒啥東西 35 /data/ 36 └── seaweedfs 37 ├── conf 38 ├── log 39 └── snapshot 40 41 2 directories, 2 files 42 [root@seaweedfs-bj-zw-vm1 ~]# netstat -tpln|grep 9333 43 tcp6 0 0 :::19333 :::* LISTEN 770/weed 44 tcp6 0 0 :::9333 :::* LISTEN 770/weed 45 這樣我們一個master節點就起來,當然如果你需要高可用的時候要將另外的master節點也起來,master節點是奇數,他們之間會選舉leader,剩下的成為從節點以備不時之需,我們的參數-peers就是指定所有的master節點ip及port,如果是測試只是用單機那就不用加這個參數了
volume節點
volume很明顯就是存儲數據的真實節點了,它保留了文件的元數據及文件,通過卷的模式將磁盤分割,每個卷都有一個索引文件,每個元數據只有40字節,讀取時間O(1),效率極高,速度極快
1 首先我們先將底層磁盤掛載上,我是2個1T的磁盤 2 [root@seaweedfs-bj-zw-vm5 ~]# mkdir -p /data/seaweedfs/volume{1..2} 3 [root@seaweedfs-bj-zw-vm5 ~]# mount /dev/vdb /data/seaweedfs/volume1 4 [root@seaweedfs-bj-zw-vm5 ~]# mount /dev/vdc /data/seaweedfs/volume2 5 [root@seaweedfs-bj-zw-vm5 ~]# df -h 6 文件系統 容量 已用 可用 已用% 掛載點 7 /dev/vda1 40G 2.3G 38G 6% / 8 devtmpfs 1.9G 0 1.9G 0% /dev 9 tmpfs 1.9G 12K 1.9G 1% /dev/shm 10 tmpfs 1.9G 17M 1.9G 1% /run 11 tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup 12 tmpfs 379M 0 379M 0% /run/user/0 13 /dev/vdb 1.0T 369G 656G 36% /data/seaweedfs/volume1 14 /dev/vdc 1.0T 185G 840G 18% /data/seaweedfs/volume2 15 # dir 存儲數據文件的目錄,剛才的掛載點 16 # mserver master服務器列表 17 # port 監聽端口 18 # ip 服務器ip 19 # max 本機volumes的最大值,在master上我們定義的每個卷為30G,可是我們的磁盤不可能就這么點,而max的作用就是表示這個磁盤上可以分多少個卷,默認是7,也就是30G * 7 = 210G,很明顯磁盤被浪費了很多空間,因此我們需要指定一個大max值,保證volumeSizeLimitMB * max >= 磁盤容量,當然你可以直接100,簡單粗暴 20 # dataCenter 機房 21 # rack 機架 22 # idleTimeout 連接空閑時間秒數 23 # images.fix.orientation 上傳時調整jpg方向 24 # ip.bind 監聽ip 25 # maxCpu 最大cpu數量 26 # read.redirect 重新定向轉移非本地volumes 27 28 /root/weed volume -dir=/data/seaweedfs/volume1 -mserver=172.16.100.107:9333,172.16.100.111:9333,172.16.100.106:9333 -ip="172.16.100.136" -max=100 -dataCenter=zw -rack=openstack-bj-zw-bgp5 -idleTimeout=30 -images.fix.orientation=true -ip.bind=0.0.0.0 -maxCpu=0 -port=8081 -read.redirect=true >>/root/volume1.out & 29 /root/weed volume -dir=/data/seaweedfs/volume2 -mserver=172.16.100.107:9333,172.16.100.111:9333,172.16.100.106:9333 -ip="172.16.100.136" -max=100 -dataCenter=zw -rack=openstack-bj-zw-bgp5 -idleTimeout=30 -images.fix.orientation=true -ip.bind=0.0.0.0 -maxCpu=0 -port=8082 -read.redirect=true >>/root/volume2.out & 30 [root@seaweedfs-bj-zw-vm5 ~]# tail -30 volume1.out 31 I0605 05:28:44 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:35 collection: replicaPlacement:000 ttl: 32 I0605 05:28:44 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/35.idx to memory readonly false 33 I0605 05:28:44 23656 store.go:103] add volume 35 34 I0605 22:36:02 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:36 collection: replicaPlacement:000 ttl: 35 I0605 22:36:02 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/36.idx to memory readonly false 36 I0605 22:36:02 23656 store.go:103] add volume 36 37 I0605 22:36:02 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:41 collection: replicaPlacement:000 ttl: 38 I0605 22:36:02 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/41.idx to memory readonly false 39 I0605 22:36:02 23656 store.go:103] add volume 41 40 I0605 22:36:02 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:42 collection: replicaPlacement:000 ttl: 41 I0605 22:36:02 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/42.idx to memory readonly false 42 I0605 22:36:02 23656 store.go:103] add volume 42 43 I0606 04:03:13 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:43 collection: replicaPlacement:000 ttl: 44 I0606 04:03:13 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/43.idx to memory readonly false 45 I0606 04:03:13 23656 store.go:103] add volume 43 46 I0606 09:42:43 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:50 collection: replicaPlacement:000 ttl: 47 I0606 09:42:43 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/50.idx to memory readonly false 48 I0606 09:42:43 23656 store.go:103] add volume 50 49 I0606 09:42:43 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:51 collection: replicaPlacement:000 ttl: 50 I0606 09:42:43 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/51.idx to memory readonly false 51 I0606 09:42:43 23656 store.go:103] add volume 51 52 I0606 09:42:43 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:53 collection: replicaPlacement:000 ttl: 53 I0606 09:42:43 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/53.idx to memory readonly false 54 I0606 09:42:43 23656 store.go:103] add volume 53 55 I0606 14:23:03 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:58 collection: replicaPlacement:000 ttl: 56 I0606 14:23:03 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/58.idx to memory readonly false 57 I0606 14:23:03 23656 store.go:103] add volume 58 58 I0606 14:23:03 23656 store.go:99] In dir /data/seaweedfs/volume1 adds volume:62 collection: replicaPlacement:000 ttl: 59 I0606 14:23:03 23656 volume_loading.go:82] loading index /data/seaweedfs/volume1/62.idx to memory readonly false 60 I0606 14:23:03 23656 store.go:103] add volume 62 61 [root@seaweedfs-bj-zw-vm5 ~]# du -sh /data/seaweedfs/volume1/* 62 30G /data/seaweedfs/volume1/23.dat 63 4.9M /data/seaweedfs/volume1/23.idx 64 30G /data/seaweedfs/volume1/29.dat 65 5.5M /data/seaweedfs/volume1/29.idx 66 30G /data/seaweedfs/volume1/33.dat 67 5.5M /data/seaweedfs/volume1/33.idx 68 30G /data/seaweedfs/volume1/34.dat 69 5.5M /data/seaweedfs/volume1/34.idx 70 30G /data/seaweedfs/volume1/35.dat 71 5.5M /data/seaweedfs/volume1/35.idx 72 30G /data/seaweedfs/volume1/36.dat 73 4.8M /data/seaweedfs/volume1/36.idx 74 30G /data/seaweedfs/volume1/41.dat 75 4.9M /data/seaweedfs/volume1/41.idx 76 30G /data/seaweedfs/volume1/42.dat 77 4.9M /data/seaweedfs/volume1/42.idx 78 30G /data/seaweedfs/volume1/43.dat 79 3.0M /data/seaweedfs/volume1/43.idx 80 30G /data/seaweedfs/volume1/50.dat 81 3.5M /data/seaweedfs/volume1/50.idx 82 30G /data/seaweedfs/volume1/51.dat 83 3.5M /data/seaweedfs/volume1/51.idx 84 30G /data/seaweedfs/volume1/53.dat 85 3.5M /data/seaweedfs/volume1/53.idx 86 8.1G /data/seaweedfs/volume1/58.dat 87 2.0M /data/seaweedfs/volume1/58.idx 88 7.9G /data/seaweedfs/volume1/62.dat 89 2.0M /data/seaweedfs/volume1/62.idx 90 我們可以看錯,每個索引文件最大5M,數據文件30G,磁盤被分割成了很多的卷(idx+dat)
簡單測試
現在的模式是master+ volume這種標准模式
1 [root@seaweedfs-bj-zw-vm5 ~]# curl http://172.16.100.107:9333/dir/assign 2 {"fid":"3,57f4e1898d66","url":"172.16.100.136:8082","publicUrl":"172.16. 100.136:8082","count":1} 3 [root@seaweedfs-bj-zw-vm5 ~]# curl -F file=@/root/9ee6c1c5d88b0468af1a3280865a6b7a.png http://172.16.100.136:8082/3,57f4e1898d66 4 [root@seaweedfs-bj-zw-vm5 ~]# wget 172.16.100.136:8082/3,57f4e1898d66 5 [root@seaweedfs-bj-zw-vm5 ~]# ls # 新下載下來的資源會被命名為fid 6 3,57f4e1898d66 7 [root@seaweedfs-bj-zw-vm5 ~]# curl -X DELETE 172.16.100.136:8082/3,57f4e1898d66 8 我們可以看出流程是,找master節點申請ip:port及fid,自己拼接ip:port/fid,然后post上傳,此時該資源到服務器上了,我們可以對ip:port/fid進行get等請求 9 這里面有2點比較麻煩 10 1. 要先申請,再拼接,再上傳 11 2. 要記錄返回的ip:port/fid才能對該資源進行以后的操作,也就是3個信息 12 相對應的解決方式也是有的 13 1. curl -F file=@/root/9ee6c1c5d88b0468af1a3280865a6b7a.png http://172.16.100.107:9333/submit這樣會直接上傳(申請fid+上傳) 14 2. wget 172.16.100.107:9333/3,57f4e1898d66我們就直接訪問master節點ip:port/fid,這樣也是可以操作資源的,因為內部默認是開啟了內部代理功能,我們只需要記錄fid就可以了
現實問題
在大部分中小企業中,大家一開始使用的都是nginx+nfs提供靜態資源訪問的模式,也就是nginx管理root路徑,而root路徑是外部掛載的大磁盤,然后我們訪問的時候就是url/資源路徑模式。
它的優點在於
- 簡單、簡單、簡單,重要的事情說三遍
- 成本低,不論是硬件成本還是管理成本
- 訪問模式很直觀,從url就可以看出文件路徑
它的缺點主要還是來源於規模帶來的一些問題
- 不是接口形式,所以項目需要直接操作磁盤,本身只支持get請求,其他請求需要代碼來協助完成
- 權限問題,因為項目必須能操作磁盤,那么該目錄的權限需要管理以及相關的安全問題
- 容量問題,隨着時間的推移,我們的大磁盤需要擴容,可是每次擴容前我們需要備份(以防萬一),而這個磁盤已經幾個T了,備份時間過長
- 高可用問題,nfs的底層磁盤應該是某台機器組成的raid,那么這台機器掛了怎么辦,當然有人說有備機,但是nfs掛載自動切換還有有點慢
- 所有需要落盤操作的機器都必須要掛載nfs,nfs的掛載連接數,磁盤io及網絡開銷隨着掛載機器增多也在增大
- Nfs是文件存儲,隨着文件的增多,文件的索引層級也會越來越深影響速度
- 逼格不夠,哈哈哈哈
解決方式
我們自然是使用本次的seaweedfs作為圖片服務器了,這樣就可以對應解決我們上述的問題
- 默認提供restful api,不需要代碼層級再度實現
- 有了接口走的是http協議,只需要網絡通就可以,不需要到處掛載文件系統了
- 容量不足了我們加機器、加磁盤進集群即可
- 本身實現了多種備份方式,可根據實際情況來選擇
- 同2
- 本質還是對象存儲,索引文件5M,操作速度極快
引出的問題
- 現有階段的代碼都是以url/文件路徑,這種模式進行操作的,而seaweedfs是url/fid,改動量太大,不好實現
- 因為是restful api,所以大家都能直接delete,很危險…..
解決方式
- 使用filer功能
- 對內網提供不同的域名,對外域名在Nginx上只允許get請求
filer節點
filer節點是可以在任何地方執行的,它再次打開了一個http服務,並且也對外提供restful api,只是我們可以使用url/文件路徑的模式進行訪問了(之前的url/fid依然生效),filer節點提供的http服務可以如同一個文件系統一樣被掛載,在掛載點,我們可以直觀的看見目錄層級(也是對象),及操作各個文件
1 [root@seaweedfs-bj-zw-vm1 ~]# /root/weed filer -master=172.16.100.111:9333,172.16.100.107:9333,172.16.100.106:9333 -ip=172.16.100.107 -defaultReplicaPlacement='000' -disableDirListing >>/root/filer.out & 2 [root@seaweedfs-bj-zw-vm1 ~]# /root/weed mount -filer=172.16.100.107:8888 -dir=/mnt >>/dev/null & 3 [root@seaweedfs-bj-zw-vm1 ~]# netstat -tpln|grep 8888 4 tcp 0 0 172.16.100.107:8888 0.0.0.0:* LISTEN 771/weed 5 tcp6 0 0 :::18888 :::* LISTEN 771/weed 6 [root@seaweedfs-bj-zw-vm1 ~]# df -h|grep mnt 7 SeaweedFS 1.3T 1.2T 48G 97% /mnt
訪問的流程其實還是,以路徑模式操作---根據路徑獲取fid---以fid模式操作----seaweedfs,也就是路徑跟fid之間filer節點幫你做了一次轉換
在默認情況下這種對應關系是存放在內存當中,實際情況下,我們需要安裝一個記錄關系的服務,以下是官方推薦的服務及其功能,我們果斷使用了熟悉的redis,redis的記錄也很簡單,就是最簡單的string的kv對應關系,key是路徑,value是fid(轉義過的),當然其他存儲的關系大概也能想來,數據庫類的自然就是有一個表(這個表的sql在配置文件里都有),然后就是兩個記錄的字段即可
1 [root@seaweedfs-bj-zw-vm1 ~]# mkdir -p /etc/seaweedfs 2 [root@seaweedfs-bj-zw-vm1 ~]# cd /etc/seaweedfs 3 [root@seaweedfs-bj-zw-vm1 seaweedfs]# /root/weed scaffold filer -output=" filer.toml " 4 [root@seaweedfs-bj-zw-vm1 ~]# vim /etc/seaweedfs/filer.toml # 把redis的信息填好,如果使用其他后端,將其enabled改成true並填寫相關信息即可 5 [redis] 6 enabled = true 7 address = "xxx:6379" 8 password = "" 9 db = 0
我們重啟filer服務后再次掛載,此時對應關系就會存在redis里了,個人已經放入1.T數據,大概1.5億個key,在性能上完全沒問題
后期我們不論是使用restful api,還是在mount的目錄直接進行操作,還是在redis的庫里直接操作,這三者操作都是一致的。例如我們在redis上刪除了某個路徑的key,那么這個文件就會直接消失,因此保存關系的后端也要維護好哦,當然,如果redis掛了,那么filer功能就會崩潰,只能直接使用url/fid的模式
因此,使用filer來兼容之前nfs,我們需要額外保證后端存儲的可用性!