Infinispan的GridFileSystem-内存中的网格文件系统

介绍

InfinispanJBoss Cache缓存框架的后继者,是一个开放源数据网格平台,它利用集群中各个节点之间的状态分布。 GridFileSystem是一个新的实验性API,它将由Infinispan支持的数据网格公开为文件系统。 该API是JDK的FileInputStreamOutputStream类的扩展,特别是GridFileGridInputStreamGridOutputStream 。 框架中还包括一个辅助类GridFilesystem 。 Infinispan版本4.1.0(从4.1.0.ALPHA2开始)提供此API。

GridFilesystem包括2个Infinispan缓存-一个用于元数据(通常是复制的),另一个用于实际数据(通常是分布式的)。 复制前者,以便每个节点都在本地具有元数据信息,并且不需要为诸如列出文件之类的任务进行RPC调用。 后者是分布式缓存,因为这是大量存储空间用完的地方,并且需要可伸缩的机制来存储数据。 文件本身是分块的,每个块都作为高速缓存条目存储。

我们在本文中重点介绍的功能是Infinispan的分布式模式。 此模式基于一致的哈希添加“分布”。 JBossCache框架仅支持“复制”模式(集群中的每个节点都将所有内容复制到其他每个节点)。

复制最好在较小的群集中使用,或者在每个节点上存储的数据相对较小时使用; 由于每个节点都会将其数据复制到群集中的每个其他节点,因此每个节点上存储的平均数据量是群集大小和数据大小的函数,因此可能对于单个节点无法存储在内存中太大。 复制的优点是,读取操作始终是本地的,因为每个人都有数据,并且当新节点加入或现有节点离开群集时,不会进行任何重新平衡。

另一方面,如果您有一个需要快速访问的大型数据集,而又无法承受访问磁盘(例如数据库)来检索数据的需求,则内存网格文件系统是更好的解决方案。

上一篇文章中 ,我们讨论了ReplCache,它是使用一致的基于散列的分布的网格数据容器的实现。 在某些方面,ReplCache用作Infinispan分布式模式的原型。

在Infinispan中,无论有无冗余,数据都可以存储在网格中。 例如,通过使用分布式缓存模式并将numOwners设置为1,数据D只能在网格中存储一次。在这种情况下,Infinispan会基于一致的哈希算法选择一台服务器来存储D。 如果将numOwners设置为2,则Infinispan会选择2台服务器来存储D,依此类推。

Infinispan的优点是它提供了网格的聚合内存。 例如,如果我们有5个主机,每个主机有1GB的堆,那么如果numOwners设置为1,则我们的聚合内存为5GB-当然,这会减少开销。 即使有一些冗余(例如,将numOwners设置为2),我们也可以使用2.5GB。

但是,存在一个问题:如果我们有许多大小为1K的数据元素,而只有少数大小为200MB的数据元素,则分布不均匀。 一些服务器将要耗尽其堆,因为它们正在存储200MB数据元素,而其他服务器可能几乎为空。

另一个问题是,如果数据元素大于给定服务器上的可用堆:例如,如果我们要将元素存储到大小为2GB的网格中,那么我们将失败,因为堆只有1GB并通过Infinispan的Cache.put(K,V)API的值将失败,并显示OutOfMemoryException错误。

为了解决这些问题,我们可以将数据元素划分为多个块,然后将这些块分布在整个集群中。 假设一个块是8K:如果将2GB数据元素划分为8K块,则最终将有250,000个8K大小的块存储在网格中。 与存储几个200MB数据元素相比,在网格中存储250,000个相等大小的块可能会导致分布更均匀。

但是,我们不希望应用程序程序员在写数据时不得不将其数据分成多个块,而在读取数据时又将这些块放回整个数据元素中,从而不会造成负担。 此外,这种方法仍然需要将数据元素存储在内存中,这将无法正常工作。

为了克服这个问题,我们选择了的概念:流(输入或输出)仅处理元素数据的子集。 例如,我们不必遍历一个输入文件(例如,以50K的步长),然后将读取的数据写入网格,而不必将2GB的数据写入网格。 这样,在任何给定时间仅需要将价值50K的数据保留在内存中。

因此,现在应用程序程序员可以编写(伪)代码,将2GB的数据元素存储到网格中,如下面的清单1所示:

清单1:将数据元素存储到网格中的代码。

