Docker-高级教程-二-

35 阅读1小时+

Docker 高级教程(二)

原文:Pro Docker

协议:CC BY-NC-SA 4.0

六、使用 Apache Cassandra

Apache Cassandra 是一个宽列、开源的 NoSQL 数据库,也是同类中最常用的 NoSQL 数据库。在 Apache Cassandra 中,数据容器相当于关系数据库中的数据库模式,是一个键空间。存储的基本单元是列族(也称为表),表中的每条记录存储在一行中,数据存储在列中。一个列有一个名称、一个值和一个与之相关联的时间戳。存储值不需要列,该列可以是空的。Apache Cassandra 基于灵活的模式(或无模式或动态模式)数据模型,其中不同的行可以有不同的列,并且不需要在表定义中预先指定列。Apache Cassandra 支持列名(称为比较器)和列值(称为验证器)的数据类型,但不要求指定数据类型(验证器和比较器)。定义表(列族)后,可以添加或修改验证器和比较器。Apache Cassandra 为表上的 CRUD(添加、获取、更新、删除)操作提供了一种 Cassandra 查询语言(CQL)。Apache Cassandra 安装包括一个cqlsh实用程序,这是一个交互式 shell,可以从其中运行 CQL 命令。Apache Cassandra 的官方 Docker 映像是可用的,在本章中,我们将在 Docker 容器中运行 Apache Cassandra。

  • 设置环境
  • 启动 Apache Cassandra
  • 启动 TTY
  • 连接到 CQL Shell
  • 创建密钥空间
  • 更改密钥空间
  • 使用密钥空间
  • 创建表格
  • 添加表格数据
  • 查询表
  • 从表格中删除
  • 截断表格
  • 放下一张桌子
  • 删除一个键空间
  • 退出 CQLSh
  • 阻止 Apache 卡桑德拉
  • 启动 Apache Cassandra 的多个实例

设置环境

本章需要以下软件。

  • -Docker(版本 1.8)
  • apache cassandra 的 docker image

我们在其他章节中使用了 Amazon EC2 AMI 来安装 Docker 和 Docker 映像。首先,SSH 到 Amazon EC2 实例。

ssh -i "docker.pem" ec2-user@54.86.243.122

安装 Docker 在第一章中讨论。启动 Docker 服务。以下命令应该输出一条 OK 消息。

sudo service docker start

验证 Docker 服务是否已启动。以下命令应该在 active 字段中输出 Active(正在运行)。

sudo service docker status

前述命令的输出如图 6-1 所示。

A978-1-4842-1830-3_6_Fig1_HTML.jpg

图 6-1。

Starting Docker Service and verifying Status

接下来,下载最新的cassandra Docker 图片。

sudo docker pull cassandra:latest

列出下载的 Docker 映像。

sudo docker images

cassandra映像应被列出,如图 6-2 所示。

A978-1-4842-1830-3_6_Fig2_HTML.jpg

图 6-2。

Listing Docker Image cassandra

启动 Apache Cassandra

使用以下命令在 Docker 容器中启动 Apache Cassandra 服务器进程,其中节点间 Apache Cassandra 集群通信端口指定为 7000,Apache Cassandra 存储数据的目录为/cassandra/data。用–name选项指定容器名为cassandradb。以分离模式启动 Cassandra 实例的语法如下。

docker run --name some-cassandra -d cassandra:tag

–d参数以分离模式启动容器,这意味着即使指定了–t –i选项,交互式 shell 也不会连接到 docker run 命令。

sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb -d -p 7000:7000  cassandra

运行 Apache Cassandra 服务器进程的 Docker 容器启动,如图 6-3 所示。

A978-1-4842-1830-3_6_Fig3_HTML.jpg

图 6-3。

Starting Docker Container for Apache Cassandra

用下面的命令列出正在运行的 Docker 容器。

sudo docker ps

运行 Apache Cassandra 服务器实例的cassandradb容器被列出。还列出了容器 id。默认情况下,端口 9042 是 Apache Cassandra 监听客户端连接的客户端端口。端口 9160 是节俭 API,如图 6-4 所示。

A978-1-4842-1830-3_6_Fig4_HTML.jpg

图 6-4。

Listing Docker Containers that are Running

启动 TTY

使用以下命令启动交互式终端(tty)。

sudo docker exec -it cassandradb bash

tty 被连接,命令提示符被设置为user@containerid。如果用户是 root,容器 id 是dfade56f871,命令提示符变成root@dfade56f871,如图 6-5 所示。

A978-1-4842-1830-3_6_Fig5_HTML.jpg

图 6-5。

Starting the TTY

连接到 CQL Shell

cqlsh 终端用于连接 Apache Cassandra 实例并运行 CQL 命令。使用以下命令启动 cqlsh 终端。

cqlsh

127.0.0.1:9042建立到测试集群的连接。Apache Cassandra 版本的输出为 2.2.2,CQL 规范版本的输出为 3.3.1。显示cqlsh>命令提示符,如图 6-6 所示。

A978-1-4842-1830-3_6_Fig6_HTML.jpg

图 6-6。

Connecting the CQL Shell

我们使用容器名启动了交互式终端,但是 tty 也可以使用容器 id 启动。无论 tty 是如何启动的,cqlsh shell 都是用cqlsh命令启动的。

sudo docker exec –it dfade56f871 bash

cqlsh

cqlsh>命令提示符显示如前,如图 6-7 所示。

A978-1-4842-1830-3_6_Fig7_HTML.jpg

图 6-7。

Connecting to CQL Shell using the Container ID

创建密钥空间

键空间是应用数据的容器,用于对列族进行分组。复制是基于每个键空间设置的。创建密钥空间的 DDL 命令如下。

CREATE KEYSPACE (IF NOT EXISTS)? <identifier> WITH <properties>

默认情况下,密钥空间名称不区分大小写,可以只包含字母数字字符,最大长度为 32。要使密钥空间名称区分大小写,请添加引号。创建顶级键空间的CREATE KEYSPACE语句支持的属性是 replication,用于指定复制策略和选项,而durable_writes用于指定提交日志是否用于键空间上的更新,replication 属性是强制的。例如,创建一个名为CatalogKeyspace的键空间,复制策略类为SimpleStrategy,复制因子为 3。

CREATE KEYSPACE CatalogKeyspace

WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 3};

CatalogKeyspace keyspace被创建,如图 6-8 所示。

A978-1-4842-1830-3_6_Fig8_HTML.jpg

图 6-8。

Creating a Keyspace

更改密钥空间

ALTER KEYSPACE语句用于改变密钥空间,其语法如下,支持的属性与CREATE KEYSPACE语句相同。

ALTER KEYSPACE <identifier> WITH <properties>

例如,改变CatalogKeyspace键空间,使复制因子为 1。

ALTER KEYSPACE CatalogKeyspace

WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};

复制因子被设置为 1,如图 6-9 所示。

A978-1-4842-1830-3_6_Fig9_HTML.jpg

图 6-9。

Altering a Keyspace

使用密钥空间

USE 语句用于设置当前密钥空间,其语法如下。

USE <identifier>

所有后续命令都在用USE语句设置的密钥空间的上下文中运行。例如,将当前密钥空间设置为CatalogKeyspace

use CatalogKeyspace;

cqlsh>命令提示符变为cqlsh:catalogkeyspace>,如图 6-10 所示。

A978-1-4842-1830-3_6_Fig10_HTML.jpg

图 6-10。

Using a Keyspace

创建表格

表也称为COLUMN FAMILYCREATE TABLECREATE COLUMN FAMILY语句用于创建表(列族)。

CREATE ( TABLE | COLUMNFAMILY ) ( IF NOT EXISTS )? <tablename>

'(' <column-definition> ( ',' <column-definition> )* ')'

( WITH <option> ( AND <option>)* )?

关于CREATE TABLE语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html#createTableStmt 。例如,创建一个名为“catalog”的表,其中包含类型为 text 的列catalog_idjournalpublishereditiontitleauthor。指定主键为catalog_id,设置压缩类为LeveledCompactionStrategy

CREATE TABLE catalog(catalog_id text,journal text,publisher text,edition text,title text,author text,PRIMARY KEY (catalog_id)) WITH  compaction = { 'class' : 'LeveledCompactionStrategy' };

catalog表被创建,如图 6-11 所示。

A978-1-4842-1830-3_6_Fig11_HTML.jpg

图 6-11。

Creating a Table

添加表格数据

INSERT DML 语句用于向表中添加数据,其语法如下。

INSERT INTO <tablename>

'(' <identifier> ( ',' <identifier> )* ')'

VALUES '(' <term-or-literal> ( ',' <term-or-literal> )* ')'

( IF NOT EXISTS )?

( USING <option> ( AND <option> )* )?

关于INSERT语句的完整语法,请参考 https://cassandra.apache.org/doc/cql3/CQL.html#insertStmt 。例如,向目录表中添加两行数据,并包含IF NOT EXISTS子句,以便在主键标识的行不存在时添加一行。

INSERT INTO catalog (catalog_id, journal, publisher, edition,title,author) VALUES ('catalog1','Oracle Magazine', 'Oracle Publishing', 'November-December 2013', 'Engineering as a Service','David A.  Kelly') IF NOT EXISTS;

INSERT INTO catalog (catalog_id, journal, publisher, edition,title,author) VALUES ('catalog2','Oracle Magazine', 'Oracle Publishing', 'November-December 2013', 'Quintessential and Collaborative','Tom Haunert') IF NOT EXISTS;

[applied] True输出所示,两行数据相加,如图 6-12 所示。

A978-1-4842-1830-3_6_Fig12_HTML.jpg

图 6-12。

Adding Table Data

查询表

具有以下语法的SELECT语句用于查询一个表。

SELECT <select-clause>

FROM <tablename>

( WHERE <where-clause> )?

( ORDER BY <order-by> )?

( LIMIT <integer> )?

( ALLOW FILTERING )?

关于SELECT语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html#selectStmt 。例如,从catalog表中选择所有列。

SELECT * FROM catalog;

先前添加的两行数据被列出,如图 6-13 所示。

A978-1-4842-1830-3_6_Fig13_HTML.jpg

图 6-13。

Querying Table

从表格中删除

DELETE语句用于删除列和行,其语法如下。

DELETE ( <selection> ( ',' <selection> )* )?

FROM <tablename>

( USING TIMESTAMP <integer>)?

WHERE <where-clause>

( IF ( EXISTS | ( <condition> ( AND <condition> )*) ) )?

关于DELETE语句的完整语法,请参考 cassandra。Apache。org/ doc/ cql3/ CQL。html # deletes mt。例如,从带有catalog_id作为catalog1的行中删除所有列。

DELETE catalog_id, journal, publisher, edition, title, author from catalog WHERE catalog_id='catalog1';

随后,用SELECT语句查询catalog表。

SELECT * FROM catalog;

带有作为catalog1catalog_id的行的列值被删除,但是包括主键列值的行本身没有被删除,即使主键catalog_id被列为要删除的列之一。后续查询列出了主键列值,但将其他列的列值列为空,如图 6-14 所示。

A978-1-4842-1830-3_6_Fig14_HTML.jpg

图 6-14。

Deleting Table Data

截断表格

TRUNCATE语句从表中删除所有数据,其语法如下。

TRUNCATE <tablename>

例如,截断catalog表。随后,使用SELECT语句运行查询。

TRUNCATE catalog;

SELECT * from catalog;

如查询输出所示,没有列出任何数据,因为TRUNCATE语句已经删除了所有数据,如图 6-15 所示。

A978-1-4842-1830-3_6_Fig15_HTML.jpg

图 6-15。

Truncating a Table

放下一张桌子

DROP TABLEDROP COLUMN FAMILY语句用于删除表,其语法如下。

DROP TABLE ( IF EXISTS )? <tablename>

例如,删除catalog表。

DROP TABLE IF EXISTS catalog;

如果没有指定IF EXISTS子句,并且该表不存在,则会生成一个错误。但是有了IF EXISTS子句,如图 6-16 中包含的 IF EXISTS子句的两个连续运行的DROP TABLE语句所示,不会产生错误。

A978-1-4842-1830-3_6_Fig16_HTML.jpg

图 6-16。

Dropping a Table

删除一个键空间

具有以下语法的DROP KEYSPACE语句删除指定的键空间,包括键空间中的列族和列族中的数据,并且键空间在被删除之前不必为空。

DROP KEYSPACE ( IF EXISTS )? <identifier>

例如,删除CatalogKeyspace键空间。

DROP KEYSPACE IF EXISTS CatalogKeyspace;

如果没有指定IF EXISTS子句,并且密钥空间不存在,则会生成一个错误。但是有了IF EXISTS子句,如图 6-17 所示,包含IF EXISTS子句的两个连续运行的DROP KEYSPACE语句所指示的错误不会产生。

A978-1-4842-1830-3_6_Fig17_HTML.jpg

图 6-17。

Dropping a Keyspace

退出 CQL 壳牌

要退出 cqlsh shell,指定退出命令,如图 6-18 所示。随后也用exit命令退出 tty。

A978-1-4842-1830-3_6_Fig18_HTML.jpg

图 6-18。

Exiting CQL Shell

阻止 Apache 卡桑德拉

要停止 Apache Cassandra,请停止运行 Apache Cassandra 服务器的 Docker 容器。

sudo docker stop cassandradb

随后,运行以下命令列出正在运行的容器。

