Web集羣實現共享存儲的架構演變及MogileFS

本篇博客從Web集羣中亟需解決的大容量存儲問題引入,分析了幾類常用的共享存儲架構,重點解析了分佈式存儲系統的原理及配置實現;

===================================================================

1 共享存儲的架構演變

2 分佈式存儲系統

    2.1 基礎知識

    2.2 分類

    2.3 CAP理論

    2.4 協議

3 MogileFS

    3.1 特性

    3.2 架構

    3.3 組成

    3.4 服務安裝及啓動

    3.5 配置部署

    3.6 配置前端代理Nginx

    3.7 訪問驗證

    3.8 後續擴展

===================================================================


1 共享存儲的架構演變

  • rsync+inotify:本地各保留一份完整數據,但通過rsync實時同步修改文件,雙主模型哦

  • NFS:多節點掛載後性能下降嚴重;存在單點故障,且多個客戶端併發修改同一個文件時可能出現不一致的情況;

  • SAN:存儲區域網絡,不適用於海量高併發的存儲場景,且代價昂貴;可通過軟件實現iSCSI存儲網絡;涉及GFS2/CLVM(LVM2)

  • MooseFS:分佈式文件系統,適用於海量小文件存儲;支持FUSE,可被掛載使用;

  • MogileFS:分佈式存儲系統,適用於海量小文件存儲;不支持FUSE,只能通過API調用;


2 分佈式存儲系統

2.1 基礎知識

定義:分佈式存儲系統是大量普通PC服務器通過Internet互聯,對外作爲一個整體提供存儲服務

特性

  • 可擴展:分佈式存儲系統可以擴展到幾百臺至幾千臺的集羣規模,且隨着集羣規模的增長,系統整體性能表現爲線性增長;

  • 低成本:分佈式存儲系統的自動容錯、自動負載均衡機制使其可以構建在普通PC機之上;另外,線性擴展能力也使得增加、減少機器非常方便,可以實現自動運維;

  • 高性能:無論是針對整個集羣還是單臺服務器,都要求分佈式系統具備高性能;

  • 易用:分佈式存儲系統需要能夠提供易用的對外接口;另外,也要求具備完善的監控、運維工具,並能方便的與其他系統集成,如從Hadoop雲計算系統導入數據;

挑戰:在於數據、狀態信息的持久化,要求在自動遷移、自動容錯、併發讀寫的過程中保證數據的一致性;

2.2 分類

數據類型大致可分爲非結構化數據(如文本、圖片、視頻等),結構化數據(一般存儲在關係型數據庫中),半結構化數據(如HTML文檔);根據處理不同類型數據的需求,分佈式存儲系統可分爲如下4類:

  • 分佈式文件系統:用於存儲Blob對象,如圖片、視頻等,這類數據以對象的形式組織,對象之間沒有關聯;如GFS,MogileFS等;

  • 分佈式鍵值系統:用於存儲關係簡單的半結構化數據,它只提供基於主鍵的CRUD(Create/Read/Update/Delete)功能;如Memcache,Redis等;

  • 分佈式表格系統:用於存儲關係較爲複雜的半結構化數據,不僅支持簡單的CRUD操作,還支持掃描某個主鍵範圍;如Google Bigtable、Megastore;

  • 分佈式數據庫:用於存儲結構化數據,利用二維表格組織數據;如MySQL Sharding集羣,Google Spanner等;

2.3 CAP理論

來自Berkerly的Eric Brewer教授提出了一個著名的CAP理論:一致性(Consistency),可用性(Availability)和分區容忍性(Tolerance of network Partition)三者不能同時滿足:

  • C:讀操作總是能讀取到之前完成的寫操作結果,滿足這個條件的系統成爲強一致系統,這裏的“之前”一般對同一個客戶端而言;

  • A:讀寫操作在單臺機器發生故障的情況下依然能夠正常執行,而不需要等待發生故障的機器重啓或者其上的服務遷移到其他機器;

  • P:機器故障、網絡故障、機房停電等異常情況下仍然能夠滿足一致性和可用性;

分佈式存儲系統要求能夠自動容錯,即分區可容忍性總是需要滿足的,因此,一致性和寫操作的可用性就不能同時滿足了,需要在這二者間權衡,是選擇不允許丟失數據,保持強一致,還是允許少量數據丟失以獲得更好的可用性;