InputStream in=new FileInputStream(“/home/bela/bond.iso”);
OutputStream out=getGridOutputStream(“/home/bela/bond.iso”);
byte[] buffer=new byte[50000];
int len;
while((len=in.read(buffer, 0, buffer.length)) != -1) {
    out.write(buffer, 0, len);
}
in.close();
out.close();

可以编写类似的代码以从网格中读取数据。

使用流接口的优点是:

  • 只需一个小缓冲区即可读取或写入数据。 这比必须为Infinispan的默认put()或get()创建2GB的byte []缓冲区要好。

  • 网格上的数据分布更加均匀。 具有良好的一致性哈希功能,所有服务器应在本地存储或多或少的相同数量的数据。

  • 我们能够存储比任何给定节点的JVM堆都大的文件。

  • 应用程序程序员不必编写用于对数据进行分块的代码。

建筑

网格文件系统不仅需要存储块,还需要存储元数据信息,例如目录,文件,文件大小,上次修改时间等。

由于元数据非常重要,而且很小,因此我们决定将其存储在网格中的每台服务器上。 因此,我们需要使用复制模式而不是分布式模式(每个节点本地可用的副本)为所有元数据提供一个Infinispan缓存,并为分布式块配置一个Infinispan缓存,并为数据块设置所需的numOwners。

注意,Infinispan不会创建两个JGroups堆栈和通道,而是在元数据和块实例之间共享一个JGroups通道,前提是它们是使用相同的CacheManager创建的。

元数据缓存

元数据缓存包含目录和文件的完整路径名作为键,而元数据(例如文件长度,上次修改日期以及键是文件还是目录)包含为值。

每当创建新目录或文件时,都会删除文件,或者无论何时写入文件,都会更新元数据缓存。 例如,当我们写入文件时,新长度和最后修改时间戳将在元数据缓存中更新。

元数据缓存还用于导航,例如列出目录“ / home / bela / grid”中的所有文件和目录。 由于对元数据缓存的更改会复制到每个服务器,因此读取始终是本地的,不需要网络通信。

块缓存

块高速缓存存储各个块。 键是块名称,值是byte []缓冲区。 通过在文件的完整路径名后附加“。#<chunk number>”来构造块名称,例如“ /home/bela/bond.iso.#125”。

在块大小为4000的情况下,写入14K的文件“ /home/bela/tmp.txt”将生成块

  1. /home/bela/tmp.txt.#0(4000字节)[0-3999]

  2. /home/bela/tmp.txt.#1(4000字节)[4000-7999]

  3. /home/bela/tmp.txt.#2(4000字节)[8000-11999]

  4. /home/bela/tmp.txt.#3(2000字节)[12000-13999]

正确块的计算是当前读或写指针和块大小的函数。 例如,在位置7900读取1000字节将从块#1读取99字节,从块#2读取901字节。