sudo docker ps

如图 6-19 所示,cassndradb容器未被列为运行中。

A978-1-4842-1830-3_6_Fig19_HTML.jpg

图 6-19。

Stopping Cassandra DB Docker Container

启动 Apache Cassandra 的多个实例

可以启动多个运行 Apache Cassandra 实例的 Docker 容器,但是容器名必须是唯一的。例如,启动一个新的 Docker 容器,也称为cassandradb来运行 Apache Cassandra 数据库的另一个实例。

sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb -d -p 7000:7000  cassandra

因为之前已经创建了一个同名(cassandradb)的 Docker 容器,所以即使容器已经停止,也会产生错误,如图 6-20 所示。必须用docker rm命令删除一个容器,才能创建一个同名的新容器。

A978-1-4842-1830-3_6_Fig20_HTML.jpg

图 6-20。

Duplicate Docker Container name error

例如,可以启动另一个具有不同名称cassandradb2的容器。

sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb2 -d -p 7000:7000  cassandra

启动第三个容器,并指定用于运行集群中多个节点的 IP 地址的CASSANDRA_SEEDS环境变量(如果需要)。

sudo docker run -t -i -v /cassandra/data:/var/lib/cassandra/data --name cassandradb3 -d -p 7000:7000 -e CASSANDRA_SEEDS=52.91.214.50,54.86.243.122,54.86.205.95 cassandra

随后,运行以下命令列出正在运行的容器。

sudo docker ps

cassandradb2cassandradb3容器被列为运行中,如图 6-21 所示。

A978-1-4842-1830-3_6_Fig21_HTML.jpg

图 6-21。

Running Multiple Docker Containers for Instances of Apache Cassandra

摘要

在本章中,我们使用 Apache Cassandra 的 Docker 映像在 Docker 容器中运行 Apache Cassandra。我们在 cqlsh shell 中使用不同的 CQL 语句来创建一个键空间,在键空间中创建一个表,并向表中添加数据。我们还运行了 CQL 语句来查询表、删除表中的数据、截断表、删除表和删除键空间。我们还演示了如何创建多个 Docker 容器来运行 Apache Cassandra 的多个实例。在下一章,我们将在 Docker 中运行 Couchbase 服务器。

七、使用 Couchbase 服务器

Couchbase 服务器是一个分布式 NoSQL 数据库。Couchbase 是一个基于 JSON (JavaScript Object Notation)的文档库。像其他 NoSQL 数据存储一样,Couchbase 没有固定的数据存储模式。Couchbase 与 MongoDB 的不同之处在于,MongoDB 基于 BSON(二进制 JSON)文档数据模型。Couchbase 提供了一个 Web 控制台,用于从图形用户界面(GUI)访问 Couchbase 服务器。Couchbase 还提供了一个命令行界面(CLI ),包括几个在 CLI 中运行的工具。在本章中,我们将在 Docker 容器中运行 Couchbase 服务器。

  • 设置环境
  • 启动 Couchbase
  • 访问 Couchbase Web 控制台
  • 配置 Couchbase 服务器
  • 添加文档
  • 启动交互式终端
  • 运行 Couchbase CLI 工具
  • 停止 Couchbase 服务器

设置环境

本章需要以下软件。

  • -Docker(版本 1.8)
  • Couchbase 的 Docker 映像(最新版本)

我们在本章中使用了图 7-1 所示的 Ubuntu 服务器 AMI 来运行软件。附录 a 中讨论了 Amazon EC2 实例的安装和配置。

A978-1-4842-1830-3_7_Fig1_HTML.jpg

图 7-1。

Ubuntu Server AMI

使用用户“Ubuntu”和 Amazon EC2 实例的公共 IP 地址 SSH 登录到 Ubuntu Amazon EC2 实例。对于不同的用户,公共 IP 地址会有所不同(根据所讨论的示例的多次运行,本章还使用了多个公共 IP 地址)。

ssh -i "docker.pem" ubuntu@54.152.90.139

我们需要修改主机 IP 地址文件/etc/hostslocalhost的 IP 地址设置。将 IP 地址设置为 Amazon EC2 实例的公共 IP 地址。获取 Amazon EC2 实例的公共 IP 地址在附录 a 中讨论。在 vi 编辑器中打开/etc/hosts文件。

sudo vi /etc/hosts

将“127.0.0.1”替换为公有 IP 地址;替换以下行:

127.0.0.1 localhost

与:

54.152.90.139 localhost

按照第一章中的讨论在 Ubuntu 上安装 Docker。运行hello-world Docker 映像来测试 Docker 安装。

sudo docker run hello-world

hello-world应用的输出如图 7-2 所示。

A978-1-4842-1830-3_7_Fig2_HTML.jpg

图 7-2。

Output from hello-world

下载名为“Couchbase”的官方 Couchbase Docker 图片。

sudo docker pull couchbase

下载最新的 Docker 映像,如图 7-3 所示。

A978-1-4842-1830-3_7_Fig3_HTML.jpg

图 7-3。

Downloading Docker Image couchbase

启动 Couchbase

接下来,运行 Docker 映像“couchbase”的 Docker 容器,这将在 Docker 容器中启动一个 Couchbase 服务器进程。运行以下 docker 命令,其中 Couchbase Web 控制台连接到 Couchbase 服务器的端口被指定为 8091。容器名被指定为“couchbasedb”。

sudo docker run --name couchbasedb -d -p 8091:8091 couchbase

Couchbase 服务器可能需要非默认的 ulimit 设置。

| Ulimit 设置 | 价值 | 描述 | | --- | --- | --- | | mmit -n | Forty thousand nine hundred and sixty | nofile:打开文件的最大数量 | | 乌利米特-c | One hundred million | 核心:最大核心文件大小。100000000 设置相当于“无限制”,不直接支持。 | | 尤利姆-l | One hundred million | memlock:最大锁定内存地址空间。100000000 设置相当于“无限制”,不直接支持。 |

Docker 容器将所有持久数据存储在/opt/couchbase/var目录中,可以使用–v命令参数从主机挂载这些数据。–ulimit命令参数用于设置docker run命令。运行以下命令来运行 Docker 容器以运行 Couchbase 服务器,如图 7-4 所示。

sudo docker run --name couchbasedb -v ∼/couchbase/data:/opt/couchbase/var -d --ulimit nofile=40960:40960 --ulimit core=100000000:100000000 --ulimit memlock=100000000:100000000 -p 8091:8091 couchbase

随后,列出正在运行的 Docker 容器。

sudo docker ps

couchbasedb 容器被列出,如图 7-4 所示。

A978-1-4842-1830-3_7_Fig4_HTML.jpg

图 7-4。

Running Docker Container for Couchbase

docker logs命令输出容器的日志。

sudo docker logs couchbasedb

显示如图 7-5 所示的信息。

A978-1-4842-1830-3_7_Fig5_HTML.jpg

图 7-5。

Listing Docker Container Log

访问 Couchbase Web 控制台

接下来,我们将从logs: http://<ip>:8091中指示的 URL 访问 Couchbase Web 控制台。使用的<ip>地址会因 Web 控制台访问的主机系统而异。如果在运行 Docker 容器的主机上,使用主机 Amazon EC2 实例的公共 IP 地址。如果在我们访问的远程主机系统上,使用 Amazon EC2 实例的公共 DNS。获取公共 IP 地址和公共 DNS 在附录 a 中讨论。如果公共 DNS 是ec2-54-152-90-139.compute-1.amazonaws.com,,则访问 Couchbase WebConsole 的 URL 变为如下。

http://ec2-54-152-90-139.compute-1.amazonaws.com:8091

在前面的 URL 打开浏览器。床座控制台显示如图 7-6 所示。在下一节中,我们将设置一个 Couchbase 服务器集群。

A978-1-4842-1830-3_7_Fig6_HTML.jpg

图 7-6。

Accessing Couchbase Admin Console

如果已经配置了 Couchbase 集群,Couchbase 控制台 URL 将显示如图 7-7 所示的登录页面。

A978-1-4842-1830-3_7_Fig7_HTML.jpg

图 7-7。

Login Page

指定用户名(管理员)和密码,点击登录,如图 7-8 所示。

A978-1-4842-1830-3_7_Fig8_HTML.jpg

图 7-8。

Specifying Username and Password

配置 Couchbase 服务器群集

在本节中,我们将配置 Couchbase 服务器集群。如前所述访问 Couchbase Web 控制台,如图 7-6 所示,URL 为 http://ec2-54-152-90-139.compute-1.amazonaws.com:8091 。单击 Web 控制台中的设置;只有首次访问 Web 控制台时,才会显示“设置”页面。随后,配置完集群后,将显示登录页面,如前一节所述。

使用配置磁盘存储部分的默认设置。在 Configure Server Hostname 中,将主机名指定为 Amazon EC2 实例的公共 IP 地址,这对于不同的用户是不同的,如图 7-9 所示。主机名字段不接受短名称,主机名中至少需要一个点。

A978-1-4842-1830-3_7_Fig9_HTML.jpg

图 7-9。

Configuring Server

“加入集群/启动新集群”部分提供了两个选项。由于我们正在配置一个新的集群,选择启动一个新的集群,如图 7-10 所示。选择默认设置或修改设置,同时考虑每台服务器可配置的总 RAM。点击下一步。

A978-1-4842-1830-3_7_Fig10_HTML.jpg

图 7-10。

Starting a New Cluster

Couchbase 服务器将数据存储在数据桶中。样本桶部分列出了样本桶。不需要选择样本桶。点击下一步。在创建默认存储桶屏幕中,存储桶名称被预先指定为“默认”。选择铲斗类型为“Couchbase”。选择默认的内存大小和副本设置。还要选择默认的磁盘 I/O 优化设置。

A978-1-4842-1830-3_7_Fig11_HTML.jpg

图 7-11。

Configuring the Default Cluster

在 Flush 中选择 Enable 并点击 Next,如图 7-12 所示。为了能够从存储桶中刷新(删除)数据,必须启用“刷新”。

A978-1-4842-1830-3_7_Fig12_HTML.jpg

图 7-12。

Enabling Flush

在通知中,选择默认设置和“我同意…”复选框,然后单击下一步,如图 7-13 所示。

A978-1-4842-1830-3_7_Fig13_HTML.jpg

图 7-13。

Configuring Notifications

在 Secure this Server 屏幕中,将用户名指定为 Administrator(默认设置),如图 7-14 所示。在密码字段中指定密码,并在验证密码字段中指定相同的密码。点击下一步。

A978-1-4842-1830-3_7_Fig14_HTML.jpg

图 7-14。

Specifying Username and Password

点击集群概述选项卡,显示集群摘要,包括分配和使用的 RAM,以及分配和使用的磁盘存储,如图 7-15 所示。

A978-1-4842-1830-3_7_Fig15_HTML.jpg

图 7-15。

Displaying Cluster Summary

在图 7-16 中,一个存储桶显示为活动的,一个服务器显示为活动的。

A978-1-4842-1830-3_7_Fig16_HTML.jpg

图 7-16。

Displaying Servers Summary

单击服务器节点以列出服务器节点。运行在 IP 地址172.17.0.1的服务器列表如图 7-17 所示。

A978-1-4842-1830-3_7_Fig17_HTML.jpg

图 7-17。

Listing Server IP Address

单击“数据桶”选项卡。“默认”铲斗被列出,如图 7-18 所示。

A978-1-4842-1830-3_7_Fig18_HTML.jpg

图 7-18。

Listing the Default Buckets

添加文档

在这一节中,我们将从 Couchbase 控制台向 Couchbase 服务器添加文档。点击默认桶的文档按钮,如图 7-19 所示。

A978-1-4842-1830-3_7_Fig19_HTML.jpg

图 7-19。

Clicking on the Documents button

在默认的➤文档中,一开始没有列出任何文档。点击创建文件按钮,如图 7-20 所示。

A978-1-4842-1830-3_7_Fig20_HTML.jpg

图 7-20。

Clicking on ‘Create Document’

在创建文档对话框中指定一个文档 ID,例如目录 1,然后点击创建,如图 7-21 所示。

A978-1-4842-1830-3_7_Fig21_HTML.jpg

图 7-21。

Creating a Document

Id 为catalog1的 JSON 文档被添加到默认桶中,如图 7-22 所示。新文档有一些默认字段,可能需要修改。

A978-1-4842-1830-3_7_Fig22_HTML.jpg

图 7-22。

New Document with ID as catalog1

用下面的 JSON 文档替换示例 JSON 文档。

{

"journal": "Oracle Magazine",

"publisher": "Oracle Publishing",

"edition": "November-December 2013",

"title": "Quintessential and Collaborative",

"author": "Tom Haunert"

}

点击【保存】,保存修改后的 JSON 文档,如图 7-23 所示。

A978-1-4842-1830-3_7_Fig23_HTML.jpg

图 7-23。

Saving a Couchbase Document

JSON 文档在 Couchbase 控制台中保存并格式化,如图 7-24 所示。

A978-1-4842-1830-3_7_Fig24_HTML.jpg

图 7-24。

Formatted JSON Document

在 Couchbase 存储桶中,“默认”存储桶的项目计数被列为 1,如图 7-25 所示。单击“文档”按钮,在默认存储桶中显示文档。

A978-1-4842-1830-3_7_Fig25_HTML.jpg

图 7-25。

Item Count for default Bucket