2.4 協議

分佈式協議涉及的協議很多,例如租約,複製協議,一致性協議,其中以兩階段提交協議和Paxos協議最具有代表性;

兩階段提交協議(Two-phase Commit,2PC)用以保證跨多個節點操作的原子性,即跨多個節點的操作要麼在所有節點上全部執行成功,要麼全部失敗;

兩個階段的執行過程如下:

  • 階段一:請求階段(Prepare phase),在請求階段,協調者通知事務參與者準備提交或者取消事務,然後進入表決過程;

  • 階段二:提交階段(Commit phase);

Paxos協議用於確保多個節點對某個投票(例如哪個節點爲主節點)達成一致;


3 MogileFS

3.1 特性

  • 工作於應用層:無需特殊的核心組件;

  • 無單點:三大組件(tracker,mogstore,database)皆可實現高可用;

  • 自動文件複製:複製的最小單位不是文件,而是class;基於不同的class,文件可以被自動的複製到多個有足夠存儲空間的存儲節點上;

  • 傳輸中立,無特殊協議:可以通過NFS或HTTP協議進行通信;

  • 簡單的命名空間:文件通過一個給定的key來確定,是一個全局的命名空間;沒有目錄,基於域實現文件隔離;

  • 不共享數據:無需通過昂貴的SAN來共享磁盤,每個存儲節點只需維護自己所屬的存儲設備(device)即可;

3.2 架構

wKiom1N5jnXTNFaZAAITIAkEXNM059.jpg

Tracker:MogileFS的核心,是一個調度器;服務進程爲mogilefsd;可以做負載均衡調度;

  • 主要職責有:

  • 數據刪除;

  • 數據複製;

  • 監控:故障後生成新的數據副本;

  • 查詢;

Database:Tracker訪問Database,返回用戶可用的Storage Node及文件的存放位置;

mogstored:數據存儲的位置,通常是一個HTTP(WebDAV)服務器,用於數據的創建、刪除、獲取等;不可做負載均衡調度;

3.3 組成

MogileFS由3個部分組成:

server:主要包括mogilefsd和mogstored兩個應用程序。

  • mogilefsd實現的是tracker,它通過數據庫來保存元數據信息,包括站點domain、class、host等;

  • mogstored是存儲節點(store node),它其實是個WebDAV服務,默認監聽在7500端口,接受客戶端的文件存儲請求。

Utils(工具集):主要是MogileFS的一些管理工具,例如mogadm等;

  • 在MogileFS安裝完後,要運行mogadm工具將所有的store node註冊到mogilefsd的數據庫裏,mogilefsd會對這些節點進行管理和監控;

客戶端API:MogileFS的客戶端API很多,例如Perl、PHP、Java、Python等,用這個模塊可以編寫客戶端程序,實現文件的備份管理功能等;

3.4 服務安裝及啓動

基本架構(在LNMT架構的基礎上改進)

wKioL1N5jryCLxbNAAcokoPHoI8707.jpg

服務器規劃

wKiom1N5jv6RaOl_AALC6DaRAQg067.jpg

服務安裝及啓動

數據庫授權

MariaDB [(none)]> grant all on *.* to 'root'@'192.168.%.%' identified by 'magedu';
Query OK, 0 rows affected (0.01 sec)
MariaDB [(none)]> grant all on mogdb.* to 'moguser'@'192.168.%.%' identified by 'mogpass';
Query OK, 0 rows affected (0.02 sec)
MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]>
grant all on *.* to 'root'@'192.168.%.%' identified by 'magedu';
grant all on mogdb.* to 'moguser'@'192.168.%.%' identified by 'mogpass';
flush privileges;

主機192.168.0.45(mogilefs+mogilestored)


