背景
Apache Kudu 是 Cloudera 贡献的开源项目,主要特点是:
- Streamlined Architecture
- Faster Analytics
- Open for Contributions
Kudu 是在 HBase 出现之后,根据 Hbase 的思想开发的。
HBase 一般将数据持久化在 HDFS 中,使用 HDFS 的数据一致性;而 Kudu 是存储在本地,通过 raft 协议来保证强一致和高可靠性。
Kudu 的设计目标是快速分析,除了和 Hbase 一样支持随机读写外,在数据扫描(Scan)的性能比 Hbase 要好,适合 OLAP 场景。
另外,Kudu 核心模块由 C++ 开发,没有 gc 风险;而 Hbase 由 Java 开发,内存紧张时有 gc 风险。
详细对比见参考 1。
与 Parquet, Hbase 比较
整理自 The Columnar Era: Leveraging Parquet, Arrow and Kudu for High-Performance Analytics
分析(快速 Scan) | 随机读写 | ||
---|---|---|---|
Parquet | 最好 | 最差 | |
KUDU | 较好 | 较好 | |
HBase | 最差 | 最好 |
安装
Kudu 可以单独安装,也可以在安装 CDH 时做为一个组件自动安装。
这里单独安装仅仅为了测试,生产环境中还是使用的 CDH 安装。
单独安装方法,来自于参考官方文档。
另外,本文单独安装方法安装的是 kudu 1.4。官方最新的版本是 kudu 1.7。
RHEL 7
增加源
wget http://archive.cloudera.com/kudu/redhat/7/x86_64/kudu/cloudera-kudu.repo
保存到文件夹 /etc/yum.repos.d/
下
可以使用阿里云的镜像,见 http://mirrors.aliyun.com/
安装源
sudo yum install kudu # Base Kudu files
sudo yum install kudu-master # Kudu master init.d service script and default configuration
sudo yum install kudu-tserver # Kudu tablet server init.d service script and default configuration
sudo yum install kudu-client0 # Kudu C++ client shared library
sudo yum install kudu-client-devel # Kudu C++ client SDK
启动服务
[root@localhost fw]# /etc/init.d/kudu-tserver start
Started Kudu Tablet Server (kudu-tserver): [ 确定 ]
[root@localhost fw]# /etc/init.d/kudu-master start
Started Kudu Master Server (kudu-master): [ 确定 ]
确认进程 kudu-tserver
和 kudu-master
都存在
- Master:
kudu-master
的页面为http://localhost:8051
- Tablet Server:
kudu-tserver
的页面为http://localhost:8050
如果远程连接不上的话,确认一下 linux 的防火墙是不是屏蔽了对应的请求。
配置文件
/etc/kudu/conf/master.gflagfile
/etc/kudu/conf/tserver.gflagfile
一般不用修改
但是如果是单机测试的话,修改一下最小分片数到 1 吧。
分别修改这两个配置文件,增加:
--unlock_unsafe_flags=true
--allow_unsafe_replication_factor=true
--default_num_replicas=1
--rpc_negotiation_timeout_ms=9000
然后重启两个服务。
Python 使用
由简单到复杂,先来看 python 的使用吧。
具体参考了官方 kudu-python 示例和 pydoc kudu 帮助手册。
安装 kudu-python
先安装 pip,如果已经有了请略过
sudo yum -y install epel-release python2-pip python-devel
pip 安装 kudu-python
## 准备活动
pip install --upgrade pip
pip install --upgrade setuptools
## 安装包. 对于 kudu1.4,要选择1.2.0的kudu-python
pip install Cython kudu-python==1.2.0
查看所有可以安装的版本:
指定个不存在的版本,就会提示出所有可选的版本。
pip install kudu-python==99.99.99
Collecting kudu-python==99.99.99
Could not find a version that satisfies the requirement kudu-python==99.99.99 (from versions: 0.1.0, 0.1.1, 0.2.0, 0.3.0, 1.1.0, 1.2.0, 1.7.0)
No matching distribution found for kudu-python==99.99.99
使用
连接
>>> import kudu
>>> client = kudu.Client("127.0.0.1:7051")
查看表
>>> client.list_tables()
['java_sample-1527939906616', 'java_sample-1527939874474', 'java_sample-1527938481750', 'java_sample-1527938216058']
删除表
>>> client.delete_table('java_sample-1527939906616')
>>> client.list_tables()
['java_sample-1527939874474', 'java_sample-1527938481750', 'java_sample-1527938216058']
创建表
创建 schema
>>> builder = kudu.schema_builder()
>>> builder.add_column('key', kudu.int32, nullable=False)
>>> builder.add_column('value', kudu.string, nullable=False).compression('lz4')
>>> builder.set_primary_keys(['key'])
>>> schema = builder.build()
创建 partition
>>> from kudu.client import Partitioning
>>> partitioning=Partitioning().add_hash_partitions(['key'], 2)
创建表
>>> client.create_table('table_demo',schema,partitioning)
查看表结构
>>> table = client.table('java_sample-1527939874474')
>>> table.schema
kudu.Schema {
key int32 NOT NULL
value string NOT NULL
PRIMARY KEY (key)
}
查看表内容
>>> scanner = table.scanner()
>>> scanner.open()
<kudu.client.Scanner object at 0x7fb7f78982d0>
>>> tuples = scanner.read_all_tuples()
>>> tuples
[(0, 'value 0'), (1, 'value 1'), (2, 'value 2')]
插入数据到表
>>> session = client.new_session()
>>> op = table.new_insert()
>>> op['key']=3
>>> op['value']='value 3'
>>> session.apply(op)
>>> session.flush()
验证插入成功
>>> scanner = table.scanner()
>>> scanner.open()
<kudu.client.Scanner object at 0x7fb7f7898960>
>>> scanner.read_all_tuples()
[(0, 'value 0'), (1, 'value 1'), (2, 'value 2'), (3, 'value 3')]
其它操作
其它操作有:
- new_delete: 删除数据
- new_update: 更新数据
- new_upsert: 如果存在则更新数据,不存在则插入数据
- rename: 更改表名
Java 使用
这里 java 依赖了 1.4 的 kudu-client,示例代码见 github。
Java 依赖
<dependencies>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
示例代码
演示了创建表,写入数据,扫描数据,和删除表的过程。
代码来自 github
import java.util.ArrayList;
import java.util.List;
import org.apache.kudu.ColumnSchema;
import org.apache.kudu.Schema;
import org.apache.kudu.Type;
import org.apache.kudu.client.CreateTableOptions;
import org.apache.kudu.client.Insert;
import org.apache.kudu.client.KuduClient;
import org.apache.kudu.client.KuduScanner;
import org.apache.kudu.client.KuduSession;
import org.apache.kudu.client.KuduTable;
import org.apache.kudu.client.PartialRow;
import org.apache.kudu.client.RowResult;
import org.apache.kudu.client.RowResultIterator;
public class Sample {
private static final String KUDU_MASTER = System.getProperty("kuduMaster", "192.168.199.137:7051");
public static void main(String[] args) {
System.out.println("-----------------------------------------------");
System.out.println("Will try to connect to Kudu master at " + KUDU_MASTER);
System.out.println("Run with -DkuduMaster=myHost:port to override.");
System.out.println("-----------------------------------------------");
String tableName = "java_sample-" + System.currentTimeMillis();
KuduClient client = new KuduClient.KuduClientBuilder(KUDU_MASTER).build();
try {
// 建表
List<ColumnSchema> columns = new ArrayList(2);
columns.add(new ColumnSchema.ColumnSchemaBuilder("key", Type.INT32).key(true).build());
columns.add(new ColumnSchema.ColumnSchemaBuilder("value", Type.STRING).build());
List<String> rangeKeys = new ArrayList<>();
rangeKeys.add("key");
Schema schema = new Schema(columns);
client.createTable(tableName, schema, new CreateTableOptions().setRangePartitionColumns(rangeKeys));
// 插入数据
KuduTable table = client.openTable(tableName);
KuduSession session = client.newSession();
for (int i = 0; i < 3; i++) {
Insert insert = table.newInsert();
PartialRow row = insert.getRow();
row.addInt(0, i);
row.addString(1, "value " + i);
session.apply(insert);
}
// 查询数据
List<String> projectColumns = new ArrayList<>(1);
projectColumns.add("value");
KuduScanner scanner = client.newScannerBuilder(table).setProjectedColumnNames(projectColumns).build();
while (scanner.hasMoreRows()) {
RowResultIterator results = scanner.nextRows();
while (results.hasNext()) {
RowResult result = results.next();
System.out.println(result.getString(0));
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 删除表
client.deleteTable(tableName);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
client.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
运行结果
-----------------------------------------------
Will try to connect to Kudu master at 192.168.199.137:7051
Run with -DkuduMaster=myHost:port to override.
-----------------------------------------------
[New I/O worker #2] WARN org.apache.kudu.util.NetUtil - Slow DNS lookup! Resolved IP of `localhost' to localhost/127.0.0.1 in 3168448ns
value 0
value 1
value 2
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于