catalog1文件列表如图 7-26 所示。如果需要,单击编辑文档按钮显示文档 JSON。

A978-1-4842-1830-3_7_Fig26_HTML.jpg

图 7-26。

Listing Documents in the default Bucket

类似地,添加文档 id 为 catalog2 的另一个文档。catalog2文档的 JSON 如下。

{

"journal": "Oracle Magazine",

"publisher": "Oracle Publishing",

"edition": "November December 2013",

"title": "Engineering as a Service",

"author": "David A. Kelly",

}

像我们为 catalog1 文档所做的那样,为catalog2的样本文档添加 JSON,并点击保存,如图 7-27 所示。

A978-1-4842-1830-3_7_Fig27_HTML.jpg

图 7-27。

Adding another JSON Document

两个文件catalog1catalog2被列出,如图 7-28 所示。

A978-1-4842-1830-3_7_Fig28_HTML.jpg

图 7-28。

Listing the Two Documents Added

启动交互式终端

要从命令行访问 Couchbase 服务器,请启动交互式终端(tty)。

sudo docker exec -it couchbasedb bash

交互外壳启动,如图 7-29 所示。

A978-1-4842-1830-3_7_Fig29_HTML.jpg

图 7-29。

Starting the Interactive Shell

也可以使用容器 id 而不是容器名称来启动交互式终端。

sudo docker exec -it bff916e55a52 bash

运行 Couchbase CLI 工具

Couchbase Server 提供了几个命令行界面工具(CLI)来监控和管理 Couchbase 服务器桶、节点和集群。

这些 CLI 工具包括用于整个集群操作的couchbase-cli工具、用于创建备份的cbbackup工具、用于加载 JSON 文档的cbdocloader工具以及用于在集群和主机上的数据文件之间传输数据的cbtransfer工具。

例如,使用下面的命令从 tty 运行,运行cbtransfer工具将数据从 Couchbase 服务器传输到 stdout。

cbtransferhttp://ec2-54-152-90-139.compute-1.amazonaws.com:8091/

之前从 Couchbase 控制台添加到 Couchbase 集群的两个 JSON 文档获得了 stdout 输出,如图 7-30 所示。

A978-1-4842-1830-3_7_Fig30_HTML.jpg

图 7-30。

Running cbtransfer

停止 Couchbase 服务器和容器

要停止 Couchbase 服务器和容器,使用exit命令退出交互终端,如图 7-31 所示。

A978-1-4842-1830-3_7_Fig31_HTML.jpg

图 7-31。

Stopping Couchbase Server

在主机系统中,运行docker stop命令来停止 Docker 容器。

sudo docker stop couchbasedb

随后,列出正在运行的 Docker 容器。

sudo docker ps

couchbasedb容器未列出,如图 7-32 所示。

A978-1-4842-1830-3_7_Fig32_HTML.jpg

图 7-32。

The Docker Container for couchbasedb does not get listed

摘要

在本章中,我们使用 Couchbase Server 的官方 Docker 映像在 Docker 容器中运行一个 Couchbase Server 实例。我们从 Couchbase 控制台访问 Couchbase 服务器,并添加了一些 JSON 文档。随后,我们使用cbtransfer CLI 工具将存储的文档输出到 stdout。在下一章,我们将讨论如何使用 Apache Hadoop。

八、使用 Apache Hadoop

Apache Hadoop 是处理大型数据集的事实上的框架。Apache Hadoop 是一个分布式软件应用,运行在一个集群中的几个(多达成百上千个)节点上。Apache Hadoop 由两个主要组件组成:Hadoop 分布式文件系统(HDFS)和 MapReduce。HDFS 用于存储大型数据集,MapReduce 用于处理大型数据集。Hadoop 可以线性扩展而不会降低性能,并且利用商用硬件而不是任何专用硬件。Hadoop 旨在容错,并通过将计算转移到数据而不是将数据转移到计算来利用数据局部性。MapReduce 框架有两个版本 MapReduce1 (MR1)和 MapReduce2 (MR2)(也叫 YARN)。MR1 是 Hadoop 早期版本(Hadoop 1.x)的默认 MapReduce 框架,YARN 是 Hadoop 后期版本(Hadoop 2.x)的默认 MapReduce 框架。

  • 设置环境
  • 启动 Hadoop
  • 启动交互式 Shell
  • 为 MapReduce 字数统计应用创建输入文件
  • 运行 MapReduce 字数统计应用
  • 停止 Hadoop Docker 容器
  • 使用 CDH 坞站映像

设置环境

本章使用了以下软件。

  • -Docker(版本 1.8)
  • Apache Hadoop 坞站映像
  • -Cloudera Hadoop (CDH)坞站映像

在其他章节中,我们使用了一个基于 Red Hat Enterprise Linux 7.1 (HVM)、SSD 卷类型 ami-12663b7a 的 Amazon EC2 实例来安装软件。到 Amazon EC2 实例的 SSH 登录。

ssh -i "docker.pem" ec2-user@52.23.207.240

按照第一章所述安装 Docker。启动 Docker 服务。

sudo service docker start

OK 消息表明 Docker 服务已经启动,如图 8-1 所示。

A978-1-4842-1830-3_8_Fig1_HTML.jpg

图 8-1。

Starting the Docker Service

添加一个名为“hadoop”的组和一个名为“hadoop”的用户。

groupadd hadoop

useradd -g hadoop hadoop

Apache Hadoop 有几个 Docker 映像。我们使用了 Docker Hub 上的sequenceiq/hadoop-docker Docker 映像。下载标签为 2.7.0 的 Docker 映像或最新的标签映像(如果不同)。

sudo dock pull sequence IQ/Hadoop dock:2 . 7 . 0

docker pull命令如图 8-2 所示。

A978-1-4842-1830-3_8_Fig2_HTML.jpg

图 8-2。

Running the docker pull Command

Docker 映像sequenceiq/hadoop-docker被下载,如图 8-3 所示。

A978-1-4842-1830-3_8_Fig3_HTML.jpg

图 8-3。

Downloading Docker Image sequenceiq/hadoop-docker

启动 Hadoop

接下来,启动 Hadoop 组件 HDFS 和 MapReduce。Docker 映像sequenceiq/hadoop-docker默认配置为启动 YARN 或 MR2 框架。运行下面的docker run命令,以分离模式启动 Docker 容器,启动 HDFS (NameNode 和 DataNode)和 YARN (ResourceManager 和 NodeManager)。

sudo docker  run -d --name hadoop sequenceiq/hadoop-docker:2.7.0

随后,列出正在运行的 Docker 容器。

sudo docker ps

前面两个命令的输出如图 8-4 所示,包括基于sequenceiq/hadoop-docker映像的 Apache Hadoop 的运行 Docker 容器。Docker 容器名为“hadoop”,容器 id 为“27436aa7c645”。

A978-1-4842-1830-3_8_Fig4_HTML.jpg

图 8-4。

Running Docker Container for Apache Hadoop

启动交互式 Shell

使用以下命令启动交互式 shell 或终端(tty)。

sudo docker exec -it hadoop bash

显示如图 8-5 所示的交互终端提示。

A978-1-4842-1830-3_8_Fig5_HTML.jpg

图 8-5。

Starting Interactive Terminal

也可以使用容器 id 而不是容器名称来启动交互式外壳。

sudo docker exec -it  27436aa7c645 bash

如果docker run命令中省略了–d命令参数,并且使用以下命令提供了–it参数(与–i–t一起提供), Docker 容器将以前台模式启动。

sudo docker run -it --name hadoop sequenceiq/hadoop-docker:2.7.0 /etc/bootstrap.sh –bash

Hadoop 组件启动并将控制台连接到 Hadoop 标准输入、标准输出和标准错误流,如图 8-6 所示。对于每个启动的 Hadoop 组件,控制台都会输出一条消息。–it参数启动交互终端(tty)。

A978-1-4842-1830-3_8_Fig6_HTML.jpg

图 8-6。

Starting Docker Container in Foreground

为 MapReduce 字数统计应用创建输入文件

在本节中,我们将为 MapReduce Word Count 应用创建输入文件,该应用包含在 Hadoop 发行版打包的示例中。要创建输入文件,请将目录(cd)更改为$HADOOP_PREFIX目录。

bash-4.1# cd $HADOOP_PREFIX

如图 8-7 所示,前面的命令将从交互终端(tty)运行。

A978-1-4842-1830-3_8_Fig7_HTML.jpg

图 8-7。

Setting Current Directory to $HADOOP_PREFIX Directory

在 HDFS 中为输入文件创建一个名为/input的目录。随后,将目录权限设置为全局(777)。

bash-4.1# bin/hdfs dfs -mkdir  /input

bash-4.1# bin/hdfs dfs -chmod -R 777 /input

前面的命令也从交互终端运行,如图 8-8 所示。

A978-1-4842-1830-3_8_Fig8_HTML.jpg

图 8-8。

Creating Input Directory

/input目录添加两个文本文件(input1.txtinput2.txt)和一些示例文本。要创建一个文本文件input1.txt,在 tty 中运行下面的 vi 编辑器命令。

vi input1.txt

input1.txt中添加以下两行文本。

Hello World Application for Apache Hadoop

Hello World and Hello Apache Hadoop

使用: wq命令保存input1.txt文件,如图 8-9 所示。

A978-1-4842-1830-3_8_Fig9_HTML.jpg

图 8-9。

The input1.txt File

用下面的命令将 input1.txt 文件放到 HDFS 目录/input中,也如图 8-10 所示。

bin/hdfs dfs -put input1.txt /input

input1.txt文件被添加到 HDFS 的/input目录中。

A978-1-4842-1830-3_8_Fig10_HTML.jpg

图 8-10。

Putting the input1.txt in the HDFS

类似地,用下面的 vi 命令打开另一个新的文本文件input2.txt

vi input2.txt

input2.txt文件中添加以下两行文本。

Hello World

Hello Apache Hadoop

使用:wq命令保存input2.txt文件,如图 8-11 所示。

A978-1-4842-1830-3_8_Fig11_HTML.jpg

图 8-11。

The input2.txt File

input2.txt文件放到 HDFS 目录/input中。

bin/hdfs dfs -put input2.txt /input

随后,运行以下命令来运行/input目录中的文件。

bin/hdfs –ls /input

添加到 HDFS 的两个文件被列出,如图 8-12 所示。

A978-1-4842-1830-3_8_Fig12_HTML.jpg

图 8-12。

Listing the Input Files in the HDFS

运行 MapReduce 字数统计应用

在本节中,我们将运行一个 MapReduce 应用进行字数统计;应用打包在hadoop-mapreduce-examples-2.7.0.jar文件中,可以用参数“wordcount”调用。wordcount应用要求提供输入和输出目录。输入目录是我们之前创建的 HDFS 中的/input目录,输出目录是/output,它在运行 hadoop 命令之前必须不存在。从交互式 shell 中运行下面的hadoop命令。

bin/hadoop jar $HADOOP_PREFIX/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.0.jar wordcount  /input /output

MapReduce 作业使用 YARN 框架开始,如图 8-13 所示。

A978-1-4842-1830-3_8_Fig13_HTML.jpg

图 8-13。

Starting MapReduce Application with YARN Framework

纱线作业完成,如图 8-14 所示,字数统计应用输出到 HDFS 的/output目录。

A978-1-4842-1830-3_8_Fig14_HTML.jpg

图 8-14。

Output from the MapReduce Application

hadoop命令的完整输出如下。

<mapreduce/hadoop-mapreduce-examples-2.7.0.jar wordcount  /input /output

15/10/18 15:46:17 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032

15/10/18 15:46:19 INFO input.FileInputFormat: Total input paths to process : 2

15/10/18 15:46:19 INFO mapreduce.JobSubmitter: number of splits:2

15/10/18 15:46:20 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1445197241840_0001

15/10/18 15:46:21 INFO impl.YarnClientImpl: Submitted application application_1445197241840_0001

15/10/18 15:46:21 INFO mapreduce.Job: The url to track the job: http://fb25c4cabc55:8088/proxy/application_1445197241840_0001/

15/10/18 15:46:21 INFO mapreduce.Job: Running job: job_1445197241840_0001

15/10/18 15:46:40 INFO mapreduce.Job: Job job_1445197241840_0001 running in uber mode : false

15/10/18 15:46:40 INFO mapreduce.Job:  map 0% reduce 0%

15/10/18 15:47:03 INFO mapreduce.Job:  map 100% reduce 0%

15/10/18 15:47:17 INFO mapreduce.Job:  map 100% reduce 100%

15/10/18 15:47:18 INFO mapreduce.Job: Job job_1445197241840_0001 completed successfully

15/10/18 15:47:18 INFO mapreduce.Job: Counters: 49

File System Counters

FILE: Number of bytes read=144

FILE: Number of bytes written=345668

FILE: Number of read operations=0

FILE: Number of large read operations=0

FILE: Number of write operations=0

HDFS: Number of bytes read=324

HDFS: Number of bytes written=60

HDFS: Number of read operations=9

HDFS: Number of large read operations=0

HDFS: Number of write operations=2

Job Counters

Launched map tasks=2

Launched reduce tasks=1

Data-local map tasks=2

Total time spent by all maps in occupied slots (ms)=41338

Total time spent by all reduces in occupied slots (ms)=11578

Total time spent by all map tasks (ms)=41338

Total time spent by all reduce tasks (ms)=11578

Total vcore-seconds taken by all map tasks=41338