# 所需程序包
[root@mysql mogilefs]# ls
MogileFS-Server-2.46-2.el6.noarch.rpm            perl-MogileFS-Client-1.14-1.el6.noarch.rpm
MogileFS-Server-mogilefsd-2.46-2.el6.noarch.rpm  perl-Net-Netmask-1.9015-8.el6.noarch.rpm
MogileFS-Server-mogstored-2.46-2.el6.noarch.rpm  perl-Perlbal-1.78-1.el6.noarch.rpm
MogileFS-Utils-2.19-1.el6.noarch.rpm
[root@mysql mogilefs]# yum install -y *.rpm perl-IO-AIO
# 修改配置文件
[root@mysql mogdata]# vi /etc/mogilefs/mogilefsd.conf # 調度器tracker的配置文件
    # Enable daemon mode to work in background and use syslog  
    daemonize = 1
    # Where to store the pid of the daemon (must be the same in the init script)
    pidfile = /var/run/mogilefsd/mogilefsd.pid
    # Database connection information
    db_dsn = DBI:mysql:mogdb:host=192.168.0.45:3406    # 存儲元數據的數據庫信息,包括數據庫mogdb及連接地址192.168.0.45:3406
    db_user = moguser     # 數據庫用戶名
    db_pass = mogpass     # 數據庫登錄密碼
    # IP:PORT to listen on for mogilefs client requests
    listen = 192.168.0.45:7001
[root@mysql mogdata]# vi /etc/mogilefs/mogstored.conf # 存儲節點mogstored的配置文件
    maxconns = 10000     # 最大連接數
    httplisten = 0.0.0.0:7500 # http請求監聽的地址和端口
    mgmtlisten = 0.0.0.0:7501
    docroot = /var/mogdata # 存儲設備掛載目錄,可修改
# 準備存儲設備
[root@mysql mogdata]# fdisk /dev/sda # 新建分區sda4,大小10G(實際生產環境中,此爲整塊磁盤,而非分區)
[root@mysql mogdata]# kpartx -af /dev/sda
[root@mysql mogdata]# partx -a /dev/sda
[root@mysql mogdata]# cat /proc/partitions # 驗證分區已創建成功
[root@mysql mogdata]# mke2fs -t ext4 /dev/sda4 # 初始化分區
[root@mysql mogdata]# mkdir /var/mogdata
[root@mysql mogdata]# mount -t ext4 /dev/sda4 /var/mogdata/ # 掛載分區
[root@mysql mogdata]# mkdir /var/mogdata/dev1 # 創建存儲設備dev1(注:在192.168.0.46上,此爲dev2)
[root@mysql mogdata]# chown -R mogilefs.mogilefs /var/mogdata/
# 初始化數據庫
[root@mysql mogdata]# mogdbsetup --dbhost=192.168.0.45 --dbport=3406 --dbrootuser=root --dbrootpass=magedu --dbuser=moguser --dbpass=mogpass --dbname=mogdb --yes
# 初始化數據庫執行一次即可,故在主機192.168.0.46上無需執行此步驟
# 啓動服務
[root@mysql mogilefs]# service mogilefsd start
Starting mogilefsd                                         [  OK  ]
[root@mysql mogilefs]# service mogstored start
Starting mogstored                                         [  OK  ]

主機192.168.0.46(mogilefs+mogilestored)

同上,直至mogilefsd和mogstored服務都正常啓動

3.5 配置部署(任意一個tracker節點上配置即可,如192.168.0.45)

添加節點

[root@mysql mogdata]# echo "trackers = 192.168.0.45:7001" > /etc/mogilefs/mogilefs.conf # 管理程序mogadm的配置文件
[root@mysql mogdata]# mogadm host add 192.168.0.45 --ip=192.168.0.45 --status=alive # 添加節點1
[root@mysql mogdata]# mogadm host add 192.168.0.46 --ip=192.168.0.46 --status=alive # 添加節點2
[root@mysql mogilefs]# mogadm host list # 查看已添加節點
192.168.0.45 [1]: alive
  IP:       192.168.0.45:7500
192.168.0.46 [2]: alive
  IP:       192.168.0.46:7500

添加設備

[root@mysql mogdata]# mogadm device add 192.168.0.45 1 # 添加存儲設備1,設備編號需與/var/mogdata目錄下的dev1目錄保持一致
[root@mysql mogdata]# mogadm device add 192.168.0.46 2 # 添加存儲設備2,設備編號需與/var/mogdata目錄下的dev2目錄保持一致
[root@mysql mogdata]# mogadm device list # 查看已添加設備
192.168.0.45 [1]: alive
                    used(G)    free(G)   total(G)  weight(%)
   dev1:   alive      0.146      9.200      9.347        100
192.168.0.46 [2]: alive
                    used(G)    free(G)   total(G)  weight(%)
   dev2:   alive      0.146      9.199      9.346        100

