Ceph很多公司内部已经进行了部署,当然也有很多公司使用阿里的OSS或者亚马逊的S3。在现在硬件廉价的大环境下,更多的公司愿意把自己的数据内容自我保管,实现企业私有云。下面我们来看一下如何使用Java技术栈来访问Ceph。
1. 部署LIBRADOS环境
客户端应用程序需要librados才能连接到Ceph存储集群。
1.1 安装jna.jar
Debian/Ubuntu环境下执行以下命令
sudo apt-get install libjna-java
CentOS/RHEL环境下执行以下命令
sudo yum install jna
JAR文件位于/usr/share/java.
1.2 克隆rados-java代码库
git clone --recursive https://github.com/ceph/rados-java.git
1.3 编译rados-java代码:
cd rados-java
ant
JAR文件位于rados-java/target目录下
1.4 关联路径
复制该JAR文件到公共目录 (例如 /usr/share/java) ,并且确认该文件和JNA JAR在你的JVM’s classpath目录中. 举个例子,你可以按照以下的方法来关联路径:
sudo cp target/rados-0.1.3.jar /usr/share/java/rados-0.1.3.jar
sudo ln -s /usr/share/java/jna-3.2.7.jar /usr/lib/jvm/default-java/jre/lib/ext/jna-3.2.7.jar
sudo ln -s /usr/share/java/rados-0.1.3.jar /usr/lib/jvm/default-java/jre/lib/ext/rados-0.1.3.jar
编译文档可执行以下的命令:
ant docs
2. 配置群集句柄
一个Ceph的客户端通过librados,直接与交互的OSD来存储和检索数据。要与OSD交互,客户端应用程序必须调用 librados 并连接到Ceph Monitor。连接后,librados从Ceph Monitor中检索 Cluster Map。当客户端应用程序想要读取或写入数据时,它会创建I/O上下文并绑定到池。该池具有关联的规则集,该规则集定义了如何将数据放入存储群集中。通过I/O上下文,客户端向librados提供对象名称,它获取对象名称和集群映射(即集群的拓扑)并计算用于定位数据的放置组和OSD。然后客户端应用程序可以读取或写入数据。客户端应用程序无需直接了解群集的拓扑。
Ceph存储集群句柄封装了客户端配置,包括:
- 使用用户ID的rados_create() 或使用用户名称的rados_create2() (推荐使用此方法).
- cephx认证密钥
- 监视器ID和IP地址
- 记录级别
- 调试级别
因此,从您的应用程序使用群集的第一步是:1)创建应用程序将用于连接到存储群集的群集句柄,然后2)使用该句柄进行连接。要连接到群集,应用程序必须提供监视器地址,用户名和身份验证密钥(默认情况下启用cephx)。
注意 与不同的Ceph存储集群 - 或与不同用户的同一集群 - 交互需要不同的集群句柄。
RADOS提供了多种设置所需值的方法。对于监视器和加密密钥设置,一种处理它们的简单方法是确保您的Ceph配置文件包含密钥环文件的密钥环路径和至少一个监视器地址(例如,mon 主机)。例如:
[global]
mon host = 192.168.1.1
keyring = /etc/ceph/ceph.client.admin.keyring
创建句柄后,可以读取Ceph配置文件以配置句柄。还可以将参数传递给您的应用程序,并使用函数解析它们以解析命令行参数(例如,rados_conf_parse_argv()),或解析Ceph环境变量(例如,rados_conf_parse_env())。某些包装器无法实现便捷方法,因此需要实现这些功能。下图提供了初始连接的高级流程。
连接后,应用程序可以仅使用群集句柄调用影响整个群集的功能。例如,一旦有了集群句柄,您就可以:
- 获取群集统计信息
- 使用池操作(存在,创建,列表,删除)
- 获取并设置配置
Ceph的一个强大功能是能够绑定到不同的池。每个池可能具有不同数量的放置组,对象副本和复制策略。例如,可以将池设置为“热”池,其将SSD用于常用对象或使用擦除编码的“冷”池。
Java要求你指定用户ID(admin)或用户名(client.admin),并使用默认的ceph cluster name。Java绑定将基于C ++的错误转换为异常。
import com.ceph.rados.Rados;
import com.ceph.rados.RadosException;
import java.io.File;
public class CephClient {
public static void main (String args[]){
try {
Rados cluster = new Rados("admin");
System.out.println("Created cluster handle.");
File f = new File("/etc/ceph/ceph.conf");
cluster.confReadFile(f);
System.out.println("Read the configuration file.");
cluster.connect();
System.out.println("Connected to the cluster.");
} catch (RadosException e) {
System.out.println(e.getMessage() + ": " + e.getReturnValue());
}
}
}
编译源代码; 然后,运行。如果你已经把连接Ceph的JAR文件复制到/usr/share/java并软连接到扩展路径, 就无需设置classpath. 如下运行:
javac CephClient.java
java CephClient
3. 创建I/O上下文
一旦应用程序具有集群句柄和与Ceph存储集群的连接,就可以创建I/O上下文并开始读取和写入数据。I/O上下文将连接绑定到特定池。用户必须具有适当的 CAPS权限才能访问指定的池。例如,具有读访问权但不具有写访问权的用户将只能读取数据。I/O上下文功能包括:
- 写/读数据和扩展属性
- 列出并迭代对象和扩展属性
- 快照池,列表快照等
RADOS使应用程序可以同步和异步交互。一旦应用程序具有I/O上下文,读/写操作只需要知道object / xattr名称。封装在librados中的CRUSH算法使用群集映射来识别适当的OSD。OSD守护程序处理复制,如Smart Daemons启用超大规模中所述。所述librados库也映射对象来展示位置组,如在 计算PG的ID。
以下示例使用默认数据池。但是,也可以使用API列出池,确保它们存在,或者创建和删除池。对于写操作,这些示例说明了如何使用同步模式。对于读取操作,这些示例说明了如何使用异步模式。
注意 使用此API删除池时请小心。如果删除池,池中的池和所有数据将丢失。
3.1 写入数据代码
import com.ceph.rados.Rados;
import com.ceph.rados.RadosException;
import java.io.File;
import com.ceph.rados.IoCTX;
public class CephClient {
public static void main (String args[]){
try {
Rados cluster = new Rados("admin");
System.out.println("Created cluster handle.");
//利用配置文件连接ceph
File f = new File("/etc/ceph/ceph.conf");
cluster.confReadFile(f);
System.out.println("Read the configuration file.");
cluster.connect();
System.out.println("Connected to the cluster.");
IoCTX io = cluster.ioCtxCreate("data");
String oidone = "hw";
String contentone = "Hello World!";
io.write(oidone, contentone);
String oidtwo = "bm";
String contenttwo = "Bonjour tout le monde!";
io.write(oidtwo, contenttwo);
String[] objects = io.listObjects();
for (String object: objects)
System.out.println(object);
io.remove(oidone);
io.remove(oidtwo);
cluster.ioCtxDestroy(io);
} catch (RadosException e) {
System.out.println(e.getMessage() + ": " + e.getReturnValue());
}
}
}
3.2 一些基本操作
package com.ceph.rbd;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import com.ceph.rados.IoCTX;
import com.ceph.rados.Rados;
import com.ceph.rados.exceptions.RadosException;
import com.ceph.rbd.jna.RbdImageInfo;
import com.ceph.rbd.jna.RbdSnapInfo;
public class RbdDao {
private static Rados rados;
private static IoCTX ioctx;
private static Rbd rbd;
/**
* 连接上ceph环境
*/
public static void connectCeph(){
try {
//利用参数连接Ceph
rados = new Rados("admin");
rados.confSet("mon_host", "172.16.60.41");
rados.confSet("key", "AQCdP9pYGI4jBBAAc96J8/OconCkVKWPBNU2vg==");
rados.connect();
ioctx = rados.ioCtxCreate("rbd");
rbd = new Rbd(ioctx);
System.out.println("successs connetc");
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
/**
* 返回所有的image,并展示其详细信息
* @return
*/
public static List<String> imageList(){
List<String> imageList=null;
try {
imageList = Arrays.asList(rbd.list());
for(String s:imageList){
showDetailOfImage(s);
}
} catch (RbdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imageList;
}
/**
* 显示image的详细信息
* @param imageName
*/
public static void showDetailOfImage(String imageName){
RbdImage image;
try {
image = rbd.open(imageName);
RbdImageInfo info = image.stat();
System.out.println("=================================================================");
System.out.println("imageName: "+imageName);
System.out.println("imageSize: "+info.size);
System.out.println("order: "+info.order);
rbd.close(image);
} catch (RbdException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 以格式1创建image
* @param imageName 名称
* @param imageSize 大小
*/
public static void createRbd_format1(String imageName, long imageSize){
try {
rbd.create(imageName, imageSize);
RbdImage image = rbd.open(imageName);
boolean oldFormat = image.isOldFormat();
System.out.println("imageFormat:==========================="+oldFormat);
rbd.close(image);
} catch (RbdException e) {
System.out.println(e.getMessage() + ": " + e.getReturnValue());
}
}
/**
* 以格式2创建image,ceph 仅支持克隆 format 2 映像(即用 rbd create –format 2 创建的),而且内核 rbd 模块还不支持。
所以现在你 只能用 QEMU/KVM 或 librbd直接访问克隆品
* @param imageName 名称
* @param imageSize 大小
*/
public static void createRbd_format2(String imageName, long imageSize){
try {
int features = (1<<0);
System.out.p