Total vcore-seconds taken by all reduce tasks=11578

Total megabyte-seconds taken by all map tasks=42330112

Total megabyte-seconds taken by all reduce tasks=11855872

Map-Reduce Framework

Map input records=6

Map output records=17

Map output bytes=178

Map output materialized bytes=150

Input split bytes=212

Combine input records=17

Combine output records=11

Reduce input groups=7

Reduce shuffle bytes=150

Reduce input records=11

Reduce output records=7

Spilled Records=22

Shuffled Maps =2

Failed Shuffles=0

Merged Map outputs=2

GC time elapsed (ms)=834

CPU time spent (ms)=2760

Physical memory (bytes) snapshot=540696576

Virtual memory (bytes) snapshot=2084392960

Total committed heap usage (bytes)=372310016

Shuffle Errors

BAD_ID=0

CONNECTION=0

IO_ERROR=0

WRONG_LENGTH=0

WRONG_MAP=0

WRONG_REDUCE=0

File Input Format Counters

Bytes Read=112

File Output Format Counters

Bytes Written=60

bash-4.1#

用下面的命令列出 HDFS 目录中的输出文件。

bin/hdfs dfs -ls  /output

列出两个文件:_SUCCESS,表示纱线作业成功完成,part-r-00000,是wordcount应用的输出,如图 8-15 所示。

A978-1-4842-1830-3_8_Fig15_HTML.jpg

图 8-15。

Files Output by the YARN Application

使用以下命令列出wordcount应用的输出。

hdfs dfs -cat /output/part-r-00000

输入文件input1.txtinput2.txt中每个不同单词的字数得到输出,如图 8-16 所示。

A978-1-4842-1830-3_8_Fig16_HTML.jpg

图 8-16。

Listing the Word Count

停止 Hadoop Docker 容器

可以使用docker stop命令停止运行 Hadoop 进程的 Docker 容器。

sudo docker stop hadoop

随后运行docker ps命令,没有容器被列为运行中,如图 8-17 所示。

A978-1-4842-1830-3_8_Fig17_HTML.jpg

图 8-17。

Listing Running Docker Containers after stopping Apache Hadoop Container

使用 CDH 坞站映像

如前所述,Apache Hadoop 有几个 Docker 映像可用。另一个 Docker 映像是svds/cdh Docker 映像,我们也将在随后的章节中使用,它基于由名为 CDH 的 Cloudera Hadoop 发行版打包的 Apache Hadoop 生态系统。svds/cdh映像不仅包括 Apache Hadoop,还包括 Apache Hadoop 生态系统中的几个框架,其中一些将在后面的章节中讨论。用下面的命令下载svds/cdh镜像。

sudo docker pull svds/cdh

启动一个运行 CDH 框架的 Docker 容器。

sudo docker run  -d --name cdh svds/cdh

启动交互式终端来运行 CDH 框架的命令。

sudo docker exec -it cdh bash

在 tty 中,Hadoop 框架应用无需进一步配置即可运行。例如,在命令行上运行带有“hdfs”的 HDFS 命令。hdfs命令的用法如下。

hdfs

HDFS 命令用法得到如图 8-18 所示的输出。

A978-1-4842-1830-3_8_Fig18_HTML.jpg

图 8-18。

hdfs Command Usage

配置文件在/etc/hadoop/conf符号链接中,如图 8-19 所示。

A978-1-4842-1830-3_8_Fig19_HTML.jpg

图 8-19。

Listing the Symlink for the Configuration Directory

图 8-20 列出了conf符号链接指向的/etc/alternatives/hadoop-conf目录下的配置文件如下。

A978-1-4842-1830-3_8_Fig20_HTML.jpg

图 8-20。

Listing the Configuration Files

可使用docker stop命令停止 cdh 容器。

sudo docker stop cdh

摘要

在本章中,我们在 Docker 容器中运行了 Apache Hadoop 组件。我们创建了一些文件,并把这些文件放在 HDFS。随后,我们运行了一个与 Hadoop 发行版中的示例打包在一起的 MapReduce wordcount应用。我们还介绍了基于 Cloudera Hadoop 发行版(CDH)的 Docker 映像,我们还将在基于 Apache Hadoop 生态系统框架的后续章节中使用它。

九、使用 Apache Hive

Apache Hive 是用于存储、管理和查询大型数据集的数据仓库框架。HiveQL 是一种类似 SQL 的语言。默认情况下,Hive 将数据存储在 HDFS 中,并且可以使用 Hive 表来定义数据的结构。Hive 支持两种表:托管表和外部表。托管表由 Hive 框架管理,而外部表则不是。删除托管表时,元数据和表数据也会被删除。当删除配置单元外部表时,仅删除元数据,而不删除表数据,因为表数据不由配置单元框架管理。Hive 利用 metastore 来存储有关 Hive 表的元数据。配置单元 metastore 数据库用于 metastore,默认情况下是 Derby 数据库。metastore 数据库可以在嵌入式模式或远程模式下运行;默认为嵌入式模式。在本章中,我们将使用一个 Docker 映像来运行 Docker 容器中的 Apache Hive。

  • 设置环境
  • 正在启动 Apache Hive
  • 连接到直线 CLI 外壳
  • 连接到 HiveServer2
  • 创建配置单元表
  • 将数据加载到配置单元表中
  • 查询配置单元表
  • 停止 Apache 蜂房

设置环境

本章需要以下软件。

  • -Docker(使用 1.8 版)
  • apache hive 的 docker image

我们使用 Amazon EC2 实例来安装软件。按照第一章所述安装 Docker。SSH 连接到 Amazon EC2 实例。

ssh -i "docker.pem" ec2-user@52.23.241.186

启动 Docker 服务并验证 Docker 服务的状态。

sudo service docker start

sudo service docker status

下载svds/cdh Docker 镜像,它与 Apache HBase、Apache Sqoop 和 Apache Spark 上的一些其他 Apache Hadoop 生态系统章节中使用的镜像相同。

sudo docker pull svds/cdh

正在启动 Apache Hive

要启动 Apache Hive,请启动一个运行cdh进程或组件的 Docker 容器。运行下面的docker run命令,该命令以分离模式启动 Docker 容器,并将名称“cdh”分配给容器。

sudo docker run  -d --name cdh svds/cdh

列出正在运行的 Docker 容器;应该会列出“cdh”容器。

sudo docker ps

启动一个交互式终端来运行 Apache Hive shell 命令。

sudo docker exec -it cdh bash

连接到直线 CLI 外壳

Apache Hive 提供了 Hive CLI 来从命令行界面访问 HiveServer1。在 Hive 的较新版本中,HiveServer1 已被弃用,并被替换为 HiveServer2,Hive CLI 已被弃用,并被替换为 Beeline CLI。Hive CLI 是一个基于 Apache Thrift 的客户端,而 Beeline 是一个基于 SQLLine CLI 的 JDBC 客户端。对于 Beeline,仍然使用 Thrift API,但不是直接从客户端使用;JDBC 驱动程序使用 Thrift API 与 HiveServer2 通信。

在使用 Hive CLI 或 Beeline CLI 之前,我们需要修改 Hive 存储其数据的 HDFS 目录的权限,这个目录就是/user/hive/warehouse目录。在/user/hive/warehouse目录上设置全局权限(777)。

hdfs dfs –chmod –R 777 /user/hive/warehouse

前面的命令在交互终端中运行,如图 9-1 所示。

A978-1-4842-1830-3_9_Fig1_HTML.jpg

图 9-1。

Setting Permissions on the Hive Warehouse Directory

如果要使用 Hive CLI,请在交互式终端中运行以下命令。

hive

配置单元 CLI 已启动。如图 9-2 所示,还会输出一条警告消息,指出 Hive CLI 已被否决,建议迁移到 Beeline。

A978-1-4842-1830-3_9_Fig2_HTML.jpg

图 9-2。

Message about Migration to Beeline

我们将在本章中使用直线 CLI。使用exitquit命令退出 Hive CLI。使用以下命令启动直线 CLI。

beeline

直线版本 1.1.0 CDH 5.4.3 开始如图 9-3 所示。

A978-1-4842-1830-3_9_Fig3_HTML.jpg

图 9-3。

Starting Beeline

连接到 HiveServer2

我们在上一节中启动了 Beeline CLI,但是我们还没有连接到 HiveServer2。要进行演示,请运行以下命令。

use default;

show tables;

输出“无电流连接”信息,如图 9-4 所示。

A978-1-4842-1830-3_9_Fig4_HTML.jpg

图 9-4。

Message “No Current Connection”

要连接到 HiveServer2,我们需要运行!connect命令。!connect命令用途可通过以下命令输出。

!connect

!connect命令用法得到如图 9-5 所示的输出。

A978-1-4842-1830-3_9_Fig5_HTML.jpg

图 9-5。

Command Usage for !connect

HiveServer2 可以以两种模式之一连接:嵌入式或远程。如果 Beeline CLI 在安装了 Hive 的同一台计算机上运行,则可以使用嵌入式模式。如果 Beeline CLI 在配置单元的远程机器上,则必须使用远程模式。我们将使用嵌入式模式。连接 url 的语法如下,其中dbName是 Hive 数据库,<host><port>是 HiveServer2 的主机名和端口号。

jdbc:hive2://<host>:<port>/dbName

运行下面的直线命令!connect,其中首先指定到 HiveServer2 的连接 url,然后是用户名、密码和 Hive JDBC 驱动程序。对于默认用户名、密码和配置单元 JDBC 驱动程序,请指定空字符串“”。默认的 Hive JDBS 驱动程序是org.apache.hive.jdbc.HiveDriver

!connect jdbc:hive2://localhost:10000/default "" "" ""

如图 9-6 所示,建立了到 Apache Hive 1.1.0 的连接。Apache Hive 1.1.0 版本是重新命名的 Hive 0.15.0 版本。

A978-1-4842-1830-3_9_Fig6_HTML.jpg

图 9-6。

Connecting with Hive2 Server

以前不运行的直线命令在连接到 HiveServer2 后会运行。再次运行以下命令,将数据库设置为“默认”并列出配置单元表。

use default

show tables

数据库被设置为默认值,并列出配置单元表。该数据库已经是连接 url 中指定的“默认”数据库,并且运行use default命令来演示该命令的运行。没有列出任何表格,因为还没有创建任何表格,如图 9-7 所示。我们将在下一部分创建一个表。

A978-1-4842-1830-3_9_Fig7_HTML.jpg

图 9-7。

Listing Tables

创建配置单元表

在本节中,我们将创建一个名为“wlslog”的配置单元表,其中包含列time_stampcategorytypeservernamecodemsg,,所有列的类型都是string。Hive 使用序列化器/反序列化器,也称为 Serde。可以使用自定义 Serde,也可以使用本地 Serde。如果没有指定ROW FORMAT,则使用本地 Serde。如果为带分隔符的数据文件指定了ROW FORMAT DELIMITED,也将使用本地 Serde。要用','分隔字段,请指定FIELDS TERMINATED BY','并用换行符结束一行数据,请指定LINES TERMINATED BY '\n'

运行下面的CREATE TABLE命令来创建一个配置单元管理的表;配置单元外部表的命令是CREATE EXTERNAL TABLE

CREATE TABLE wlslog(time_stamp STRING,category STRING,type STRING,servername STRING,code STRING,msg STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';

名为wlslog的配置单元表被创建,如图 9-8 所示。我们还没有使用wlslog表中的PRIMARY KEY字段。

A978-1-4842-1830-3_9_Fig8_HTML.jpg

图 9-8。

Creating Hive Table

运行以下命令来描述wlslog表。

desc wlslog;

由列名和数据类型组成的表结构如图 9-9 所示。

A978-1-4842-1830-3_9_Fig9_HTML.jpg

图 9-9。

Describing Table Structure

将数据加载到配置单元表中

接下来,我们将数据加载到 Hive 表中。运行下面的INSERT HiveQL 语句将一行数据添加到wlslog表中。

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STANDBY');

MapReduce 作业开始将数据加载到 Hive 表中,如图 9-10 所示。

A978-1-4842-1830-3_9_Fig10_HTML.jpg

图 9-10。

Running the INSERT Command

MapReduce 作业由 1 个映射器和 0 个缩减器组成。数据被加载到default.wlslog表中,如图 9-11 所示。

A978-1-4842-1830-3_9_Fig11_HTML.jpg

图 9-11。

Loading Data into Hive Table

如果没有指定PRIMARY KEY,配置单元表中的数据不会被约束为具有唯一的列值,我们没有指定。可以添加具有相同数据的行,而不在表定义中添加PRIMARY KEY。运行下面的INSERT语句,再添加 7 行数据,包括一行具有重复列数据的数据。

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer,BEA-000365','Server state changed to STANDBY');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:17-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STARTING');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:18-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to ADMIN');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:19-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RESUMING');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:20-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000331','Started WebLogic AdminServer');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:21-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RUNNING');

INSERT INTO TABLE wlslog VALUES ('Apr-8-2014-7:06:22-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000360','Server started in RUNNING mode');

查询配置单元表

创建了一个 Hive 表并将数据加载到该表中后,我们将使用一个SELECT HiveQL 语句查询该表。在直线 CLI 中运行以下查询。

select * from wlslog;

8 行数据被列出,如图 9-12 所示。

A978-1-4842-1830-3_9_Fig12_HTML.jpg

图 9-12。

