GlusterFS分布式文件系統
一.簡單介紹
分布式存儲按其存儲接口分為三種:文件存儲、塊存儲、對象存儲
*文件存儲
通常支持POSIX接口(如glusterFS,但GFS、HDFS是非POSIX接口的),可以像普通文件系統(如ext4)那樣訪問,但又比普通文件系統多了並行化訪問的能力和冗余機制。主要的分布式存儲系統有TFS、CephFS、GlusterFS和HDFS等。主要存儲非結構化數據,如普通文件,圖片,音視頻等。
*塊存儲
這種接口通常以QEMU Driver或者Kernel Module的方式存在,主要通過qemu或iscsi協議訪問。主要的塊存儲系統有Ceph塊存儲、SheepDog等。主要用來存儲結構化數據,如數據庫數據。
*對象存儲
對象存儲系統綜合了文件系統(NAS)和塊存儲(SAN)的優點,同時具有SAN的高速直接訪問和NAS的數據共享等優勢。以對象作為基本的存儲單元,向外提供Restful數據讀寫接口,常以網絡服務的形式提供數據訪問。主要的對象存儲系統有AWS、Swift和Ceph對象存儲。主要用來存儲費結構化數據
GlusterFS是Scale-out存儲解決方案Gluster的核心,它是一個開源的分布式文件系統,具有強大的橫向擴展能力,通過擴展能夠支持數PB存儲容量和處理數千客戶端。GlusterFS借助TCP/IP或者InfiniBandRDMA網絡將物理分布的存儲資源聚集在一起,具有高擴展性、高可用性、高性能的特點,並且沒有元數據服務器的設計,讓整個服務沒有單點故障的隱患,使用單一全局命名空間來管理數據。
二.GlusterFS架構
三.GlusterFS特點
*優勢:
- 擴展性和高性能
GlusterFS采用無中心對稱式結構,沒有專用的元數據服務器,也就不存在元數據服務器瓶頸。元數據存在於文件的屬性和擴展屬性中,當需要訪問某文件時,客戶端使用DHT算法,根據文件的路徑和文件名計算出文件所在的brick,然后由客戶端從此brick獲取數據,省去了同元數據服務器通信的過程。 - 良好的可擴展性
使用彈性hash算法替代傳統的有元數據節點服務,獲得了接近線性的高擴展性 - 高可用
采用副本、EC等冗余設計,保證在冗余范圍內的節點掉線時,任然可以從其它服務器節點獲取數據,保證高可用性。采用弱一致性的設計,當向副本中文件寫入數據時,客戶端計算出文件所在brick,然后通過網絡把數據傳給所在brick,當其中有一個成功返回,就認為數據成功寫入,不必等待其它brick返回,就會避免當某個節點網絡異常或磁盤損壞時,因為一個brick沒有成功寫入而導致寫操作等待。
服務器端還會隨着存儲池的啟動,而開啟一個glustershd進程,這個進程會定期檢查副本和EC卷中各個brick之間數據的一致性,並恢復。 - 存儲池類型豐富
包括粗粒度、條帶、副本、條帶副本和EC,可以根據用戶的需求,滿足不同程度的冗余。
粗粒度不帶任何冗余,文件不進行切片,是完整的存放在某個brick上。
條帶卷不帶任何冗余,文件會切片存儲(默認大小為128kB)在不同的brick上,這些切片可以並發讀寫(並發粒度是條帶塊),可以明顯提高讀寫性能。該模式一般只適合用於處理超大型文件和多節點性能要求高的情況。
副本卷冗余度高,副本數量可以靈活配置,可以保證數據的安全性
條帶副本卷是條帶卷和副本卷的結合
EC卷使用EC校驗算法,提供了低於副本卷的冗余度,冗余度小於100%,滿足比較低的數據安全性,例如可以使2+1(冗余度為50%),5+3(冗余度為60%)等。這個可以滿足安全性要求不高的數據
*缺點:
- 擴容、縮容時影響的服務器較多
GlusterFS對邏輯卷中的存儲單元brick划分hash分布式空間(會以brick所在磁盤大小作為權重,空間總范圍為0~2**32-1),一個brick占一份空間,當訪問某文件時,使用Davies-Meyer算法根據文件名計算出hash值,比較hash值落在哪個范圍內,即可確認文件所在的brick,這樣定位文件會很快。但是在向邏輯卷中添加或移除brick時,hash分布空間會重新計算,每個brick的hash范圍都會變化,文件定位就會失敗,因此需要遍歷文件,把文件移動到正確的hash分布范圍對應的brick上,移動的文件可能會很多,加載系統負載,影響到正常的文件訪問操作。 - 遍歷目錄下文件耗時
GlusterFS沒有元數據節點,而是根據hash算法來確定文件的分布,目錄利用擴展屬性記錄子卷中的brick的hash分布范圍,每個brick的范圍均不重疊,遍歷目錄時,需要readdir子卷中每個brick中的目錄。獲取每個文件的屬性和擴展屬性,然后進行聚合,相對於有專門元數據節點的分布式存儲,遍歷效率會差很多,當目錄下有大量文件時,遍歷會非常緩慢。
刪除目錄也會遇到此問題,目前提供的解決方法是合理組織目錄結構,目錄層級不要太深,目錄下文件數量不要太多,增大GlusterFS目錄緩存,另外,還可以設計把元數據和數據分離,把元數據放到內存數據庫中(如redis、memcache),並在ssd上持久保持 - 小文件性能較差
GlusterFS主要是為大文件設計,如io-cache、read-ahead、write-behind和條帶等都是為優化大文件訪問,對小文件的優化很少。
GlusterFS采用無元數據節點的設計,文件的元數據和數據一起保持在文件中,訪問元數據和數據的速率相同。訪問元數據的時間與訪問數據的時間比例會較大,而有元數據中心的分布式存儲系統,對元數據服務器可以采用快速的SSD盤(如ceph),可以采用更大的元數據緩存等優化措施才減少訪問元數據時間與訪問數據時間的比值,來提高小文件性能
四.GlusterFS的組件
-
brick
GlusterFS中的存儲單元,通常是一個受信存儲池中的服務器的一個導出目錄。可以通過主機名和目錄名來標識,如'SERVER:EXPORT'- brick是一個節點和一個導出目錄的集合,e.g.node1:/brick1
- brick是底層的RAID或磁盤經XFS或ext4文件系統格式化而來,所以繼承了文件系統的限制
- 每個節點上的brick數是不限的
- 理想的狀況是,一個集群的所有brick大小都一樣
-
Client
掛載了GlusterFS卷的設備 -
GFID
GlusterFS卷中的每個文件或目錄都有一個唯一的128位的數據相關聯,其用於模擬inode -
Namespace
每個Gluster卷都導出單個ns作為POSIX的掛載點 -
Node
一個擁有若干brick的設備 -
RDMA
遠程直接內存訪問,支持不通過雙方的OS進行直接內存訪問 -
RRDNS
round robin DNS是一種通過DNS輪轉返回不同的設備以進行負載均衡的方法 -
Self-heal
用於后台運行監測副本卷中文件和目錄的不一致性並解決這些不一致 -
Split-brain
腦裂 -
Volfile
GlusterFS進程的配置文件,通常位於/var/lib/glusterd/vols/volname -
Volume
- 是brick的邏輯組合
- 創建時命名來識別
-
Trushed Storage Pool
- 一堆存儲節點的集合
- 通過一個節點邀請其它節點創建,這里叫probe
- 成員可以動態加入,動態刪除
五.GlusterFS集群的部署
我們使用GlusterF作為K8S的后端存儲,在使用動態存儲StorageClass時,集群至少需要配置三節點,如果GlusterFS集群少於三節點,在創建volume時會提示Failed to allocate new volume: No space報錯
這里我們采用的集群節點如下:
節點hostname 節點IP 數據盤
glusterfs-01 192.168.1.123 /dev/sdb,/dev/sdc
glusterfs-02 192.168.1.125 /dev/sdb,/dev/sdc
glusterfs-03 192.168.1.127 /dev/sdb
5.1 部署配置GlusterFS集群
1)所有節點安裝gluster
[root@glusterfs-01 ~]#yum install centos-release-gluster -y
[root@glusterfs-01 ~]#yum install -y glusterfs glusterfs-server glusterfs-fuse glusterfs-rdma glusterfs-geo-replication glusterfs-devel
2)啟動glusterFS
[root@glusterfs-01 ~]#systemctl start glusterd.service
[root@glusterfs-01 ~]#systemctl enable glusterd.service
[root@glusterfs-01 ~]#systemctl status glusterd.servic
3)在集群任意節點,將glusterfs的peer添加進去
[root@glusterfs-01 ~]#gluster peer probe glusterfs-01
[root@glusterfs-01 ~]#gluster peer probe glusterfs-02
[root@glusterfs-01 ~]#gluster peer probe glusterfs-03
4)格式化集群所有節點的所有數據盤,並將物理硬盤分區初始化為物理卷
[root@glusterfs-01 ~]#mkfs.xfs /dev/sdb -f
[root@glusterfs-01 ~]#pvcreate /dev/sdb
[root@glusterfs-01 ~]#mkfs.xfs /dev/sdc -f
[root@glusterfs-01 ~]#pvcreate /dev/sdc
5.2 部署配置GlusterFS的動態存儲StorageClass
heketi提供一個RESTful管理節點界面,可以用來管理GlusterFS卷的生命周期,通過heketi,就可以像使用Opentack Manila,kubernetes和openShift一樣申請可以動態配置GlusterFS卷,Heketi會動態在集群內選擇bricks構建所需的volumes,這樣以確保數據的副本會分散到集群不同的故障域內。
1)所有節點安裝heketi和heketi的客戶端
[root@glusterfs-01 ~]#yum install -y heketi heketi-client
2)在集群主節點配置SSH密鑰
[root@glusterfs-01 ~]#ssh-keygen -f /etc/heketi/heketi_key -t rsa -N ''
[root@glusterfs-01 ~]#ssh-copy-id -i /etc/heketi/heketi_key.pub root@glusterfs-01
[root@glusterfs-01 ~]#ssh-copy-id -i /etc/heketi/heketi_key.pub root@glusterfs-02
[root@glusterfs-01 ~]#ssh-copy-id -i /etc/heketi/heketi_key.pub root@glusterfs-03
[root@glusterfs-01 ~]#chown heketi:heketi /etc/heketi/heketi_key*
3)編輯修改heketi的配置文件/etc/heketi/heketi.json
heketi有三種executor,分別為mock,ssh,kubernetes,建議在測試環境使用mock,生成環境使用ssh,當glusterfs以容器的方式部署在Kubernetes上時,才是用kubernetes。
[root@glusterfs-01 ~]# cat /etc/heketi/heketi.json
{
"_port_comment": "Heketi Server Port Number",
#這里端口默認為8080,如果在實際的使用過程中,可以修改此端口號
"port": "8080",
"_use_auth": "Enable JWT authorization. Please enable for deployment",
"use_auth": false,
"_jwt": "Private keys for access",
"jwt": {
"_admin": "Admin has access to all APIs",
"admin": {
"key": "My Secret"
},
"_user": "User only has access to /volumes endpoint",
"user": {
"key": "My Secret"
}
},
"_glusterfs_comment": "GlusterFS Configuration",
"glusterfs": {
"_executor_comment": [
"Execute plugin. Possible choices: mock, ssh",
"mock: This setting is used for testing and development.",
" It will not send commands to any node.",
"ssh: This setting will notify Heketi to ssh to the nodes.",
" It will need the values in sshexec to be configured.",
"kubernetes: Communicate with GlusterFS containers over",
" Kubernetes exec api."
],
#修改執行插件為ssh
"executor": "ssh",
#配置ssh所需的證書
"_sshexec_comment": "SSH username and private key file information",
"sshexec": {
"keyfile": "/etc/heketi/heketi_key",
"user": "root",
"port": "22",
"fstab": "/etc/fstab"
},
"_kubeexec_comment": "Kubernetes configuration",
"kubeexec": {
"host" :"https://kubernetes.host:8443",
"cert" : "/path/to/crt.file",
"insecure": false,
"user": "kubernetes username",
"password": "password for kubernetes user",
"namespace": "OpenShift project or Kubernetes namespace",
"fstab": "Optional: Specify fstab file on node. Default is /etc/fstab"
},
"_db_comment": "Database file name",
"db": "/var/lib/heketi/heketi.db",
"_loglevel_comment": [
"Set log level. Choices are:",
" none, critical, error, warning, info, debug",
"Default is warning"
],
"loglevel" : "debug"
}
}
4)在集群所有節點將heketi服務加入開機啟動,並啟動服務
[root@glusterfs-01 ~]#systemctl restart heketi
[root@glusterfs-01 ~]#systemctl enable heketi
5)測試heketi的連接
[root@glusterfs-01 ~]# curl http://glusterfs-01:8080/hello
Hello from Heketi[root@glusterfs-01 ~]#
[root@glusterfs-01 ~]# curl http://glusterfs-02:8080/hello
Hello from Heketi[root@glusterfs-01 ~]#
[root@glusterfs-01 ~]# curl http://glusterfs-03:8080/hello
Hello from Heketi[root@glusterfs-01 ~]#
6)在集群的主節點設置環境變量
注意這里的端口號要和/etc/heketi/heketi.json配置文件中的保持一致
[root@glusterfs-01 ~]#export HEKETI_CLI_SERVER=http://glusterfs-01:8080
7)在集群的主節點修改/usr/share/heketi/topology-sample.json配置文件,執行添加節點和添加device的操作
manage為GFS管理服務的Node節點主機名,storage為Node節點IP,device為Node節點上的裸設備
[root@glusterfs-01 ~]# cat /usr/share/heketi/topology-sample.json
{
"clusters": [
{
"nodes": [
{
"node": {
"hostnames": {
"manage": [
"glusterfs-01"
],
"storage": [
"192.168.1.123"
]
},
"zone": 1
},
"devices": [
{
"name": "/dev/sdb",
"destroydata": false
},
{
"name": "/dev/sdc",
"destroydata": false
}
]
},
{
"node": {
"hostnames": {
"manage": [
"glusterfs-02"
],
"storage": [
"192.168.1.125"
]
},
"zone": 1
},
"devices": [
{
"name": "/dev/sdb",
"destroydata": false
},
{
"name": "/dev/sdc",
"destroydata": false
}
]
},
{
"node": {
"hostnames": {
"manage": [
"glusterfs-03"
],
"storage": [
"192.168.1.127"
]
},
"zone": 1
},
"devices": [
{
"name": "/dev/sdb",
"destroydata": false
}
]
}
]
}
]
}
執行創建:
[root@glusterfs-01 ~]# heketi-cli topology load --json=/usr/share/heketi/topology-sample.json
Creating cluster ... ID: 1a182a5967c9b6689ac0e60f6bf037fe
Allowing file volumes on cluster.
Allowing block volumes on cluster.
Creating node glusterfs-01 ... ID: f70e977eb2a36b8ab4a5fa1f4fb5dadc
Adding device /dev/sdb ... OK
Adding device /dev/sdc ... OK
Creating node glusterfs-02 ... ID: f2b6e9a3e32e8aea3ee04aa39430a538
Adding device /dev/sdb ... OK
Adding device /dev/sdc ... OK
Creating node glusterfs-03 ... ID: f4c6e9a3e32a36b8ab39430dadc300aa3
Adding device /dev/sdb ... OK
創建一個volume測試
[root@glusterfs-01 ~]# heketi-cli volume create --size=2
Name: vol_3488b923b854a115cec5354ad9941489
Size: 2
Volume Id: 3488b923b854a115cec5354ad9941489
Cluster Id: b994b57f05d2868f12ae046caaaa33f5
Mount: 192.168.1.125:vol_3488b923b854a115cec5354ad9941489
Mount Options: backup-volfile-servers=192.168.1.123,192.168.1.127
Block: false
Free Size: 0
Reserved Size: 0
Block Hosting Restriction: (none)
Block Volumes: []
Durability Type: replicate
Distributed+Replica: 3
查看volume的信息:
[root@glusterfs-01 ~]# gluster volume info
Volume Name: vol_3488b923b854a115cec5354ad9941489
Type: Replicate
Volume ID: dd8d5556-f74b-4757-9678-3736f8a50540
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x 3 = 3
Transport-type: tcp
Bricks:
Brick1: 192.168.1.125:/var/lib/heketi/mounts/vg_114274eb7da9d241080e09673f6b4920/brick_06260836e395cfb530f5fe3470681e7b/brick
Brick2: 192.168.1.123:/var/lib/heketi/mounts/vg_671bf19791b555b967c1537bf3c383c5/brick_f118bb0aca3f85eef02725041411c9f3/brick
Brick3: 192.168.1.127:/var/lib/heketi/mounts/vg_98733e5faf54c9c023d928d1858f1aaf/brick_b6e86351244a8e028f3838e90b51ab9e/brick
Options Reconfigured:
transport.address-family: inet
nfs.disable: on
performance.client-io-threads: off
8)配置StorageClass
創建glusterfs-storageclass.yaml文件內容如下:
[root@glusterfs-01 ~]# cat glusterfs-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gluster-dynmic
provisioner: kubernetes.io/glusterfs
parameters:
#這里根據配置的環境變量指定主機的hostname或者ip都可
resturl: http://192.168.1.123:8080
restauthenabled: "false"
執行storageclass的創建
[root@glusterfs-01 ~]# kubectl create -f glusterfs-storageclass.yaml
查看storageclass
[root@glusterfs-01 ~]# kubectl get sc
NAME PROVISIONER AGE
gluster-dynmic kubernetes.io/glusterfs 2d17h
9)執行PVC的創建測試
pvc的yaml文件如下:
[root@glusterfs-01 ~]# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gluster-dyn-pvc
annotations:
volume.beta.kubernetes.io/storage-class: gluster-dynmic
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
執行PVC的創建:
[root@glusterfs-01 ~]# kubectl create -f pvc.yaml
persistentvolumeclaim/gluster-dyn-pvc created
查看創建的PVC的狀態:
[root@glusterfs-01 ~]# kubectl get pvc
gluster-dyn-pvc Bound pvc-0c1cb408-1a08-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 42s
10)Pod的創建驗證
[root@glusterfs-01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mysql-6668bbf547-rvmfb 1/1 Running 0 106m
redis-c744fd4c9-5p44g 1/1 Running 0 96m
[root@glusterfs-01 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
bigdata-pv-claim Bound pvc-1c74445b-19f9-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 108m
gluster-dyn-pvc Bound pvc-0c1cb408-1a08-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 109s
log-pv-claim Bound pvc-1c77ffc0-19f9-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 108m
mysql-pv-claim Bound pvc-1c771e55-19f9-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 108m
shared-pv-claim Bound pvc-1c762bd8-19f9-11e9-9f58-000c29c0255c 2Gi RWX gluster-dynmic 108m
六.節點擴容
monmaptool --add node1 10.0.2.21:6789 --add node2 10.0.2.22:6789 --add node3 10.0.2.23:6789 map