添加domain(域)

[root@mysql mogdata]# mogadm domain add images
[root@mysql mogdata]# mogadm domain add text
[root@mysql mogdata]# mogadm domain list
 domain               class                mindevcount   replpolicy   hashtype
-------------------- -------------------- ------------- ------------ -------
 images               default                   2        MultipleHosts() NONE
 text                 default                   2        MultipleHosts() NONE

添加class(文件類別)

[root@mysql mogdata]# mogadm class add images class1 --mindevcount=2 # 在域images中添加類別class1和class2,最小文件複製份數爲2
[root@mysql mogdata]# mogadm class add images class2 --mindevcount=2
[root@mysql mogdata]# mogadm class add text class1 --mindevcount=2 # 在域text中添加類別class1和class2,最小文件複製份數爲2
[root@mysql mogdata]# mogadm class add text class2 --mindevcount=2
[root@mysql mogdata]# mogadm class list
 domain               class                mindevcount   replpolicy   hashtype
-------------------- -------------------- ------------- ------------ -------
 images               class1                    2        MultipleHosts() NONE
 images               class2                    2        MultipleHosts() NONE
 images               default                   2        MultipleHosts() NONE
 text                 class1                    2        MultipleHosts() NONE
 text                 class2                    2        MultipleHosts() NONE
 text                 default                   2        MultipleHosts() NONE

3.6 配置前端代理Nginx

重新編譯安裝nginx,添加nginx-mogilefs-module-master模塊

[root@nginx1 tar]# cd /home/software/src/nginx-1.4.7/
[root@nginx1 nginx-1.4.7]# ./configure \
>   --prefix=/usr \
>   --sbin-path=/usr/sbin/nginx \
>   --conf-path=/etc/nginx/nginx.conf \
>   --error-log-path=/var/log/nginx/error.log \
>   --http-log-path=/var/log/nginx/access.log \
>   --pid-path=/var/run/nginx/nginx.pid  \
>   --lock-path=/var/lock/nginx.lock \
>   --user=nginx \
>   --group=nginx \
>   --with-http_ssl_module \
>   --with-http_flv_module \
>   --with-http_stub_status_module \
>   --with-http_gzip_static_module \
>   --http-client-body-temp-path=/var/tmp/nginx/client/ \
>   --http-proxy-temp-path=/var/tmp/nginx/proxy/ \
>   --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/ \
>   --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
>   --http-scgi-temp-path=/var/tmp/nginx/scgi \
>   --with-pcre \
>   --with-debug \
>   --add-module=/home/software/tar/nginx-mogilefs-module-master
[root@nginx1 nginx-1.4.7]# make && make install

配置Nginx,將靜態文件和圖片的訪問都轉發至後端MogileFS即可