Running a SELECT HiveQL Statement

停止 Apache 蜂房

要停止 Apache Hive 进程,运行docker stop命令来停止运行 cdh 框架的 Docker 容器。

sudo docker stop cdh

摘要

在本章中,我们使用了一个 Docker 映像来运行 CDH 框架,包括 Docker 容器中的 Apache Hive 框架。我们启动了一个直线 CLI,它取代了 Hive CLI,并从直线 CLI 连接到 HiveServer2。我们创建了一个配置单元管理表,并将数据加载到配置单元表中。随后,我们从 Beeline CLI 查询了 Hive 表。在下一章中,我们将使用 Docker 容器中的 Apache HBase 数据库。

十、使用 Apache HBase

Apache HBase 是 Apache Hadoop 数据库。Apache HBase 基于宽列数据存储模型,以表作为存储单位。一个表由一个或多个柱族组成。Apache HBase 是一个无模式的 NoSQL 数据库。默认情况下,HBase 将数据存储在 HDFS 中。在本章中,我们将使用 Docker 映像在 Docker 容器中运行 Apache HBase。我们将使用我们在第八章中介绍的 svds/cdh Docker 镜像。

  • 设置环境
  • 从 CDH 开始
  • 启动交互式外壳
  • 启动 HBase Shell
  • 创建 HBase 表
  • 列出 HBase 表
  • 获取单个表格行
  • 获取单行列
  • 扫描表格
  • 阻止 CDH

设置环境

本章需要以下软件。

  • -Docker(使用 1.8 版)
  • cdh 的坞站映像

在其他章节中,我们已经在 Amazon EC2 实例上安装了软件。到 Amazon EC2 实例的 SSH 登录。

ssh -i "docker.pem" ec2-user@54.209.254.175

启动 Docker 服务。

sudo service docker start

验证 Docker 是否已启动。

sudo service docker status

下载 svds/cdh Docker 映像(如果尚未下载前一章的映像)。

sudo docker pull svds/cdh

下载svds/cdh:latest Docker 镜像,如图 10-1 所示。

A978-1-4842-1830-3_10_Fig1_HTML.jpg

图 10-1。

Downloading the svds/cdh Docker Image

列出 Docker 映像以验证 svds/cdh 映像是否已下载。

sudo docker images

从 CDH 开始

启动 Docker 容器来运行 Apache Hadoop 生态系统框架,其中包括 Apache HBase。运行带有–d选项的docker run命令,以分离模式启动容器。Docker 容器名是“cdh ”,用–name选项指定。

sudo docker run  -d --name cdh svds/cdh

Docker 容器启动如图 10-2 所示。

A978-1-4842-1830-3_10_Fig2_HTML.jpg

图 10-2。

Starting Docker Container

列出正在运行的 Docker 容器。

sudo docker ps

“cdh”容器被列为正在运行,如图 10-3 所示。还列出了容器 id。

A978-1-4842-1830-3_10_Fig3_HTML.jpg

图 10-3。

Listing the Running Docker Containers

启动交互式外壳

接下来,启动一个交互式终端(tty)来运行 HBase shell。

sudo docker exec -it cdh bash

交互终端启动,命令提示符变为root@86f0cf0a5c8d,如图 10-4 所示。

A978-1-4842-1830-3_10_Fig4_HTML.jpg

图 10-4。

Starting the Interactive Shell

也可以使用容器 id 而不是容器名称来启动交互式外壳。

sudo docker exec -it 86f0cfoa5c8d bash

启动 HBase Shell

接下来,在交互式终端中运行以下命令,启动 HBase shell。

bin/hbase shell

HBase shell 启动,如图 10-5 所示。

A978-1-4842-1830-3_10_Fig5_HTML.jpg

图 10-5。

Starting the HBase Shell

创建 HBase 表

使用“创建”命令创建一个 HBase 表。除了表名之外,还要提供一个或多个列族以及每个列族的规范字典。或者,提供一个表配置字典。例如,创建一个名为“wlslog”的表,其中包含一个名为“log”的列族。

create 'wlslog', 'log'

HBase 表' wlslog '被创建,如图 10-6 所示。

A978-1-4842-1830-3_10_Fig6_HTML.jpg

图 10-6。

Creating an HBase Table

使用put命令在表格/行/列坐标处添加单元格值。用下面的put命令添加 7 行数据。Apache HBase 和其他 Apache Hadoop 生态系统软件是为大量数据而设计的,这些数据可能有数百万行,但我们只添加了一个数据示例来演示 Apache HBase 的使用。

put 'wlslog', 'log1', 'log:time_stamp', 'Apr-8-2014-7:06:16-PM-PDT'

put 'wlslog', 'log1', 'log:category', 'Notice'

put 'wlslog', 'log1', 'log:type', 'WeblogicServer'

put 'wlslog', 'log1', 'log:servername', 'AdminServer'

put 'wlslog', 'log1', 'log:code', 'BEA-000365'

put 'wlslog', 'log1', 'log:msg', 'Server state changed to STANDBY'

put 'wlslog', 'log2', 'log:time_stamp', 'Apr-8-2014-7:06:17-PM-PDT'

put 'wlslog', 'log2', 'log:category', 'Notice'

put 'wlslog', 'log2', 'log:type', 'WeblogicServer'

put 'wlslog', 'log2', 'log:servername', 'AdminServer'

put 'wlslog', 'log2', 'log:code', 'BEA-000365'

put 'wlslog', 'log2', 'log:msg', 'Server state changed to STARTING'

put 'wlslog', 'log3', 'log:time_stamp', 'Apr-8-2014-7:06:18-PM-PDT'

put 'wlslog', 'log3', 'log:category', 'Notice'

put 'wlslog', 'log3', 'log:type', 'WeblogicServer'

put 'wlslog', 'log3', 'log:servername', 'AdminServer'

put 'wlslog', 'log3', 'log:code', 'BEA-000365'

put 'wlslog', 'log3', 'log:msg', 'Server state changed to ADMIN'

put 'wlslog', 'log4', 'log:time_stamp', 'Apr-8-2014-7:06:19-PM-PDT'

put 'wlslog', 'log4', 'log:category', 'Notice'

put 'wlslog', 'log4', 'log:type', 'WeblogicServer'

put 'wlslog', 'log4', 'log:servername', 'AdminServer'

put 'wlslog', 'log4', 'log:code', 'BEA-000365'

put 'wlslog', 'log4', 'log:msg', 'Server state changed to RESUMING'

put 'wlslog', 'log5', 'log:time_stamp', 'Apr-8-2014-7:06:20-PM-PDT'

put 'wlslog', 'log5', 'log:category', 'Notice'

put 'wlslog', 'log5', 'log:type', 'WeblogicServer'

put 'wlslog', 'log5', 'log:servername', 'AdminServer'

put 'wlslog', 'log5', 'log:code', 'BEA-000331'

put 'wlslog', 'log5', 'log:msg', 'Started Weblogic AdminServer'

put 'wlslog', 'log6', 'log:time_stamp', 'Apr-8-2014-7:06:21-PM-PDT'

put 'wlslog', 'log6', 'log:category', 'Notice'

put 'wlslog', 'log6', 'log:type', 'WeblogicServer'

put 'wlslog', 'log6', 'log:servername', 'AdminServer'

put 'wlslog', 'log6', 'log:code', 'BEA-000365'

put 'wlslog', 'log6', 'log:msg', 'Server state changed to RUNNING'

put 'wlslog', 'log7', 'log:time_stamp', 'Apr-8-2014-7:06:22-PM-PDT'

put 'wlslog', 'log7', 'log:category', 'Notice'

put 'wlslog', 'log7', 'log:type', 'WeblogicServer'

put 'wlslog', 'log7', 'log:servername', 'AdminServer'

put 'wlslog', 'log7', 'log:code', 'BEA-000360'

put 'wlslog', 'log7', 'log:msg', 'Server started in RUNNING mode'

数据被添加到“wlslog”表中,如图 10-7 所示。

A978-1-4842-1830-3_10_Fig7_HTML.jpg

图 10-7。

Adding Data to HBase Table

列出 HBase 表

使用在 HBase shell 中运行的以下命令列出这些表。

list

一个表格,即“wlslog”表格,如图 10-8 所示。

A978-1-4842-1830-3_10_Fig8_HTML.jpg

图 10-8。

Listing HBase Tables

获取单个表格行

get命令用于获取行或列单元格中的数据。运行下面的get命令获取表‘WLS log’中‘log 7’行的数据。

get 'wlslog', 'log7'

单列数据被列出,如图 10-9 所示。

A978-1-4842-1830-3_10_Fig9_HTML.jpg

图 10-9。

Getting a Single Table Row

获取单行列

可选地,列的字典可以被提供给get命令。例如,从log.msg列中的“log5”行获取wlslog表中的列数据。

get  'wlslog', 'log5', {COLUMNS=>['log:msg']}

表‘WLS log’中‘log5’行的log.msg列数据得到如图 10-10 所示的输出。

A978-1-4842-1830-3_10_Fig10_HTML.jpg

图 10-10。

Getting a Single Row Column Value

扫描表格

scan命令用于扫描一个表,以获取表中的所有数据。可选地,可以提供扫描仪规范的字典,这在下面的命令中省略了。

scan 'wlslog'

每行的行➤列数据得到输出,如图 10-11 所示。

A978-1-4842-1830-3_10_Fig11_HTML.jpg

图 10-11。

Scanning a HBase Table

7 行数据得到如图 10-12 所示的输出。

A978-1-4842-1830-3_10_Fig12_HTML.jpg

图 10-12。

Output from the scan Command

阻止 CDH

要停止 Docker 容器,请对“cdh”容器运行docker stop命令。

sudo docker stop cdh

或者,可以指定容器 id。

sudo docker stop  86f0cfoa5c8d

摘要

在这一章中,我们使用了一个 Docker 镜像来运行 Docker 容器中的 CDH 框架。我们启动了一个交互式终端,并在 tty 中启动了一个 HBase shell。在 HBase shell 中,我们使用了create命令来创建一个表。我们使用put命令将数据放入表中。随后,我们使用get命令来添加数据。我们还运行了scan命令来扫描整个表并列出表中的所有数据。在下一章,我们将在 Docker 容器中运行 Apache Sqoop。

十一、使用 Apache Sqoop

Apache Sqoop 是一个 Hadoop 生态系统框架,用于将批量数据从关系数据库(RDBMS)传输到 Hadoop 分布式文件系统(HDFS)、Apache HBase 和 Apache Hive。Sqoop 还支持从 HDFS 到 RDBMS 的批量数据传输。Sqoop 支持的直接数据传输路径如图 11-1 所示。Sqoop 支持 HSQLDB(版本 1.8.0 以上)、MySQL(版本 5.0 以上)、Oracle(版本 10.2.0)和 PostgreSQL(版本 8.3 以上),也可以用于其他关系数据库,如 IBM DB2 数据库和版本。Sqoop 使用 JDBC 进行数据传输,并且要求安装 Java,JDBC 驱动程序 jar 位于运行时类路径中。

A978-1-4842-1830-3_11_Fig1_HTML.jpg

图 11-1。

Direct Transfer Paths supported by Sqoop

在本章中,我们将使用 Apache Sqoop 从 MySQL 数据库导入数据到 HDFS。我们还将从 HDFS 导出数据回 MySQL 数据库表。

  • 设置环境
  • 启动 Docker 容器
  • 启动交互式终端
  • 创建 MySQL 表
  • 将 MySQL JDBC Jar 添加到 Sqoop 类路径
  • 配置 Apache Hadoop
  • 用 Sqoop 将 MySQL 表数据导入 HDFS
  • 导入 HDFS 的列表数据
  • 用 Sqoop 从 HDFS 导出到 MySQL
  • 查询导出的数据
  • 停止和移除 Docker 容器

设置环境

本章需要以下软件。

  • -Docker 引擎(版本 1.8)
  • MySQL 数据库的 Docker 映像
  • cdh 的坞站映像

SSH 连接到 Amazon EC2 实例。

ssh -i "docker.pem" ec2-user@54.175.13.99

如果尚未安装 Docker,则按照第一章所述安装 Docker。启动 Docker 服务,并验证 Docker 是否已经启动。

sudo service docker start

sudo service docker status

下载jdk-8u65-linux-x64.gz。甲骨文。com/tech network/Java/javase/downloads/JDK 8-downloads-2133151。html 。由于 JDK 下载需要 BSD 许可才能被接受,使用wget或类似软件下载文件会使下载命令成为非标准命令。使用浏览器下载jdk-8u65-linux-x64.gz,并使用如下的scp命令复制到 EC2 实例。

scp -i "docker.pem" /jdk-8u65-linux-x64.gz ec2-user@54.175.13.99:/

我们需要为本章下载两个 Docker 映像,因为 CDH 的 Docker 映像包括 Apache Sqoop,但不包括 MySQL Server。使用 docker pull 命令下载mysql Docker 映像。

sudo docker pull mysql

下载 svds/cdh 坞站映像。

sudo docker pull svds/cdh

docker images命令列出 Docker 映像。

sudo docker images

mysqlsvds/cdh Docker 映像都应该被列出,如图 11-2 所示。

A978-1-4842-1830-3_11_Fig2_HTML.jpg

图 11-2。

Listing Docker Images Required for Apache Sqoop with MySQL Database

启动 Docker 容器

