#总览
Quantcast File System (QFS) 是高性能,且具有故障容错能力的分布式文件系统。它可以支持MapReduce处理,以及其他应用程序的大文件的I/O操作。本文将会介绍QFS,它的相关配置等等。更详细的介绍,请参见QFS官方wiki
如果你有什么未解决的问题,可发送邮件到
[email protected] 或者搜索论坛
QFS Developer Mailing List. 你也可以通过JIRA issue tracker来问问题,报告bugs以及关于QFS功能更新的请求.
更进一步查看QFS内部如何工作的,请参见论文
QFS paper presented at VLDB.
#简介
Hadoop和其他的批处理框架在具有顺序读顺序写(例如MB或者GB级别)的访问模式的文件系统下具有较高的性能。 Quantcast File System (QFS)正是基于这种需求出发开发的分布式文件系统。 它在KFS的基础上演化而来的。 在2011年,QFS开发团队不再使用HDFS作为后端存储,转向使用QFS。 同时,他们将源代码开源在https://github.com/quantcast/qfs
QFS基于C++实现,使用TCP sockets, STL以及boost库。 它已经被部署到运行centos5或6的x86-64架构的生产环境中。 客户端库也已经在CentOS 5 and 6, OSX 10.X, Cygwin, and Debian/Ubuntu进行了测试。
##QFS特性
###两个问题:
#编译
1,在https://github.com/quantcast/qfs下载zip压缩包源代码,自动命名为qfs-master.zip
2,解压缩源代码,unzip qfs-master.zip
3,进入qfs-master目录,打开README.md
4,从链接地址https://github.com/quantcast/qfs/wiki/Developer-Documentation进行编译
##具体编译过程:
1,在源代码最顶层目录make命令
2,等待直到编译成功
用户应用程序与qfs client的lib连接,然后client lib连接metaserver或者chunk server进行文件操作
编译模式设定
1,默认debug模式编译,可选用release模式
BUILD_TYPE=release make
生成的内容在build/release/bin目录中
2,启用verbose输出
VERBOSE=true make
3,编译test
make test
这会在本地创建metaserver和chunkserver,并进行一系列测试,这可能会耗费几分钟时间。
4,编写测试程序
#include
#include "tests/integtest.h"
class FooTest : public QFSTest {
public:
virtual void SetUp() { ... }
virtual void TearDown() { ... }
};
TEST_F(FooTest, TestBar) {
...
}
5,编写c++客户端
例子代码在 examples/cc/qfssample_main.cc file.
QFS客户端接口在 src/cc/libclient/KfsClient.h.
客户端链接的库有 libqfs_client library 和其他的 libqfs_ dependencies
6,编写java客户端
java通过jni调用相应接口
例子代码在 examples/java/QfsSample.java.
java客户端相关接口在 src/java/qfs-access/src/main/java/com/quantcast/qfs/access/KfsAccess.java.
java额外的jar包路径: build/java/qfs-access/qfs-access-.jar in the CLASSPATH. 执行客户端需要 build/release/lib should be in the LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH, if it is Mac OS X). To build,
$ cd ~/code/qfs/examples/java
$ qfsjar=`echo ../../build/qfs-access/qfs-access*.jar`
$ javac -classpath "$qfsjar" QfsSample.java
To execute,
$ libdir="`cd ../../build/release/lib && pwd`"
$ export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${libdir}"
$ qfsjar=`echo ../../build/qfs-access/qfs-access*.jar`
$ java -Djava.library.path="$libdir" -classpath ".:$qfsjar" QfsSample 127.0.0.1 20000
编写python(实验阶段)
使用命令 make python. 将会生成 build/build//qfs.so
python客户端使用qfs.so, 例子代码 examples/python/qfssample.py
Set PYTHONPATH accordingly if you are using a qfs.so install path different from the default path, so that the python run-time can detect the qfs.so. Also, ensure that LD_LIBRARY_PATH has the path to the QFS libraries. For example,
$ export PYTHONPATH=/usr/lib/python2.7/dist-packages:$PYTHONPATH
$ export LD_LIBRARY_PATH=/usr/lib/python2.7/dist-packages/qfs:$LD_LIBRARY_PATH
$ python examples/python/qfssample.py
##测试编译qfs
1,启动简单的server
./examples/sampleservers/sample_setup.py -a install
提示在build目录找不到MetaServer,查看python代码,发现其搜索目录为build/release/bin
2,进行release编译
BUILD_TYPE=release make
3,再次启动server
Meta server started, listening on localhost:20000
netstat -tlnp |grep 20000
tcp 0 0 0.0.0.0:20000 0.0.0.0:* LISTEN 2587/metaserver
#部署说明
QFS着眼于在廉价设备上部署,其支持两种类型的容错:块副本和RS编码。 本文档说明了简单部署以及大规模部署。
注意:在文件创建的时候,必须给定副本或者编码类型,QFS不支持默认类型。
##组件
QFS支持三种组件
###MetaServer
部署metaserver的机器需要支持故障容错的磁盘阵列以支持它的transaction logs和checkpoints。
###Chunk server
存储具体数据,I/O密集型,网络密集型。
##简单cluster
###使用块副本
下面的例子演示了使用3个数据节点配置副本数为3的cluster.
注意: 这个配置不妨碍使用RS编码,因为客户可以针对每一个文件设置不同的容错能力
####配置
MetaServer.prp
# port used by clients to connect to the metaserver
metaServer.clientPort = 20000
# port used by chunk servers to connect to the metaserver
metaServer.chunkServerPort = 30000
# chunk placement groups by IP address or first three octets
metaServer.rackPrefixes = 192.168.1.1 1 192.168.1.2 2 192.168.1.3 3
# create new file system if no transaction logs or checkpoints are found
metaServer.createEmptyFs = 1
# location to write transaction logs
metaServer.logDir = /home/qfsm/transaction_logs
# location to write checkpoints, this needs be pruned periodically
metaServer.cpDir = /home/qfsm/checkpoint
# unique cluster id
metaServer.clusterKey = my-fs-unique-identifier
ChunkServer.prp
# address of the metaserver, host names should not be used
chunkServer.metaServer.hostname 192.168.0.1
# metaserver port for chunk server to use
chunkServer.metaServer.port = 30000
# chunk server client listener port
chunkServer.clientPort = 22000
# locations to store chunk data, independent spindles should be
used
chunkServer.chunkDir = /mnt/data0 /mnt/data1
# unique cluster id
chunkServer.clusterKey = my-fs-unique-identifier
注意:
###使用Reed-Solomon编码
RS编码比副本要求更少的空间来容忍故障。客户端库产生相应的校验信息以用来重构chunk,并将校验信息散步到多个server中,而不是像副本方式那样写入一个chunk的多个副本。这种空间的高效是以增加的恢复带宽或者更长的chunk重构时间为代价的: 因为丢失chunk并没有额外的副本使用,它必须利用编码条纹下其他的数据块来重构,带来较大的时间和带宽代销。
注意: 纠删码的配置并不阻止chunk副本的使用,因为客户端可以在文件创建时候针对单个文件设置不同的容错能力。
Reed-Solomon
值 | 描述 |
---|---|
k | 副本因子, 通常其为 1 且 n=3, 当大于 1 时 n == 0 |
m | 条纹内数据块数目, 数据范围 1 到 64 且 n == 3, 当其为 255 时 n == 0 |
n | 条纹内校验块数目, 当前只有 0 和 3 是合法的, 且 n == 0 时只有数据块 |
当前只有
Replication vs Reed-Solomon
编码 | 文件大小 | 空间使用 | 容错能力 |
---|---|---|---|
replication 3 |
6 MB | 18 MB | up to 2 chunks |
replication 4 |
6 MB | 24 MB | up to 3 chunks |
6 MB | 9 MB | up to 3 chunks |
有用的公式:
disk usage = file size x ((data stripes + recovery stripes) / data stripes) x replication)
effective capacity = raw capacity x (data stripes / ((data stripes + recovery stripes) x replication))
####布局
它需要最少9个chunk servers才可达到理想的chunk放置。 这是因为
有9个块(6个数据块,3个校验块)。 如副本中配置的那样,将条纹内的数据块放入不同的节点组中,可达到3个节点的故障容错能力。
对于
的编码,需要至少N+3个chunk servers以处理3个同时的chunk server故障。基于上述假设(chunk server的数目至少N+3),再均衡策略并不会尝试将每个chunk server下的chunk数目保持一致。
例如如下场景:
起始只有一个chunk server。当客户的写入一个具有6个数据块的大文件且使用RS(6+3)进行编码,这会在这个chunk server中存储9个块。然后又有5个chunk servers加入到系统中,再均衡放置策略会将第一个server中的5个chunks移动到这5个servers中,而在第一个server节点中留下4个chunk。 如果第一个节点挂掉,会发生数据丢失(6+3最多支持3容错)。
这意味着,如果你系统中只有6个chunk servers且使用6+3的RS编码,即使一个机器故障也可能导致数据丢失。
#####MetaServer.prp
# port used by clients to connect to the metaserver
metaServer.clientPort 20000
# port used by chunk servers to connect to metaserver
metaServer.chunkServerPort = 30000
# chunk placement groups by IP address or first three octets
metaServer.rackPrefixes = 192.168.1.1 1 192.168.1.2 2 192.168.1.3 3 192.168.1.4 4 192.168.1.5 5 192.168.1.6 6 192.168.1.7 7 192.168.1.8 8 192.168.1.9 9
# create new file system if no transaction logs or checkpoints are found
metaServer.createEmptyFs = 1
# location to write transaction logs
metaServer.logDir = /home/qfsm/transaction_logs
# location to write checkpoints, this needs be pruned periodically
metaServer.cpDir = /home/qfsm/checkpoint
# unique cluster id
metaServer.clusterKey = my-fs-unique-identifier
#####ChunkServer.prp
# IP address of the metaserver, host names should not be used
chunkServer.metaServer.hostname 192.168.0.1
# metaserver port for chunk server to use
chunkServer.metaServer.port = 30000
# chunk server client listener port
chunkServer.clientPort = 22000
# locations to store chunk data, independent spindles should be used
chunkServer.chunkDir = /mnt/data0 /mnt/data1
# unique cluster id
chunkServer.clusterKey = my-fs-unique-identifier
注意:
clusterKey
参数必须在整个系统的metaserver和所有的chunk server中保持一致。这允许一个机器节点有多个QFS文件系统下的chunk servers,只要每个系统具有自己的metaserver和clusterKey
.##RS编码高级配置
这里我们讨论一个大规模QFS的机架部署,每一个机架有22个chunk server节点。
还有一个head node来放置metaserver
###布局
机架是常见的故障域,任何时刻都可能发生网络或者电源故障。因此,机架成为最理想的chunk放置域。如前面讨论的,
需要9个机架: 一个机架存储条纹内的一个块.
考虑采用RS编码的话,此集群有大约4324.32 TB 或者 4.22 PB的存储空间。
不像前面的RS编码块放置的例子,此集群以机架而不是节点为域放置块。这种配置可以容忍至多同时3个机架故障。然后,我们需要注意,磁盘经常会发生故障,因此总体来看,此系统可容忍1到2个机架的故障。
###配置
####MetaServer.prp
# port used by clients to connect to the metaserver
metaServer.clientPort 20000
# port used by chunk servers to connect to the metaserver
metaServer.chunkServerPort = 30000
# chunk placement groups by IP address or first three octets
metaServer.rackPrefixes = 192.168.1 1 192.168.2 2 192.168.3 3 192.168.4 4 192.168.5 5 192.168.6 6 192.168.7 7 192.168.8 8 192.168.9 9
# create new file system if no transaction logs or checkpoints are found
metaServer.createEmptyFs = 1
# location to write transaction logs
metaServer.logDir = /home/qfsm/transaction_logs
# location to write checkpoints, this needs be pruned periodically
metaServer.cpDir = /home/qfsm/checkpoint
# unique cluster id
metaServer.clusterKey = my-fs-unique-identifier
注意:上面的metaServer.rackPrefixes
放置域是基于机架的,而不是基于节点的。192.168.1 1是第一个放置域,此域管理192.168.1.*的节点。
####ChunkServer.prp
# address of the metaserver, host names should not be used
chunkServer.metaServer.hostname 192.168.0.1
# metaserver port for chunk server to use
chunkServer.metaServer.port = 30000
# chunk server client listener port
chunkServer.clientPort = 22000
# locations to store chunk data, independent spindles should be used
chunkServer.chunkDir = /mnt/data0 /mnt/data1
# unique cluster id
chunkServer.clusterKey = my-fs-unique-identifier
##FUSE
你可直接使用qfs_fuse
命令或者/etc/fstab来使用fuse。类似于将网络文件系统即QFS挂载到本地。
$ sudo ./qfs_fuse :20000 /mnt/qfs -o allow_other,ro
$ sudo umount /mnt/qfs
qfs_fuse
的符号链接: $ ln -s /sbin/mount.qfs
:20000 /mnt/qfs qfs ro,allow_other 0 0
FUSE是开源的,需要遵循开源协议。
##优秀实践
#简单cluster的配置实现
##前提条件
单机器,centos6.5系统,64位。
代码已经全部编译OK,当前使用build/debug/bin目录下的相关命令
##目标
在此单机器下配置1个metaserver,3个chunkserver,基于副本方式,能进行上传,下载文件等操作。
##MetaServer配置
MetaServer配置文件名叫MetaServer.prp,可对conf/MetaServer.prp
文件进行相应修改即可。
MetaServer配置文件如下:
metaServer.clientPort = 20000
metaServer.chunkServerPort = 30000
metaServer.logDir = meta/transaction_logs
metaServer.cpDir = meta/checkpoint
metaServer.createEmptyFs = 1
metaServer.rootDirUser = 542
metaServer.rootDirGroup = 543
metaServer.rootDirMode = 0755
metaServer.defaultLoadUser = 542
metaServer.defaultLoadGroup = 543
metaServer.defaultLoadFileMode = 0644
metaServer.defaultLoadDirMode = 0755
metaServer.recoveryInterval = 30
metaServer.clusterKey = my-fs-unique-identifier
metaServer.msgLogWriter.logLevel = DEBUG
chunkServer.msgLogWriter.logLevel = DEBUG
注意:需要首先创建meta/transaction_logs和meta/checkpoint目录
##ChunkServer配置
ChunkServer配置文件名叫ChunkServer.prp,可对conf/ChunkServer.prp
文件进行相应修改即可。
ChunkServer配置文件如下:
chunkServer.metaServer.hostname = localhost
chunkServer.metaServer.port = 30000
chunkServer.clientPort = 22000
chunkServer.chunkDir = meta/chunks
chunkServer.clusterKey = my-fs-unique-identifier
chunkServer.stdout = /dev/null
chunkServer.stderr = /dev/null
chunkServer.ioBufferPool.partitionBufferCount = 131072
chunkServer.msgLogWriter.logLevel = INFO
注意:需要首先创建meta/chunks目录
###另外两个ChunkServer的配置
复制ChunkServer.prp到ChunkServer1.prp, ChunkServer2.prp,修改chunkServer.clientPort和chunkServer.chunkDir
ChunkServer1.prp配置文件如下:
chunkServer.metaServer.hostname = localhost
chunkServer.metaServer.port = 30000
chunkServer.clientPort = 22001
chunkServer.chunkDir = meta/chunks1
chunkServer.clusterKey = my-fs-unique-identifier
chunkServer.stdout = /dev/null
chunkServer.stderr = /dev/null
chunkServer.ioBufferPool.partitionBufferCount = 131072
chunkServer.msgLogWriter.logLevel = INFO
注意: 端口号与目录与ChunkServer.prp不一致
##运行
###启动metaserver
启动命令:
首先cd
到qfs的根目录
build/debug/bin/metaserver conf/MetaServer.prp
运行成功后,此命令不会自动退出,会不断打印如下信息:
......
05-20-2016 20:26:33.989 INFO - (metaserver_main.cc:548) start servicing
05-20-2016 20:26:34.991 INFO - (NetDispatch.cc:667) ===request=counters: 1463747194991100 5999
......
05-20-2016 20:26:34.991 INFO - (LayoutManager.cc:9391) Initiating a replication check of all chunks
###启动chunkserver
启动命令:
首先cd
到qfs的根目录,然后分别启动3个控制终端,启动3个ChunkServer
build/debug/bin/chunkserver conf/ChunkServer.prp
build/debug/bin/chunkserver conf/ChunkServer1.prp
build/debug/bin/chunkserver conf/ChunkServer2.prp
##相关命令测试
###qfsfsck测试
qfsfsck命令位于build/debug/bin/qfsfsck
使用命令: qfsfsck -m localhost -p 20000
注意:20000端口在MetaServer.prp中metaServer.clientPort
配置
输出如下:
Lost files total: 0
Directories: 2
Directories reachable: 2 100%
Directory reachable max depth: 1
Files: 0
......
###qfsshell测试
在qfs主目录下创建bin目录,将位于build/debug/bin/tools目录下的命令全都copy到此bin目录,便于测试运行。
[xxx@air qfs-master]$ bin/qfsshell -s localhost -p 20000
QfsShell>
QfsShell> help
append
cd
......
rm
rmdir
stat
QfsShell> ls
dumpster
另外一种方式,不使用交互模式执行命令
[xxx@air qfs-master]$ bin/qfsshell -s localhost -p 20000 -q ls
dumpster
###上传文件
上传文件命令如下:
build/debug/bin/tools/cptoqfs -s localhost -p 20000 -d CMakeLists.txt -k f1
此命令将当前目录下的CMakeLists.txt上传到服务器并保存为名字f1.
使用qfsshell的ls命令查看是否上传成功:
[lipeng@air qfs-master]$ bin/qfsshell -s localhost -p 20000 -q ls
dumpster
f1
可以看到f1文件已经上传成功。
使用qfscat命令查看文件内容:
build/debug/bin/tools/qfscat -s localhost -p 20000 f1
###下载文件
下载文件命令如下:
build/debug/bin/tools/cpfromqfs -s localhost -p 20000 -k f1 -d tmp.txt
此命令将服务器上的存在的文件名为f1的文件下载到本地目录,并命名为tmp.txt
确定是否和上传的文件CMakeLists.txt内容一致,使用文本比较命令:
[xxx@air qfs-master]$ diff -s tmp.txt CMakeLists.txt
Files tmp.txt and CMakeLists.txt are identical(这说明两个文件完全相同)
###查看f1文件详情
[lipeng@air qfs-master]$ bin/qfsshell -s localhost -p 20000 -q stat f1
File: f1
......
Replication: 3
Chunks: 1
......
文件f1的副本因子为3,数据块数目为1
###命令列表
[xxx@air qfs-master]$ ls build/debug/bin
chunkscrubber chunkserver devtools emulator examples filelister logcompactor metaserver qfsfsck qfs_fuse tests tools
[xxx@air qfs-master]$ ls build/debug/bin/tools
cpfromqfs cptoqfs qfs qfsadmin qfscat qfsdataverify qfsfileenum qfshibernate qfsping qfsput qfsshell qfsstats qfstoggleworm
上面是常用的命令所在的目录以及命令名字。我采用的方式是猜测根据命令名字猜测命令的行为,然后使用命令自带的帮助,查看如何使用此命令。
####如何使用命令
根据命令的名字猜测命令的功能,例如qfsadmin命令。
根据qfsadmin猜测命令是用来进行qfs管理的。
[xxx@air qfs-master]$ build/debug/bin/tools/qfsadmin -s localhost -p 20000
Usage: build/debug/bin/tools/qfsadmin
-m|-s
-p
[-f ]
[-a -- show response headers]
[-v -- verbose]
[-F =]
-- ...
......
根据命令的输出结果,得出qfsadmin支持的命令参数,例如需要查看chunkserver的状态,可使用如下命令:
[xxx@air qfs-master]$ build/debug/bin/tools/qfsadmin -s localhost -p 20000 upservers
127.0.0.1 22000
127.0.0.1 22001
127.0.0.1 22002
##阅读代码
Ctrl+Shift+R
命令即可快速定位文件Ctrl+H
即可进行全局搜索关键字
##问题
创建目录失败,权限不够
[xxx@air qfs-master]$ bin/qfsshell -s localhost -p 20000 -q mkdir d1
d1: mkdirs failure: Permission denied 13
解答:经过一天的跟踪代码,知晓了确切的执行流程,修改MetaServer.prp配置文件,配置相应的用户即可,我的配置如下:
# Root directory permissions -- used only when the new file system created.
metaServer.rootDirUser = 542
metaServer.rootDirGroup = 543
metaServer.rootDirMode = 0755
# Defaults for checkpoint and transaction log without permissions conversion on
# startup.
metaServer.defaultLoadUser = 542
metaServer.defaultLoadGroup = 543
metaServer.defaultLoadFileMode = 0644
metaServer.defaultLoadDirMode = 0755
#542和543是当前使用qfsshell命令的账户名的id,可在/etc/passwd文件中使用用户名找到。
创建文件命令执行失败,服务器显示meta server in recovery mode
build/debug/bin/tools/cptoqfs -s localhost -p 20000 -d README.md -k d1
服务器日志提示meta server in recovery mode同时使用qfsshell也没有发现文件的创建
解答:全局搜索recovery mode关键字(查看阅读代码),最终在LayoutManager::IsAllocationAllowed(MetaAllocate* req)
找到了recovery mode。
inline bool
LayoutManager::InRecoveryPeriod() const
{
return (TimeNow() < mRecoveryStartTime + mRecoveryIntervalSec);
}
inline bool
LayoutManager::InRecovery() const
{
return (
mChunkServers.size() < mMinChunkserversToExitRecovery ||
InRecoveryPeriod()
);
}
猜测应该是机器数目不足,当前我只在一台centos机器上部署了qfs,打印日志查看mChunkServers.size() == 0。
再次查看配置文件conf/MetaServer.prp关于chunkserver的配置,里面具有配置项目chunkServer.clientPort = 22000,然而通过netstat -tlnp查看却没有发现此端口,这表明chunkserver根本就没有启动。通过手动启动ChunkServer,命令chunkserver conf/ChunkServer.prp即可。具体配置过程请参见简单cluster的配置实现
如何一次将所有的Server全部启动?
过去我一直在HDFS上修改源代码,HDFS有start-all.sh可以一次启动所有NameNode,DataNode节点,而不需要一个个的启动。故而我猜测QFS应该也支持这样的命令,暂时还没有找到。
如何设置机器以server启动,不需要进行交互式shell
先搞定问题3,再考虑这个。只需要查看日志即可,不需要交互。
##Checkpoint and Transaction Log Pruning
#未完待续
##声明
本人lpstudy,转载请注明出处:http://blog.csdn.net/lpstudy/article/details/51457250