[root@nginx1 nginx]# cat /etc/nginx/nginx.conf
worker_processes  2;
error_log  /var/log/nginx/nginx.error.log;
pid        /var/run/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    sendfile        on;
    keepalive_timeout  65;
    fastcgi_cache_path /www/cache levels=1:2 keys_zone=fcgicache:10m inactive=5m;
    upstream mogfs_cluster { # 定義後端mogilefs集羣
        server 192.168.0.45:7001;
        server 192.168.0.46:7001;
    }
    server {
        listen       4040;
        server_name  xxrenzhe.lnmmp.com;
        access_log  /var/log/nginx/nginx-img.access.log  main;
        root /www/lnmmp.com;
        valid_referers none blocked xxrenzhe.lnmmp.com *.lnmmp.com;
        if ($invalid_referer) {
            rewrite ^/ http://xxrenzhe.lnmmp.com/404.html
        }
        location ~* ^(/images/.*)$ {    # 圖片訪問直接轉發至後端mogilefs集羣
            mogilefs_tracker mogfs_cluster;
            mogilefs_domain images;    # 指定images域
            mogilefs_noverify on;
            mogilefs_pass $1 {    # 傳輸訪問的全路徑(/images/.*)
                proxy_pass $mogilefs_path;
                proxy_hide_header Content=Type;
                proxy_buffering off;
            }
        }
    }
    server {
        listen       80;
        server_name  xxrenzhe.lnmmp.com;
        access_log  /var/log/nginx/nginx-static.access.log  main;
        location / {
            root   /www/lnmmp.com;
            index  index.php index.html index.htm;
        }
        location ~* ^(/text/.*)$ {    # 文本訪問直接轉發至後端mogilefs集羣
            mogilefs_tracker mogfs_cluster;
            mogilefs_domain text;    # 指定text域
            mogilefs_noverify on;
            mogilefs_pass $1 {    # 傳輸訪問的全路徑(/text/.*)
               proxy_pass $mogilefs_path;
               proxy_hide_header Content=Type;
               proxy_buffering off;
            }
        }
        gzip on;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_types text/plain text/css application/x-javascript text/xml application/xml;
        gzip_disable msie6;
    }
    server {
        listen       8080;
        server_name  xxrenzhe.lnmmp.com;
        access_log  /var/log/nginx/nginx-php.access.log  main;
        location / {
            root   /www/lnmmp.com;
            index  index.php index.html index.htm;
        }
        error_page  404              /404.html;
        error_page  500 502 503 504  /50x.html;
        location = /50x.html {
            root   /www/lnmmp.com;
        }
        location ~ \.php$ {
            root           /www/lnmmp.com;
            fastcgi_pass   127.0.0.1:9000;
          fastcgi_cache  fcgicache;
          fastcgi_cache_valid 200 302 1h;
          fastcgi_cache_valid 301 1d;
          fastcgi_cache_valid any 1m;
          fastcgi_cache_min_uses 1;
          fastcgi_cache_key $request_method://$host$request_uri;
          fastcgi_cache_use_stale error timeout invalid_header http_500;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

啓動nginx服務

[root@nginx1 nginx]# service nginx start
Starting nginx:                                            [  OK  ]

3.7 訪問驗證

上傳文件測試分佈式文件系統MogileFS的功能

[root@mysql mogdata]# mogupload --domain=images --key='/images/fish.jpg' --file="/images/fish.jpg" # 上傳圖片文件,選擇images域
[root@mysql mogdata]# mogupload --domain=text --key='/text/index.html' --file="/text/index.html" # 上傳文本文件,選擇text域
[root@mysql mogdata]# moglistkeys --domain=images # 列出已添加的key
/images/fish.jpg
[root@mysql mogdata]# moglistkeys --domain=text
/text/index.html
[root@mysql mogdata]# mogfileinfo --domain=images --key='/images/fish.jpg' # 查看已添加文件的具體信息,包括實際可訪問地址
- file: /images/fish.jpg
     class:              default
  devcount:                    2
    domain:               images
       fid:                    9
       key:     /images/fish.jpg
    length:                 3225
 - http://192.168.0.45:7500/dev1/0/000/000/0000000009.fid
 - http://192.168.0.46:7500/dev2/0/000/000/0000000009.fid
[root@mysql mogdata]# mogfileinfo --domain=text --key='/text/index.html'
- file: /text/index.html
     class:              default
  devcount:                    2
    domain:                 text
       fid:                    8
       key:     /text/index.html
    length:                   15
 - http://192.168.0.46:7500/dev2/0/000/000/0000000008.fid
 - http://192.168.0.45:7500/dev1/0/000/000/0000000008.fid

wKioL1N5kDKSm8M5AAIFP5jSOZ4098.jpg

wKioL1N5kEfyHb5GAAHQ2SleL4s408.jpg

說明:直接訪問mogilefs提供的文件存儲路徑,訪問正常;

結合Nginx,從前端訪問測試

wKioL1N5kHqRsxb9AAG1O1WVluU610.jpg

wKioL1N5kI-Rfe30AAFcrLcKYOM853.jpg

說明:通過前端Nginx訪問圖片和文本文件一切正常,實現了對前端訪問的透明性;

3.8 後續擴展

結合LNMT的架構,再通過Haproxy進行前端調度,就可以使用MogileFS這個分佈式存儲系統完全替代NFS,實現對圖片文件和文本文件的存儲和讀寫;

鑑於MogileFS的無目錄性,無法直接掛載使用,故向mogilefs集羣中添加文件則需要程序通過API調用上傳(upload)文件,雖然對於運維人員有點不方便,但也保證了一定的高效性;

如果想體驗直接掛載使用分佈式文件系統的樂趣,則可以嘗試使用MooseFS,在此就不多說了!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章