mysql 和 svds/cdh Docker 映像已经在前面的章节中分别讨论过,并用于启动 Docker 容器。但是,使用两个 Docker 映像略有不同,需要链接两个 Docker 容器。在本节中,我们将启动两个独立的 Docker 容器:cdh用于cdh Docker 映像,而mysqldb用于mysql Docker 映像。对于mysqldb容器,为 MySQL 存储的数据创建一个目录,并将其权限设置为 global (777)。

sudo mkdir -p /mysql/data

sudo chmod -R 777 /mysql/data

前面的命令将在连接到 Amazon EC2 实例时运行,如图 11-3 所示。

A978-1-4842-1830-3_11_Fig3_HTML.jpg

图 11-3。

Creating Directory for MySQL Data

下表讨论了docker run命令中使用的环境变量,表 11-1 。

表 11-1。

Environment Variables for a Docker container based on mysql Docker Image

| 环境变量 | 描述 | 价值 | | --- | --- | --- | | MYSQL _ 数据库 | 要创建的 MySQL 数据库实例。 | mysqldb | | MYSQL_USER | 创建的数据库的用户名。 | 关系型数据库 | | MYSQL_PASSWORD | 创建的数据库的密码。 | 关系型数据库 | | MYSQL _ ALLOW _ EMPTY _ 密码 | 是否允许空密码。 | 不 | | MYSQL _ ROOT _ 密码 | “root”用户的密码。 | 关系型数据库 |

运行下面的docker run命令来启动 MySQL 数据库的 Docker 容器。环境变量只在docker run命令中设置,而不在 bash shell 中设置。

sudo docker run -v /mysql/data:/var/lib/mysql --name mysqldb -e MYSQL_DATABASE='mysqldb' -e MYSQL_USER='mysql' -e MYSQL_PASSWORD='mysql' -e MYSQL_ALLOW_EMPTY_PASSWORD='no' -e MYSQL_ROOT_PASSWORD='mysql' -d mysql

运行下面的docker run命令来启动 svds/cdh 映像软件的 Docker 容器,它包括 Apache Sqoop,并使用--link命令参数将该容器与运行 MySQL 数据库的mysqldb容器链接起来。

sudo docker run  -d --name cdh --link mysqldb svds/cdh

列出正在运行的 Docker 容器。

sudo docker ps

前面命令的输出如图 11-4 所示。cdh 和 mysqldb 容器都被列为已启动。

A978-1-4842-1830-3_11_Fig4_HTML.jpg

图 11-4。

Starting Docker Containers for CDH and MySQL

启动交互式终端

启动 Docker 容器后,为每个 Docker 容器启动交互终端(tty)。使用以下命令启动 mysqldb 容器的交互式 shell。

sudo docker exec -it mysqldb bash

使用以下命令启动 cdh 容器的交互式 shell。

sudo docker exec -it cdh bash

创建 MySQL 表

在本节中,我们将登录 MySQL CLI 并创建一个数据库表,该表将通过 Apache Sqoop 导入 HDFS。运行以下命令登录 MySQL CLI。

mysql –u mysql –p

出现如图 11-5 所示的mysql>提示。

A978-1-4842-1830-3_11_Fig5_HTML.jpg

图 11-5。

Starting the MySQL CLI Shell

将数据库设置为“mysqldb”。

use mysqldb

使用GRANT选项将mysqldb数据库上的所有权限授予mysql用户。

GRANT ALL PRIVILEGES ON mysqldb.* TO 'mysql'@'%' IDENTIFIED BY 'mysql' WITH GRANT OPTION;

mysqldb数据库上设置权限,如图 11-6 所示。

A978-1-4842-1830-3_11_Fig6_HTML.jpg

图 11-6。

Setting Privileges on mysqldb Database

接下来,创建一个名为wlslog的数据库表,其中包含列time_stampcategorytypeservernamecodemsgPRIMARY KEY栏需要包含在sqoop import工具中,以便将数据导入 HDFS。在 MySQL CLI 中运行以下 SQL 命令。

CREATE TABLE wlslog(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255), code VARCHAR(255),msg VARCHAR(255));

名为wlslog的数据库表被创建,如图 11-7 所示。

A978-1-4842-1830-3_11_Fig7_HTML.jpg

图 11-7。

Creating a MySQL Database Table

wlslog表添加数据。运行下面的INSERT SQL 语句将数据添加到wlslog表中。

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:16-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STANDBY');

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:17-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to STARTING');

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:18-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to ADMIN');

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:19-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RESUMING');

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:20-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000361','Started WebLogic AdminServer');

INSERT INTO wlslog(time_stamp,category,type,servername,code,msg) VALUES('Apr-8-2014-7:06:21-PM-PDT','Notice','WebLogicServer','AdminServer','BEA-000365','Server state changed to RUNNING');

前面 SQL 语句的输出如图 11-8 所示。

A978-1-4842-1830-3_11_Fig8_HTML.jpg

图 11-8。

Running INSERT SQL Statements

运行以下 SQL 查询来列出添加的数据。

SELECT * FROM wlslog;

如图 11-9 所示,列出 6 行数据。

A978-1-4842-1830-3_11_Fig9_HTML.jpg

图 11-9。

Running a SQL Query

我们需要为sqoop export工具创建另一个数据库表,将数据从 HDFS 导出到 MySQL 数据库。因为wlslog表已经有数据,所以创建另一个名为WLSLOG_COPY的表,它与wlslog表有相同的表定义。在 MySQL CLI 中运行以下 SQL 脚本。

CREATE TABLE WLSLOG_COPY(time_stamp VARCHAR(255) PRIMARY KEY,category VARCHAR(255),type VARCHAR(255),servername VARCHAR(255), code VARCHAR(255),msg VARCHAR(255));

WLSLOG_COPY表被创建,如图 11-10 所示。

A978-1-4842-1830-3_11_Fig10_HTML.jpg

图 11-10。

Creating MySQL Table WLSLOG_COPY

将 MySQL JDBC Jar 添加到 Sqoop 类路径

我们需要将 MySQL JDBC jar 添加到 Apache Sqoop 类路径中。启动 cdh 容器的交互式终端(如果尚未启动)。

sudo docker exec -it cdh bash

在交互式 shell 中,下载 MySQL-connector-Java-5 . 1 . 37 . jar,并将 jar 复制到/usr/lib/sqoop/lib 目录。

wgethttp://central.maven.org/maven2/mysql/mysql-connector-java/5.1.37/mysql-connector-java-5.1.37.jar

cp mysql-connector-java-5.1.37.jar /usr/lib/sqoop/lib

前面命令的输出如图 11-11 所示。

A978-1-4842-1830-3_11_Fig11_HTML.jpg

图 11-11。

Adding MySQL JDBC Jar to Sqoop Classpath

设置 JAVA_HOME 环境变量

为了运行 Apache Sqoop,我们需要设置JAVA_HOME环境变量。但是,首先我们需要将 jdk-8u65-linux-x64.gz 文件复制到运行包括 Apache Sqoop 在内的 CDH 框架的 Docker 容器中。我们之前下载了 jdk-8u65-linux-x64.gz。使用以下命令将 jdk-8u65-linux-x64.gz 文件复制到 Docker 容器,其中容器 id 从图 11-12 中的docker ps命令的输出中获得。

sudo docker cp jdk-8u65-linux-x64.gz 49d774f8f1fe:/jdk-8u65-linux-x64.gz

jdk-8u65-linux-x64.gz 文件被复制到 Docker 容器“cdh”中,如图 11-12 所示。

A978-1-4842-1830-3_11_Fig12_HTML.jpg

图 11-12。

Copying the JDK gz File to Docker Container

前面的命令将从 Amazon EC2 实例中运行。启动 cdh 容器的交互式 shell。

sudo docker exec -it cdh bash

使用以下命令列出 Docker 容器根目录中的文件。

ls –l

jdk-8u65-linux-x64.gz 文件被列出,如图 11-13 所示。

A978-1-4842-1830-3_11_Fig13_HTML.jpg

图 11-13。

Listing the files in Docker Container’s root Directory

提取 jdk-8u65-linux-x64.gz 文件。

tar -xv jdk-8u65-linux-x64.gz

那个。gz 文件被提取,如图 11-14 所示。

A978-1-4842-1830-3_11_Fig14_HTML.jpg

图 11-14。

Extracting the JDK .gz File

我们需要在hadoop-env.sh文件中设置JAVA_HOME环境变量。要找到hadoop-env.sh文件的目录,运行以下命令。

find –name hadoop-env.sh

包含hadoop-env.sh文件的不同目录被列出,如图 11-15 所示。

A978-1-4842-1830-3_11_Fig15_HTML.jpg

图 11-15。

Finding the hadoop-env.sh File

在 vi 编辑器中打开./etc/hadoop/conf.psuedo/hadoop-env.sh文件,并添加下面的export语句。

export JAVA_HOME=./jdk1.8.0_65

hadoop-env.sh文件中的前述语句如图 11-16 所示。用:wq命令保存文件。

A978-1-4842-1830-3_11_Fig16_HTML.jpg

图 11-16。

Setting the JAVA_HOME Environment Variable

配置 Apache Hadoop

Apache Hadoop MapReduce 框架可以在三种模式下启动:localclassicyarn。在“本地”模式下,MapReduce 在 Java 进程中运行。在经典模式下,MapReduce 使用 MapReduce1 框架运行。在 yarn 模式下,MapReduce 使用 MapReduce2 框架(也称为 YARN)运行。要使用的 MapReduce 框架是在mapred-site.xml配置文件的mapreduce.framework.name设置中设置的,该文件与hadoop-env.sh./etc/hadoop/conf.psuedo目录在同一个目录下。因为 yarn 和 classic 框架需要比本地更多的内存,所以将mapreduce.framework.name设置为本地。

<property>

<name>mapreduce.framework.name</name>

<value>local</value>

</property>

mapreduce.framework.name设置如图 11.17 所示。

A978-1-4842-1830-3_11_Fig17_HTML.jpg

图 11-17。

Setting the MapReduce Framework to local

同时在hdfs-site.xml配置文件中设置以下(表 11-2 )配置属性。

表 11-2。

Configuration Properties for hdfs-site.xml

| 配置属性 | 描述 | 价值 | | --- | --- | --- | | dfs.permissions .超级用户组 | 设置超级用户组 | 大数据 | | dfs . namenode . name . dir | 设置 NameNode 存储目录 | file:///data/1/dfs/nn | | dfs.replication | 设置复制级别 | one | | dfs .权限 | 是否要检查权限 | 错误的 |

下面列出了hdfs-site.xml配置设置。

<configuration>

<property>

<name>dfs.permissions.superusergroup</name>

<value>hadoop</value>

</property>

<property>

<name>dfs.namenode.name.dir</name>

<value>file:///data/1/dfs/nn</value>

</property>

<property>

<name>dfs.replication</name>

<value>1</value>

</property>

<property>

<name>dfs.permissions</name>

<value>false</value>

</property>

</configuration>

hdfs-site.xml配置文件如图 11-18 所示。

A978-1-4842-1830-3_11_Fig18_HTML.jpg

图 11-18。

The hdfs-site.xml Configuration File

我们需要在dfs.namenode.name.dir属性中创建 NameNode 存储目录集。创建/data/1/dfs/nn目录并将其权限设置为全局(777)。

sudo mkdir -p /data/1/dfs/nn

sudo chmod -R 777 /data/1/dfs/nn

创建用户组hadoop和用户hadoop

groupadd hadoop

useradd hadoop

我们需要在core-site.xml文件中设置以下(表 11-3 )配置属性。

表 11-3。

Configuration Properties for core-site.xml

| 配置属性 | 描述 | 价值 | | --- | --- | --- | | fs.defaultfs(默认设置) | URI 这个名字 | hdfs://localhost:8020 | | hadoop.tmp.dir | Hadoop 临时目录 | file:///var/lib/Hadoop-0.20/cache |

列出了core-site.xml配置设置:

<configuration>

<property>

<name>fs.defaultFS</name>

<value>hdfs://10.0.2.15:8020</value>

</property>

<property>

<name>hadoop.tmp.dir</name>

<value>file:///var/lib/hadoop-0.20/cache</value>

</property>

</configuration>

core-site.xml文件如图 11-19 所示。用:wq保存文件。

A978-1-4842-1830-3_11_Fig19_HTML.jpg

图 11-19。

The core-site.xml Configuration File

hadoop.tmp.dir目录中创建目录集,并将其权限设置为全局(777)。

mkdir -p /var/lib/hadoop-0.20/cache

chmod -R 777  /var/lib/hadoop-0.20/cache

我们还需要使用下面的命令将 HDFS 的/目录的权限设置为 global (777)。

sudo -u hdfs hdfs dfs -chmod 777 /

用 Sqoop 将 MySQL 表数据导入 HDFS

在本节中,我们将使用sqoop import命令将 MySQL 数据库表数据导入到 HDFS。通过从 cdh 容器的交互 shell 中运行sqoop help命令,可以列出 sqoop 工具支持的不同命令,如图 11-20 所示。import命令用于将一个表从关系数据库导入到 HDFS。

A978-1-4842-1830-3_11_Fig20_HTML.jpg

图 11-20。

Running the sqoop help Command

运行sqoop import命令需要生成访问关系数据库的代码。代码可以在运行sqoop import命令时直接生成,也可以在使用sqoop codegen命令运行sqoop import命令之前生成。运行下面的sqoop codegen命令来生成与数据库记录交互的代码。