块名称(“ /home/bela/tmp.txt.#2”)用于选择服务器,以使用一致的哈希将块写入或从中读取。

API

GridFileSystem框架通过4个类实现:

该系统的入口点是GridFilesystem:用于创建GridFile,GridOutputStream和GridInputStream的实例。 清单2显示了该类的主要方法。

清单2:GridFileSystem类的主要方法

public GridFilesystem(Cache<String, byte[]> data, Cache<String, 
                      GridFile.Metadata> metadata, int default_chunk_size) {
    ...
}

public File getFile(String pathname) {
    ...
}

public OutputStream getOutput(String pathname) throws IOException {
    ...
}

public InputStream getInput(String pathname) throws FileNotFoundException {
    ...
}

构造函数采用两个(完全创建并正在运行)的Infinispan缓存,第一个用于数据块,第二个用于元数据。 default_chunk_size参数为默认块大小设置默认值。 下面的清单3显示了有关如何创建GridFilesystem对象的代码。

清单3:创建GridFileSystem对象的代码

Cache<String,byte[]> data;
Cache<String,GridFile.Metadata> metadata;
GridFilesystem fs;

data = cacheManager.getCache(“distributed”);
metadata = cacheManager.getCache(“replicated”);
data.start();
metadata.start();

fs = new GridFilesystem(data, metadata, 8000);

方法getFile()可用于获取文件的句柄,该句柄可用于列出文件,创建新文件或创建目录。 getFile()方法返回GridFile的实例,该实例扩展了java.io.File,该实例覆盖了File类的大多数(但不是全部)方法。 清单4显示了使用getFile()方法的代码片段。

清单4. GridFileSystem getFile()方法示例

// create directories
File file=fs.getFile(“/home/bela/grid/config”);
fs.mkdirs(); // creates directories /home/bela/grid/config

// List all files and directories under “/usr/local”
file=fs.getFile(“/usr/local”);
File[] files=file.listFiles();

// Create a new file 
file=fs.getFile(“/home/bela/grid/tmp.txt”);
file.createNewFile();

方法getOutput()返回GridOutputStream的实例,可用于将数据写入网格。 清单5中的以下代码显示了如何将文件从本地文件系统复制到网格(省略了错误处理):

清单5:GridFileSystem getOutput()方法示例。

InputStream in=new FileInputStream(“/home/bela/bond.iso”);
OutputStream out=fs.getOutput(“/home/bela/bond.iso”); // same name in the grid
byte[] buffer=new byte[20000];
int len;
while((len=in.read(buffer, 0, buffer.length)) != -1) {
    out.write(buffer, 0, len);
}
in.close();
out.close();

方法getInput()创建GridInputStream的实例,该实例可用于从网格读取数据。 下面的清单6显示了getInput()方法调用的示例。

清单6:GridFileSystem getInput()方法示例。

InputStream in=in.getInput(“/home/bela/bond.iso”);
OutputStream out=new FileOutputStream(“/home/bela/bond.iso”); // local name same as grid
byte[] buffer=new byte[20000];
int len;
while((len=in.read(buffer, 0, buffer.length)) != -1) {
    out.write(buffer, 0, len);
}
in.close();
out.close();

使用WebDav公开网格文件系统

从4.1.0.ALPHA2版本开始,Infinispan附带了GridFileSystem WebDAV演示。 该演示可从网站的下载页面获得,它是根据最新Infinispan发行版中的独立WAR文件进行编译的。 将WAR文件部署到您喜欢的servlet容器中,然后您就可以使用WebDAV协议在http:// YOUR_HOST / infinispan-gridfs-webdav /上挂载文件系统。

还有另一个演示 ,其中运行infinispan-gridfs-webdav演示Web应用程序启动了两个JBoss AS实例,并将WebDAV实例安装为远程驱动器。 文件被复制到它们,并且高可用性被证明为关闭了一个实例,同时仍从第二个实例读取文件。

监控方式

Grid File System提供的监视支持包括通过基础Infinispan框架提供的JMX和/或JOPR / JON

JMX

可以在两个不同级别启用JMX报告:CacheManager和Cache。 CacheManager控制从其创建的所有缓存实例。 缓存级别管理包括由各个缓存实例生成的信息。

乔普

管理多个Infinispan实例的另一种方式是使用JOPR,它是JBoss的企业管理解决方案。 JOPR的代理和自动发现功能有助于监视Cache Manager和Cache实例。 借助JOPR,管理员可以访问关键运行时参数或统计信息的图形视图,并且如果这些参数超过或低于某些限制,还可以得到通知。

结论

本文讨论了如何使用GridFS通过新的流式API(使用Infinispan)在网格中存储大量数据。 增值功能是对数据进行分块并将其存储在网格中的能力,并具有不同程度的冗余度,从而可以完全在内存中处理非常大的数据集。

网格文件系统是一个原型,尚未实现所有的java.io. *功能,但当前包含最重要的方法。 有关更多信息,请参考此API上的Infinispan 文档

参考资料

GridFileSystem: http : //community.jboss.org/wiki/GridFileSystem

ReplCache: http ://www.jgroups.org/javagroupsnew/docs/replcache.html

Infinspan: http//www.infinispan.org

启用分布式模式: http : //docs.jboss.org/infinispan/4.0/apidocs/config.html#ce_default_clustering

关于作者

Bela Ban在瑞士苏黎世大学获得博士学位。 在IBM Research工作一段时间后,他在Cornell担任了博士后。 然后,他在加利福尼亚州圣何塞的富士通网络通信公司从事NMS / EMS的工作。 2003年,他加入JBoss,全职从事开源工作。 Bela在JBoss管理集群团队,并创建并领导JGroups项目。 Bela的兴趣包括网络协议,性能,群组通信,越野跑,骑自行车和比喻。 在不修改代码时,他与家人在一起。

Manik Surtani是Infinispan缓存框架的项目负责人。

翻译自: https://www.infoq.com/articles/infinispan-gridfs/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值