sudo -u hdfs sqoop codegen --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql" --table "wlslog"

–u hdfs 将用户指定为hdfs。命令参数在表 11-4 中讨论。

表 11-4。

Command Parameters for the hdfs Command

| 参数 | 描述 | 价值 | | --- | --- | --- | | -连接 | 连接到 MySQL 数据库的连接 url。主机名是运行 MySQL 的容器 id。 | " JDBC:MySQL://e 414 F8 c41 d0s had:3306/mysqldb " | | -密码 | 连接 MySQL 的密码。建议使用非 root 用户。 | " mysql " | | -用户名 | 连接到 MySQL 的用户名。 | " mysql " | | -桌子 | 要从中导入的 MySQL 表 | " wlslog " |

与数据库交互所需的代码在wlslog.jar文件中生成,如图 11-21 所示。

A978-1-4842-1830-3_11_Fig21_HTML.jpg

图 11-21。

Output from the codegen Command

接下来,以用户hdfs的身份运行sqoop import命令。用–libjars选项在类路径中添加wlslog.jar文件。

sudo -u hdfs sqoop import -libjars /tmp/sqoop-hdfs/compile/6348ef9539c8ad2bee9ba1875a62c923/wlslog.jar  --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql" --table "wlslog" --columns "time_stamp,category,type,servername,code,msg" --target-dir "/mysql/import" –verbose

其他命令参数在表 11-5 中讨论。

表 11-5。

Command Parameters for sqoop import

| 参数 | 描述 | 价值 | | --- | --- | --- | | -连接 | 连接到 MySQL 数据库的连接 url。主机名是运行 MySQL 的容器 id。 | " JDBC:MySQL://e 414 F8 c41 d0s had:3306/mysqldb " | | -密码 | 连接 MySQL 的密码。建议使用非 root 用户。 | " mysql " | | -用户名 | 连接到 MySQL 的用户名。 | " mysql " | | -列 | 要导入的列 | 时间戳,类别,类型,服务器名,代码,消息 | | -桌子 | 要从中导入的 MySQL 表 | " wlslog " | | -目标方向 | 要导入的 HDFS 目录 | "/mysql/import " |

sqoop import命令的输出如图 11-22 所示。

A978-1-4842-1830-3_11_Fig22_HTML.jpg

图 11-22。

Output from sqoop import

sqoop import命令的详细输出如下:

root@08b338cb2a90:/# sudo -u hdfs sqoop import -libjars /tmp/sqoop-hdfs/compile/6348ef9539c8ad2bee9ba1875a62c923/wlslog.jar  --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql" --table "wlslog" --columns "time_stamp,category,type,servername,code,msg" --target-dir "/mysql/import" -verbose

15/10/22 00:07:07 INFO sqoop.Sqoop: Running Sqoop version: 1.4.5-cdh5.4.3

ConnManager

15/10/22 00:07:10 INFO tool.CodeGenTool: Beginning code generation

15/10/22 00:07:10 DEBUG manager.SqlManager: Execute getColumnInfoRawQuery : SELECT t.* FROM wlslog AS t LIMIT 1

15/10/22 00:07:10 DEBUG manager.SqlManager: No connection paramenters specified. Using regular API for making connection.

15/10/22 00:07:11 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648

15/10/22 00:07:11 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM wlslog AS t LIMIT 1

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column time_stamp of type [12, 255, 0]

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column category of type [12, 255, 0]

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column type of type [12, 255, 0]

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column servername of type [12, 255, 0]

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column code of type [12, 255, 0]

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column msg of type [12, 255, 0]

15/10/22 00:07:11 DEBUG orm.ClassWriter: selected columns:

15/10/22 00:07:11 DEBUG orm.ClassWriter:   time_stamp

15/10/22 00:07:11 DEBUG orm.ClassWriter:   category

15/10/22 00:07:11 DEBUG orm.ClassWriter:   type

15/10/22 00:07:11 DEBUG orm.ClassWriter:   servername

15/10/22 00:07:11 DEBUG orm.ClassWriter:   code

15/10/22 00:07:11 DEBUG orm.ClassWriter:   msg

15/10/22 00:07:11 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648

15/10/22 00:07:11 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM wlslog AS t LIMIT 1

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column time_stamp of type VARCHAR

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column category of type VARCHAR

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column type of type VARCHAR

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column servername of type VARCHAR

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column code of type VARCHAR

15/10/22 00:07:11 DEBUG manager.SqlManager: Found column msg of type VARCHAR

15/10/22 00:07:11 DEBUG orm.ClassWriter: Writing source file: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.java

15/10/22 00:07:11 DEBUG orm.ClassWriter: Table name: wlslog

15/10/22 00:07:11 DEBUG orm.ClassWriter: Columns: time_stamp:12, category:12, type:12, servername:12, code:12, msg:12,

15/10/22 00:07:11 DEBUG orm.ClassWriter: sourceFilename is wlslog.java

15/10/22 00:07:11 DEBUG orm.CompilationManager: Found existing /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/

15/10/22 00:07:11 INFO orm.CompilationManager: HADOOP_MAPRED_HOME is /usr/lib/hadoop-mapreduce

15/10/22 00:07:11 DEBUG orm.CompilationManager: Returning jar file path /usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core.jar:/usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core-2.6.0-cdh5.4.3.jar

15/10/22 00:07:17 DEBUG orm.CompilationManager: Could not rename /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.java to /./wlslog.java

15/10/22 00:07:17 INFO orm.CompilationManager: Writing jar file: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.jar

15/10/22 00:07:17 DEBUG orm.CompilationManager: Scanning for .class files in directory: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468

15/10/22 00:07:17 DEBUG orm.CompilationManager: Got classfile: /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.class -> wlslog.class

15/10/22 00:07:17 DEBUG orm.CompilationManager: Finished writing jar file /tmp/sqoop-hdfs/compile/3c3425a2eecf819af8fe8f4eabd40468/wlslog.jar

15/10/22 00:07:17 WARN manager.MySQLManager: It looks like you are importing from mysql.

15/10/22 00:07:17 WARN manager.MySQLManager: This transfer can be faster! Use the --direct

15/10/22 00:07:17 WARN manager.MySQLManager: option to exercise a MySQL-specific fast path.

15/10/22 00:07:17 INFO manager.MySQLManager: Setting zero DATETIME behavior to convertToNull (mysql)

15/10/22 00:07:17 DEBUG manager.MySQLManager: Rewriting connect string to jdbc:mysql://e414f8c41d0b:3306/mysqldb?zeroDateTimeBehavior=convertToNull

15/10/22 00:07:17 DEBUG manager.CatalogQueryManager: Retrieving primary key for table 'wlslog' with query SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'wlslog' AND COLUMN_KEY = 'PRI'

15/10/22 00:07:17 DEBUG manager.CatalogQueryManager: Retrieving primary key for table 'wlslog' with query SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'wlslog' AND COLUMN_KEY = 'PRI'

15/10/22 00:07:17 INFO mapreduce.ImportJobBase: Beginning import of wlslog

15/10/22 00:07:17 INFO Configuration.deprecation: mapred.job.tracker is deprecated. Instead, use mapreduce.jobtracker.address

15/10/22 00:07:17 INFO Configuration.deprecation: mapred.jar is deprecated. Instead, use mapreduce.job.jar

15/10/22 00:07:17 DEBUG db.DBConfiguration: Securing password into job credentials store

15/10/22 00:07:17 DEBUG mapreduce.DataDrivenImportJob: Using table class: wlslog

15/10/22 00:07:17 DEBUG mapreduce.DataDrivenImportJob: Using InputFormat: class com.cloudera.sqoop.mapreduce.db.DataDrivenDBInputFormat

15/10/22 00:07:18 INFO Configuration.deprecation: mapred.map.tasks is deprecated. Instead, use mapreduce.job.maps

15/10/22 00:07:19 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=

15/10/22 00:07:20 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:07:20 INFO db.DBInputFormat: Using read commited transaction isolation

15/10/22 00:07:20 DEBUG db.DataDrivenDBInputFormat: Creating input split with lower bound '1=1' and upper bound '1=1'

15/10/22 00:07:20 INFO mapreduce.JobSubmitter: number of splits:1

15/10/22 00:07:21 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_local2065078437_0001

15/10/22 00:07:25 INFO mapreduce.Job: The url to track the job: http://localhost:8080/

15/10/22 00:07:25 INFO mapreduce.Job: Running job: job_local2065078437_0001

15/10/22 00:07:25 INFO mapred.LocalJobRunner: OutputCommitter set in config null

15/10/22 00:07:25 INFO output.FileOutputCommitter: File Output Committer Algorithm version is 1

15/10/22 00:07:25 INFO mapred.LocalJobRunner: OutputCommitter is org.apache.hadoop.mapreduce.lib.output.FileOutputCommitter

15/10/22 00:07:26 INFO mapred.LocalJobRunner: Waiting for map tasks

15/10/22 00:07:26 INFO mapred.LocalJobRunner: Starting task: attempt_local2065078437_0001_m_000000_0

15/10/22 00:07:26 INFO output.FileOutputCommitter: File Output Committer Algorithm version is 1

15/10/22 00:07:26 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]

15/10/22 00:07:26 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:07:26 INFO db.DBInputFormat: Using read commited transaction isolation

15/10/22 00:07:26 INFO mapred.MapTask: Processing split: 1=1 AND 1=1

15/10/22 00:07:26 DEBUG db.DataDrivenDBInputFormat: Creating db record reader for db product: MYSQL

15/10/22 00:07:26 INFO mapreduce.Job: Job job_local2065078437_0001 running in uber mode : false

15/10/22 00:07:26 INFO mapreduce.Job:  map 0% reduce 0%

15/10/22 00:07:27 INFO db.DBRecordReader: Working on split: 1=1 AND 1=1

15/10/22 00:07:27 DEBUG db.DataDrivenDBRecordReader: Using query: SELECT time_stamp, category, type, servername, code, msgFROMwlslogASwlslog WHERE ( 1=1 ) AND ( 1=1 )

15/10/22 00:07:27 DEBUG db.DBRecordReader: Using fetchSize for next query: -2147483648

15/10/22 00:07:27 INFO db.DBRecordReader: Executing query: SELECT time_stamp, category, type, servername, code, msgFROMwlslogASwlslog WHERE ( 1=1 ) AND ( 1=1 )

15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.

15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown…

15/10/22 00:07:27 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false

15/10/22 00:07:27 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.

15/10/22 00:07:27 INFO mapred.LocalJobRunner:

15/10/22 00:07:27 INFO mapred.Task: Task:attempt_local2065078437_0001_m_000000_0 is done. And is in the process of committing

15/10/22 00:07:27 INFO mapred.LocalJobRunner:

15/10/22 00:07:27 INFO mapred.Task: Task attempt_local2065078437_0001_m_000000_0 is allowed to commit now

15/10/22 00:07:27 INFO output.FileOutputCommitter: Saved output of task 'attempt_local2065078437_0001_m_000000_0' to hdfs://localhost:8020/mysql/import/_temporary/0/task_local2065078437_0001_m_000000

15/10/22 00:07:27 INFO mapred.LocalJobRunner: map

15/10/22 00:07:27 INFO mapred.Task: Task 'attempt_local2065078437_0001_m_000000_0' done.

15/10/22 00:07:27 INFO mapred.LocalJobRunner: Finishing task: attempt_local2065078437_0001_m_000000_0

15/10/22 00:07:27 INFO mapred.LocalJobRunner: map task executor complete.

15/10/22 00:07:28 INFO mapreduce.Job:  map 100% reduce 0%

15/10/22 00:07:28 INFO mapreduce.Job: Job job_local2065078437_0001 completed successfully

15/10/22 00:07:28 INFO mapreduce.Job: Counters: 23

File System Counters

FILE: Number of bytes read=17796154

FILE: Number of bytes written=18238016

FILE: Number of read operations=0

FILE: Number of large read operations=0

FILE: Number of write operations=0

HDFS: Number of bytes read=0

HDFS: Number of bytes written=615

HDFS: Number of read operations=4

HDFS: Number of large read operations=0

HDFS: Number of write operations=3

Map-Reduce Framework

Map input records=6

Map output records=6

Input split bytes=87

Spilled Records=0

Failed Shuffles=0

Merged Map outputs=0

GC time elapsed (ms)=306

CPU time spent (ms)=0

Physical memory (bytes) snapshot=0

Virtual memory (bytes) snapshot=0

Total committed heap usage (bytes)=138571776

File Input Format Counters

Bytes Read=0

File Output Format Counters

Bytes Written=615

15/10/22 00:07:28 INFO mapreduce.ImportJobBase: Transferred 615 bytes in 9.6688 seconds (63.6064 bytes/sec)

15/10/22 00:07:28 INFO mapreduce.ImportJobBase: Retrieved 6 records.

root@08b338cb2a90:/#

导入 HDFS 的列表数据

要在/mysql/import目录中列出用sqoop import工具生成的文件,运行以下命令。

sudo -u hdfs hdfs dfs -ls /mysql/import

列出两个文件:_SUCCESS,表示sqoop import命令成功完成,part-m-00000,导入数据如图 11-23 所示。

A978-1-4842-1830-3_11_Fig23_HTML.jpg

图 11-23。

Listing Files Generated by sqoop import

用以下命令列出数据文件part-m-00000中的数据。

sudo -u hdfs hdfs dfs -cat /mysql/import/part-m-00000

sqoop import工具导入的数据如图 11-24 所示。

A978-1-4842-1830-3_11_Fig24_HTML.jpg

图 11-24。

Listing Data imported by Sqoop

用 Sqoop 从 HDFS 导出到 MySQL

接下来,我们将把导入 HDFS 的数据导出回 MySQL 数据库。一般来说,sqoop export工具将一组文件从 HDFS 导出回 RDBMS,其中目标表已经存在于数据库中,输入文件将被读取并根据“用户指定”值中指定的分隔符解析成一组记录。

与数据库交互所需的代码可在sqoop export命令期间或在sqoop export命令之前生成。我们将在使用sqoop codegen命令运行sqoop export命令之前生成代码,如下所示。

sudo -u hdfs sqoop codegen --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql" --table "WLSLOG_COPY"

命令参数与在sqoop import命令之前运行的sqoop codegen命令相同,除了表名是WLSLOG_COPY而不是wlslogsqoop export命令所需的代码在WLSLOG_COPY.jar文件中生成,如图 11-25 所示。

A978-1-4842-1830-3_11_Fig25_HTML.jpg

图 11-25。

Running the sqoop codegen Command

接下来,运行sqoop export命令,用–libjars选项将WLSLOG_COPY.jar添加到类路径中。除了–table为“WLSLOG_COPY”和用--export-dir选项代替--target-dir外,其他命令参数与sqoop import命令相同。--export-dir选项中的目录应与sqoop import命令的--data-dir选项中的目录相同。

sudo -u hdfs sqoop export  -libjars /tmp/sqoop-hdfs/compile/047d0687acbb2298370a7b461cdfdd2e/WLSLOG_COPY.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql"  --export-dir "/mysql/import" --table "WLSLOG_COPY"   --verbose

sqoop export命令的输出如图 11-26 所示。

A978-1-4842-1830-3_11_Fig26_HTML.jpg

图 11-26。

Output from the sqoop export command

sqoop export命令的详细输出如下:

root@08b338cb2a90:/# sudo -u hdfs sqoop export  -libjars /tmp/sqoop-hdfs/compile/047d0687acbb2298370a7b461cdfdd2e/WLSLOG_COPY.jar --connect "jdbc:mysql://e414f8c41d0b:3306/mysqldb"   --password "mysql" --username "mysql"  --export-dir "/mysql/import" --table "WLSLOG_COPY"   --verbose

15/10/22 00:13:52 INFO sqoop.Sqoop: Running Sqoop version: 1.4.5-cdh5.4.3

15/10/22 00:13:54 INFO tool.CodeGenTool: Beginning code generation

15/10/22 00:13:54 DEBUG manager.SqlManager: Execute getColumnInfoRawQuery : SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1

15/10/22 00:13:54 DEBUG manager.SqlManager: No connection paramenters specified. Using regular API for making connection.

15/10/22 00:13:55 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648

15/10/22 00:13:55 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column time_stamp of type [12, 255, 0]

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column category of type [12, 255, 0]

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column type of type [12, 255, 0]

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column servername of type [12, 255, 0]

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column code of type [12, 255, 0]

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column msg of type [12, 255, 0]

15/10/22 00:13:55 DEBUG orm.ClassWriter: selected columns:

15/10/22 00:13:55 DEBUG orm.ClassWriter:   time_stamp

15/10/22 00:13:55 DEBUG orm.ClassWriter:   category

15/10/22 00:13:55 DEBUG orm.ClassWriter:   type

15/10/22 00:13:55 DEBUG orm.ClassWriter:   servername

15/10/22 00:13:55 DEBUG orm.ClassWriter:   code

15/10/22 00:13:55 DEBUG orm.ClassWriter:   msg

15/10/22 00:13:55 DEBUG manager.SqlManager: Using fetchSize for next query: -2147483648

15/10/22 00:13:55 INFO manager.SqlManager: Executing SQL statement: SELECT t.* FROM WLSLOG_COPY AS t LIMIT 1

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column time_stamp of type VARCHAR

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column category of type VARCHAR

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column type of type VARCHAR

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column servername of type VARCHAR

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column code of type VARCHAR

15/10/22 00:13:55 DEBUG manager.SqlManager: Found column msg of type VARCHAR

15/10/22 00:13:55 DEBUG orm.ClassWriter: Writing source file: /tmp/sqoop-hdfs/compile/715ce1218221b63dfffd800222f863f0/WLSLOG_COPY.java

15/10/22 00:13:55 DEBUG orm.ClassWriter: Table name: WLSLOG_COPY

15/10/22 00:13:55 DEBUG orm.ClassWriter: Columns: time_stamp:12, category:12, type:12, servername:12, code:12, msg:12,

15/10/22 00:13:55 DEBUG orm.ClassWriter: sourceFilename is WLSLOG_COPY.java

15/10/22 00:13:55 DEBUG orm.CompilationManager: Found existing /tmp/sqoop-hdfs/compile/715ce1218221b63dfffd800222f863f0/

15/10/22 00:13:55 INFO orm.CompilationManager: HADOOP_MAPRED_HOME is /usr/lib/hadoop-mapreduce

15/10/22 00:13:55 DEBUG orm.CompilationManager: Returning jar file path /usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core.jar:/usr/lib/hadoop-mapreduce/hadoop-mapreduce-client-core-2.6.0-cdh5.4.3.jar

15/10/22 00:14:02 INFO mapreduce.ExportJobBase: Beginning export of WLSLOG_COPY

15/10/22 00:14:02 INFO Configuration.deprecation: mapred.job.tracker is deprecated. Instead, use mapreduce.jobtracker.address

15/10/22 00:14:02 INFO Configuration.deprecation: mapred.jar is deprecated. Instead, use mapreduce.job.jar

15/10/22 00:14:04 DEBUG mapreduce.JobBase: Using InputFormat: class org.apache.sqoop.mapreduce.ExportInputFormat

15/10/22 00:14:04 DEBUG db.DBConfiguration: Securing password into job credentials store

15/10/22 00:14:04 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=

15/10/22 00:14:06 INFO input.FileInputFormat: Total input paths to process : 1

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Target numMapTasks=4

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Total input bytes=615

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: maxSplitSize=153

15/10/22 00:14:06 INFO input.FileInputFormat: Total input paths to process : 1

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat: Generated splits:

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat:   Paths:/mysql/import/part-m-00000:0+153 Locations:08b338cb2a90:;

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat:   Paths:/mysql/import/part-m-00000:153+153 Locations:08b338cb2a90:;

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat:   Paths:/mysql/import/part-m-00000:306+153 Locations:08b338cb2a90:;

15/10/22 00:14:06 DEBUG mapreduce.ExportInputFormat:   Paths:/mysql/import/part-m-00000:459+78,/mysql/import/part-m-00000:537+78 Locations:08b338cb2a90:;

15/10/22 00:14:06 INFO mapreduce.JobSubmitter: number of splits:4

15/10/22 00:14:06 INFO Configuration.deprecation: mapred.map.tasks.speculative.execution is deprecated. Instead, use mapreduce.map.speculative

15/10/22 00:14:06 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_local1198888838_0001

15/10/22 00:14:11 INFO mapreduce.Job: The url to track the job: http://localhost:8080/

15/10/22 00:14:11 INFO mapreduce.Job: Running job: job_local1198888838_0001

15/10/22 00:14:11 INFO mapred.LocalJobRunner: OutputCommitter set in config null

15/10/22 00:14:11 INFO mapred.LocalJobRunner: OutputCommitter is org.apache.sqoop.mapreduce.NullOutputCommitter

15/10/22 00:14:11 INFO mapred.LocalJobRunner: Waiting for map tasks

15/10/22 00:14:11 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000000_0

15/10/22 00:14:11 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000

15/10/22 00:14:11 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...

15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.

15/10/22 00:14:12 INFO mapred.LocalJobRunner:

15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements

15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000000_0 is done. And is in the process of committing

15/10/22 00:14:12 INFO mapred.LocalJobRunner: map

15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000000_0' done.

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000000_0

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000001_0

15/10/22 00:14:12 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]

15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:0+153

15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000

15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...

15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.

15/10/22 00:14:12 INFO mapred.LocalJobRunner:

15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements

15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000001_0 is done. And is in the process of committing

15/10/22 00:14:12 INFO mapred.LocalJobRunner: map

15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000001_0' done.

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000001_0

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000002_0

15/10/22 00:14:12 INFO mapreduce.Job: Job job_local1198888838_0001 running in uber mode : false

15/10/22 00:14:12 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]

15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:153+153

15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000

15/10/22 00:14:12 INFO mapreduce.Job:  map 100% reduce 0%

15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...

15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.

15/10/22 00:14:12 INFO mapred.LocalJobRunner:

15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements

15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000002_0 is done. And is in the process of committing

15/10/22 00:14:12 INFO mapred.LocalJobRunner: map

15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000002_0' done.

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000002_0

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Starting task: attempt_local1198888838_0001_m_000003_0

15/10/22 00:14:12 INFO mapred.Task:  Using ResourceCalculatorProcessTree : [ ]

15/10/22 00:14:12 INFO mapred.MapTask: Processing split: Paths:/mysql/import/part-m-00000:306+153

15/10/22 00:14:12 DEBUG mapreduce.CombineShimRecordReader: ChildSplit operates on: hdfs://localhost:8020/mysql/import/part-m-00000

15/10/22 00:14:12 DEBUG db.DBConfiguration: Fetching password from job credentials store

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Instructing auto-progress thread to quit.

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Waiting for progress thread shutdown...

15/10/22 00:14:12 INFO mapreduce.AutoProgressMapper: Auto-progress thread is finished. keepGoing=false

15/10/22 00:14:12 DEBUG mapreduce.AutoProgressMapper: Progress thread shutdown detected.

15/10/22 00:14:12 INFO mapred.LocalJobRunner:

15/10/22 00:14:12 DEBUG mapreduce.AsyncSqlOutputFormat: Committing transaction of 1 statements

15/10/22 00:14:12 INFO mapred.Task: Task:attempt_local1198888838_0001_m_000003_0 is done. And is in the process of committing

15/10/22 00:14:12 INFO mapred.LocalJobRunner: map

15/10/22 00:14:12 INFO mapred.Task: Task 'attempt_local1198888838_0001_m_000003_0' done.

15/10/22 00:14:12 INFO mapred.LocalJobRunner: Finishing task: attempt_local1198888838_0001_m_000003_0

15/10/22 00:14:12 INFO mapred.LocalJobRunner: map task executor complete.

15/10/22 00:14:13 INFO mapreduce.Job: Job job_local1198888838_0001 completed successfully

15/10/22 00:14:13 INFO mapreduce.Job: Counters: 23

File System Counters

FILE: Number of bytes read=71190614

FILE: Number of bytes written=72948608

FILE: Number of read operations=0

FILE: Number of large read operations=0

FILE: Number of write operations=0

HDFS: Number of bytes read=4068

HDFS: Number of bytes written=0

HDFS: Number of read operations=86

HDFS: Number of large read operations=0

HDFS: Number of write operations=0

Map-Reduce Framework

Map input records=6

Map output records=6

Input split bytes=576

Spilled Records=0

Failed Shuffles=0

Merged Map outputs=0

GC time elapsed (ms)=0

CPU time spent (ms)=0

Physical memory (bytes) snapshot=0

Virtual memory (bytes) snapshot=0

Total committed heap usage (bytes)=576782336

File Input Format Counters

Bytes Read=0

File Output Format Counters

Bytes Written=0

15/10/22 00:14:13 INFO mapreduce.ExportJobBase: Transferred 3.9727 KB in 8.722 seconds (466.4067 bytes/sec)

15/10/22 00:14:13 INFO mapreduce.ExportJobBase: Exported 6 records.

root@08b338cb2a90:/#

查询导出的数据

从 HDFS 导出到 MySQL 后,在 MySQL CLI 中使用下面的SELECT语句查询导出的数据。

select * from WLSLOG_COPY;

导出的六行数据列表如图 11-27 所示。

A978-1-4842-1830-3_11_Fig27_HTML.jpg

图 11-27。

Querying Exported Data in WLSLOG_COPY

停止和移除 Docker 容器

要移除mysqldbcdh容器,必须首先停止容器。用docker stop命令停止mysqldb容器。

sudo docker stop mysqldb

docker rm命令移除mysqldb容器。

sudo docker rm mysqldb

mysqldb容器停止移动,如图 11-28 所示。

A978-1-4842-1830-3_11_Fig28_HTML.jpg

图 11-28。

Stopping and Removing Docker Container for MySQL Database

同样,停止并移除cdh容器。

sudo docker stop cdh

sudo docker rm cdh

cdh容器停止移动,如图 11-29 所示。

A978-1-4842-1830-3_11_Fig29_HTML.jpg

图 11-29。

Stopping and Removing Docker Container for CDH

摘要

在这一章中,我们使用 CDH 和 MySQL 数据库的 Docker 镜像来运行两个独立但链接的 Docker 容器。我们在 Docker 容器中创建了一个 MySQL 数据库,并在 CDH 容器中运行了sqoop import工具,将数据从 MySQL 导入到 HDFS。随后,我们运行sqoop export工具从 HDFS 导出到 MySQL 数据库。在下一章,我们将讨论 ApacheKafka。