OracleDB 笔记整理
1. SQL 分类
分类 | 说明 | 关键字 |
---|---|---|
DML (Data Manipulation Language) | 数据操作语言 | SELECT , INSERT , UPDATE , DELETE , MERGE |
DDL (Data Definition Language) | 数据定义语言 | CREATE , ALTER , DROP , RENAME , TRUNCATE , COMMENT |
DCL (Data Control Language) | 数据控制语言 | GRANT , REVOKE |
事务 (Transaction) | 事务控制 | COMMIT , ROLLBACK , SAVEPOINT |
2. OracleDB 构成
2.1 基本构成
OracleDB 由 Oracle实例(instance) 和 Database 构成:
- 实例(Instance) 由:
- SGA(System Global Area):内存区域
- Background Process:后台进程
- Database 由:
- 控制文件(制御ファイル)
- REDO 文件(REDO ログ)
- 数据文件(データファイル)
2.2 进程视角
除了实例中的 Background Process,还包括:
- 用户进程
- 服务器进程
- 监听进程
2.3 工具列表
安装和升级相关工具
工具名 | 用途 |
---|---|
Oracle Universal Installer (OUI) | 安装 Oracle 软件 |
Oracle Database Configuration Assistant (DBCA) | 创建数据库 |
Oracle Database Upgrade Assistant (DBUA) | 升级现有数据库到新版本 |
网络相关工具
工具名 | 用途 |
---|---|
Oracle Net Manager (netmgr) | 配置 Oracle 网络 |
Oracle Net Configuration Assistant (netca) | 配置 Oracle 网络 |
实例和数据库管理工具
工具名 | 用途 |
---|---|
Oracle Enterprise Manager (EM) | 管理 Oracle DB |
SQL*Plus | SQL 命令行工具 |
SQL Developer | 图形化数据库管理工具 |
Recovery Manager (RMAN) | 数据库备份、恢复、复原 |
Oracle Secure Backup | 备份管理 |
Data Pump | 数据库间高速数据传输 |
SQL*Loader | 外部文件数据批量导入 |
3. 安装
3.1 OUI 功能
- 显示已安装的 Oracle 软件
- 安装新软件
- 删除软件
- 查看在线帮助
- 检查安装需求
3.2 系统要求
- 内存:1GB
- SWAP:1.5GB
- 硬盘空间:
- 最小 1GB
- 一般需要 6.1GB
3.3 创建用户和组
- 软件所有者:Oracle 用户
- Oracle Inventory Group:用于管理 Oracle 软件
- DB 管理组:
OSDBA
:数据库管理员组OSOPER
:受限制的数据库管理员组
3.4 环境变量
变量名 | 说明 |
---|---|
ORACLE_BASE |
Oracle 主目录 |
ORACLE_HOME |
Oracle 软件安装位置 |
ORACLE_SID |
系统标识(实例名) |
LD_LIBRARY_PATH |
共享库路径(如 $ORACLE_HOME/lib ) |
3.5 安装脚本
脚本名 | 用途 |
---|---|
orainstRoot.sh |
生成 inventory pointer 文件 |
root.sh |
生成 oratab 并设置环境变量 (oraenv 和 coraenv ),指定 dbstart 和 dbshut 脚本 |
3.6 创建数据库(DBCA)
3.6.1 指定 Global DB 名
格式:database_name.domain_name
3.6.2 Enterprise Manager 选项
- Database Express:单数据库管理
- Cloud Control:集中管理多个数据库(需预先安装 Cloud Control)
3.6.3 存储类型
类型 | 说明 |
---|---|
文件系统 | 使用操作系统文件 |
ASM (Automatic Storage Management) | 文件存储在 ASM 磁盘组,需额外实例 |
3.6.4 数据库文件位置
- 使用模板的文件位置
- 所有数据库文件共享文件夹
- Oracle Managed Files:由 Oracle 直接管理文件
3.6.5 模板
模板包含以下信息:
- 数据库选项
- 初始化参数
- 存储属性(数据文件、表空间、控制文件、REDO 日志属性)
模板分类
模板类型 | 说明 |
---|---|
通用事务处理(默认) | 适用于 OLTP 场景 |
数据仓库 (Data Warehouse) | 适用于复杂查询和大数据处理 |
自定义模板 | 用户自定义配置 |
模板形式
形式 | 说明 |
---|---|
Sheet Template | 包含现有数据库结构和物理文件 |
Non-Sheet Template | 仅包含数据库特性 |
4. EM Express
4.1 功能
- 提供数据库管理功能(不包括启动/停止数据库)
- 如需启动/停止数据库,需使用 Oracle Enterprise Manager Cloud Control
4.2 手动配置 EM Express
- 启动监听进程
- 初始化
DISPATCHERS
参数(设置PROTOCOL=TCP
):1
dispatchers="(PROTOCOL=TCP)(SERVICE=<sid>XDB)"
- 设置端口(需
SYSDBA
权限):1
EXEC DBMS_XDB_CONFIG.setHTTPSPORT(5500);
4.3 使用 EM Express
4.3.1 查询 EM Express 端口
1 | SELECT DBMS_XDB_CONFIG.getHTTPSPort FROM DUAL; |
4.3.2 权限分配
权限 | 说明 |
---|---|
EM_EXPRESS_BASIC |
只读模式 |
EM_EXPRESS_ALL |
完全权限 |
4.4 连接数据库
4.4.1 SQL*Plus 连接方式
- 运行
oraenv
设置环境变量:1
. oraenv
- 启动 SQL*Plus(
/nolog
表示不登录数据库):1
sqlplus /nolog
- 连接数据库:
1
CONNECT <用户名>/<密码> [AS SYSDBA | AS SYSOPER]
- 其他功能:
- 执行 SQL 脚本:
1
@<sql文件名>
- 执行操作系统命令:
1
HOST <命令> # 例如:HOST ls
- 执行 SQL 脚本:
4.4.2 SQL Developer 连接方式
- 运行
oraenv
设置环境变量:1
. oraenv
- 启动 SQL Developer:
1
2cd $ORACLE_HOME/sqldeveloper
sh sqldeveloper.sh - 功能:
- 普通模式:查看、创建、编辑、删除表、视图等对象
- DBA Navigator:连接 DBA 用户后可启动/停止数据库
5. Oracle 网络构成
5.1 Oracle Net 概述
- 功能:提供网络服务
- 安装方式:随 Oracle 数据库软件或客户端一同安装
- 通信模式:
- 客户端-服务端模式:两端均需安装 Oracle Net
- 客户端-Web 服务器-DB 服务器模式:客户端和 Web 服务器需安装 Oracle Net
5.2 通信条件
角色 | 要求 |
---|---|
DB 服务端 | 1. 网络服务器在线 2. 已安装 Oracle DB 3. 支持 TCP/IP 协议 4. 监听进程已启动 |
客户端 | 1. 网络服务器在线 2. 已安装 Oracle 客户端 3. 支持 TCP/IP 协议 |
5.3 监听进程
-
自动安装:通过 OUI 初始化 DB 时,NetCA 会默认安装监听进程
-
作用:处理客户端连接请求(连接建立后不再参与通信)
-
关键命令:
命令 功能 lsnrctl start <监听进程名>
启动监听进程 lsnrctl stop <监听进程名>
停止监听进程 lsnrctl status <监听进程名>
查看状态 lsnrctl services <监听进程名>
查看支持的服务 LSNRCTL> set current_listener <名称>
切换监听进程(需交互模式)
5.4 客户端构成
- 数据库连接示例:
1
2
3CONNECT hr@(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = proj1-sv)(PORT = 1521))
(CONNECT_DATA = (SERVICE_NAME = sales.edifist.com)))
5.5 命名方法
类型 | 存储位置 | 说明 |
---|---|---|
本地命名 | 客户端 tnsnames.ora |
网络服务名映射存储在本地文件 |
LDAP 基准 | LDAP 服务器 | 集中管理服务名映射 |
简易连接命名 | 无 | 直接使用 TCP/IP 连接字符串(如 connect scott@host名/服务名 ) |
外部命名 | 第三方命名服务(如 NIS) | 依赖非 Oracle 服务 |
本地命名配置方法
1 | netca # 启动图形化配置工具 |
简易连接示例
1 | sqlplus /nolog |
6. 数据库服务器架构概要
6.1 核心组件
- Oracle 实例:内存结构(SGA) + 后台进程
- Oracle 数据库:物理文件集合
6.2 SGA (System Global Area) 构成
组件 | 功能 |
---|---|
数据库缓存 | 存储数据块(Buffer Cache) |
REDO 日志 Buffer | 记录数据变更历史 |
共享池 | 缓存 SQL/PLSQL 解析结果、执行计划、数据字典 |
Large Pool | 可选,用于共享服务器模式、并行查询、RMAN 备份等 |
Java Pool | 支持 Java 虚拟机(JVM) |
Stream Pool | 支持 Oracle Stream 数据复制 |
6.3 关键后台进程
进程 | 名称 | 功能 |
---|---|---|
SMON | System Monitor | 实例恢复(如崩溃后自动修复) |
PMON | Process Monitor | 清理异常终止的用户进程资源 |
DBWn | Database Writer | 将脏缓冲区写入数据文件 |
CKPT | Checkpoint | 触发 DBWn 写入,更新控制文件(用于灾难恢复) |
LGWR | Log Writer | 将 REDO 日志缓冲区写入磁盘 |
ARCn | Archiver | 归档 REDO 日志 |
MMON | Manageability Monitor | 执行 AWR(自动工作负载仓库)相关任务 |
6.4 用户与服务器进程
- 用户进程:运行应用程序(如 SQL*Plus)
- 服务器进程:处理用户提交的 SQL 查询
6.5 PGA (Program Global Area)
- 特点:非共享内存,仅限单个进程访问
- 用途:存储 SQL 执行时的排序区、会话信息等
7. 实例启停
7.1 启动方法
- SQL*Plus(
STARTUP
命令) - Windows 服务管理器
- SQL Developer
- Enterprise Manager Cloud Control
7.2 启动状态迁移
状态 | 描述 |
---|---|
NOMOUNT | 读取参数文件,分配 SGA,启动后台进程(控制文件未打开) |
MOUNT | 打开控制文件(获知数据文件/日志文件路径,但未打开文件) |
OPEN | 打开所有数据文件和 REDO 日志,数据库可用 |
7.3 权限要求
权限 | 能力 |
---|---|
SYSDBA | 完全控制(包括启停实例、用户授权) |
SYSOPER | 仅限启停实例(无权管理用户对象) |
连接示例
1 | CONNECT 用户名/密码 AS {SYSOPER | SYSDBA} |
7.4 停止流程
- 关闭数据库(OPEN → CLOSED)
- 执行 Checkpoint,写入数据文件和 REDO 日志
- 关闭数据文件和 REDO 日志(控制文件仍打开)
- 卸载数据库(CLOSED → DISMOUNT)
- 实例与数据库分离
- 停止实例(DISMOUNT → SHUTDOWN)
- 终止后台进程,释放 SGA 内存
7.5 停止模式对比
行为 | NORMAL | TRANSACTIONAL | IMMEDIATE | ABORT |
---|---|---|---|---|
接受新连接 | × | × | × | × |
等待当前会话结束 | ✓ | ✓ | × | × |
等待当前事务结束 | ✓ | ✓ | ✓ | × |
执行 Checkpoint 后关闭 | ✓ | ✓ | ✓ | × |
7.6 初始化参数文件
类型 | 名称 | 特点 |
---|---|---|
静态 | PFILE(文本文件) | 手动编辑,需重启生效 |
动态 | SPFILE(二进制文件) | 支持在线修改(ALTER SYSTEM ),优先使用 |
Kafka 是一种高吞吐的分布式发布订阅消息系统,能够替代传统的消息队列用于解耦合数据处理,缓存未处理消息等,同时具有更高的吞吐率,支持分区、多副本、冗余,因此被广泛用于大规模消息数据处理应用。Kafka 支持Java 及多种其它语言客户端,可与Hadoop、Storm、Spark等其它大数据工具结合使用。
环境安装
测试用例
Github 代码
代码我已放到 Github ,导入spring-boot-kafka
项目
github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-kafka
添加依赖
在项目中添加 kafka-clients
依赖
1 | <dependency> |
启用 kafka
1 | @Configuration |
消息生产者
1 | @Component |
消息消费者
1 | @Component |
参数配置
application.properties
1 | #kafka |
启动服务
1 | @SpringBootApplication |
单元测试
1 | import io.ymq.kafka.MsgProducer; |
消息生产者,响应
1 | 2017-10-17 15:54:44.814 INFO 2960 --- [ main] io.ymq.kafka.MsgProducer : 向kafka推送数据:[topic--------1] |
消息消费者,响应
1 | 消息被消费topic--------1 |
代码我已放到 Github ,导入spring-boot-kafka
项目
github https://github.com/souyunku/spring-boot-examples/tree/master/spring-boot-kafka
遇到一些坑
1 | [2017-10-16 19:20:08.340] - 14884 严重 [main] --- org.springframework.kafka.support.LoggingProducerListener: Exception thrown when sending a message with key='null' and payload='topic--------2' to topic topic-2: |
经调试发现 kafka 连接是用的主机名,所以修改 hosts
1 | C:\Windows\System32\drivers\etc\hosts |
搭建高吞吐量 Kafka 分布式发布订阅消息 集群
简介
Kafka 是一种高吞吐的分布式发布订阅消息系统,能够替代传统的消息队列用于解耦合数据处理,缓存未处理消息等,同时具有更高的吞吐率,支持分区、多副本、冗余,因此被广泛用于大规模消息数据处理应用。Kafka 支持Java 及多种其它语言客户端,可与Hadoop、Storm、Spark等其它大数据工具结合使用。
环境
Zookeeper集群: 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181
kafka 集群: 192.168.252.124 , 192.168.252.125 , 192.168.252.126
kafka-manager: 192.168.252.127
主机名修改
CentOs7.3 修改主机名
ssh 免密登录
CentOs7.3 ssh 免密登录
安装 JDK1.8
搭建 Zookeeper 集群
CentOs7.3 搭建 ZooKeeper-3.4.9 Cluster 集群服务
Zookeeper集群: 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181
主机名依次被我修改成: node1,node2,node3
搭建 kafka 集群
kafka 集群: 192.168.252.124 , 192.168.252.125 , 192.168.252.126
主机名依次被我修改成: node4,node5,node6
1.下载代码
kafka 官网下载 http://kafka.apache.org/downloads
下载最新版本的kafka ,
清华镜像:https://mirrors.tuna.tsinghua.edu.cn/apache/kafka/
阿里镜像:https://mirrors.aliyun.com/apache/kafka/
1 | $ cd /opt |
2.修改配置
在 node4 操作
1 | $ vi /opt/kafka_2.12-0.11.0.0/config/server.properties |
1 | broker.id=0 每台服务器不能重复 |
把配置复制到 node5,node6 集群
1 | $ for a in {5..6} ; do scp -r /opt/kafka_2.12-0.11.0.0/ node$a:/opt/kafka_2.12-0.11.0.0 ; done |
修改 node5,node6 集群的broker.id
1 | $ vi /opt/kafka_2.12-0.11.0.0/config/server.properties |
3.启动kafka
在 node1,启动 Kafka使用的 ZooKeeper,所以先启动ZooKeeper服务器
1 | $ for a in {1..3} ; do ssh node$a "source /etc/profile; /opt/zookeeper-3.4.9/bin/zkServer.sh start" ; done |
现在 node4 启动Kafka服务器
1 | $ for a in {4..6} ; do ssh node$a "source /etc/profile; /opt/kafka_2.12-0.11.0.0/bin/kafka-server-start.sh /opt/kafka_2.12-0.11.0.0/config/server.properties" ; done |
或者后台启动运行,日志查看去Kafka解压目录有个log
文件夹查看
1 | $ for a in {4..6} ; do ssh node$a "source /etc/profile; nohup /opt/kafka_2.12-0.11.0.0/bin/kafka-server-start.sh /opt/kafka_2.12-0.11.0.0/config/server.properties > /dev/null 2>&1 &" ; done |
查看进程,Kafka 是否启动成功
1 | $ jps |
如果报错删除
1 | kafka.common.KafkaException: Failed to acquire lock on file .lock in /tmp/kafka-logs. A Kafka instance in another process or thread is using this directory. |
4.创建主题
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-topics.sh --create --zookeeper 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181 --replication-factor 2 --partitions 1 --topic ymq |
--replication-factor 2 #复制两份
--partitions 1 #创建1个分区
--topic #主题为ymq
运行list topic命令,可以看到该主题:
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-topics.sh --list --zookeeper 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181 |
5.生产消息
Kafka附带一个命令行客户端,它将从文件或标准输入中输入,并将其作为消息发送到Kafka群集。默认情况下,每行将作为单独的消息发送。
在 node5 运行生产者,然后在控制台中输入一些消息以发送到服务器。
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic ymq |
6.消费消息
在node6 运行消费者,将把消息转储到标准输出。
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-console-consumer.sh --zookeeper 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181 --topic ymq --from-beginning |
7.topic详情
用describe 查看集群中topic每个节点情况
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-topics.sh --describe --zookeeper 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181 --topic ymq |
以下是输出的说明。第一行给出了所有分区的摘要,每个附加行提供有关一个分区的信息。由于我们这个主题只有一个分区,只有一行。
leader
负责给定分区的读取和写入分配节点编号,每个分区的部分数据会随机指定不同的节点
replicas
是复制此分区的日志的节点列表
isr
一组正在同步的副本列表
8.删除topic
1 | $ /opt/kafka_2.12-0.11.0.0/bin/kafka-topics.sh --delete --zookeeper 192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181 --topic ymq |
9.停止kafka
1 | $ for a in {4..6} ; do ssh node$a "source /etc/profile; /opt/kafka_2.12-0.11.0.0/bin/kafka-server-stop.sh /opt/kafka_2.12-0.11.0.0/config/server.properties " ; done |
部署 Kafka Manager
Yahoo开源Kafka集群管理器Kafka Manager
作为一个分布式的消息发布-订阅系统,Apache Kafka在Yahoo内部已经被很多团队所使用,例如媒体分析团队就将其应用到了实时分析流水线中,同时,Yahoo整个Kafka集群处理的峰值带宽超过了20Gbps(压缩数据)。为了让开发者和服务工程师能够更加简单地维护Kafka集群,Yahoo构建了一个基于Web的管理工具,称为Kafka Manager,日前该项目已经在GitHub上开源。
通过Kafka Manager用户能够更容易地发现集群中哪些主题或者分区分布不均匀,同时能够管理多个集群,能够更容易地检查集群的状态,能够创建主题,执行首选的副本选择,能够基于集群当前的状态生成分区分配,并基于生成的分配执行分区的重分配,此外,Kafka Manager还是一个非常好的可以快速查看集群状态的工具。
Kafka Manager使用Scala语言编写,其Web控制台基于Play Framework实现,除此之外,Yahoo还迁移了一些Apache Kafka的帮助程序以便能够与Apache Curator框架一起工作。
一、它支持以下内容:
- 管理多个群集
- 容易检查集群状态(主题,消费者,偏移量,经纪人,副本分发,分区分配)
- 运行首选副本选举
- 使用选项生成分区分配,以选择要使用的代理
- 运行分区的重新分配(基于生成的分配)
- 创建可选主题配置的主题(0.8.1.1具有不同于0.8.2+的配置)
- 删除主题(仅支持0.8.2+,并记住在代理配置中设置delete.topic.enable = true)
- 主题列表现在表示标记为删除的主题(仅支持0.8.2+)
- 批量生成多个主题的分区分配,并选择要使用的代理
- 批量运行多个主题的分区重新分配
- 将分区添加到现有主题
- 更新现有主题的配置
- 可选地,启用JMX轮询代理级和主题级度量。
- 可选地筛选出在zookeeper中没有ids / owner /&offset /目录的消费者。
源码,并编译打包
在 kafka-manager: 192.168.252.127 node7 部署
编译超级慢
1 | $ yum install git |
下载编译好的包
1 | $ yum install unzip |
修改这个 zk 地址
1 | kafka-manager.zkhosts="192.168.252.121:2181,192.168.252.122:2181,192.168.252.123:2181" |
启动 kafka-manager
默认端口 NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
1 | $ /opt/kafka-manager-1.3.2.1/bin/kafka-manager -Dconfig.file=conf/application.conf |
或者后台运行 并且配置端口
1 | $ nohup bin/kafka-manager -Dconfig.file=/home/hadoop/app/kafka-manager-1.3.2.1/conf/application.conf -Dhttp.port=9000 & |
访问: http://ip:9000
CentOs7.3 搭建 ZooKeeper-3.4.9 Cluster 集群服务
Zookeeper 概述
zookeeper实际上是yahoo开发的,用于分布式中一致性处理的框架。最初其作为研发Hadoop时的副产品。由于分布式系统中一致性处理较为困难,其他的分布式系统没有必要 费劲重复造轮子,故随后的分布式系统中大量应用了zookeeper,以至于zookeeper成为了各种分布式系统的基础组件,其地位之重要,可想而知。著名的hadoop,kafka,dubbo 都是基于zookeeper而构建。
要想理解zookeeper到底是做啥的,那首先得理解清楚,什么是一致性?
所谓的一致性,实际上就是围绕着“看见”来的。谁能看见?能否看见?什么时候看见?举个例子:淘宝后台卖家,在后台上架一件大促的商品,通过服务器A提交到主数据库,假设刚提交后立马就有用户去通过应用服务器B去从数据库查询该商品,就会出现一个现象,卖家已经更新成功了,然而买家却看不到;而经过一段时间后,主数据库的数据同步到了从数据库,买家就能查到了。
假设卖家更新成功之后买家立马就能看到卖家的更新,则称为强一致性
如果卖家更新成功后买家不能看到卖家更新的内容,则称为弱一致性
而卖家更新成功后,买家经过一段时间最终能看到卖家的更新,则称为最终一致性
环境
VMware版本号:12.0.0
CentOS版本:CentOS 7.3.1611
ZooKeeper版本:ZooKeeper-3.4.9.tar.gz
虚拟机IP:192.168.252.101,192.168.252.102,192.168.252.103
集群主机名称:node1,node2,node3
集群主机用户:都是用root用户
集群JDK环境:jdk-8u144-linux-x64.tar.gz JDK 1.8 安装 具体参考《CentOs7.3 安装 JDK1.8》
集群主机之间设置免密登陆:
注意事项
关闭防火墙
centos 6.x 关闭 iptables
1 | $ service iptables stop # 关闭命令: |
centos 7.x 关闭firewall
1 | $ systemctl stop firewalld.service # 停止firewall |
ZooKeeper 安装
1.下载ZooKeeper
下载最新版本的ZooKeeper ,我在北京我就选择,清华镜像比较快
清华镜像:https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/
阿里镜像:https://mirrors.aliyun.com/apache/zookeeper/
1 | $ cd /opt/ |
或者在浏览器下载上传至opt 目录
2.提取tar文件
1 | $ cd /opt/ |
创建data
文件夹 用于存储数据文件
1 | $ mkdir /opt/zookeeper-3.4.9/data |
创建logs
文件夹 用于存储日志
1 | $ mkdir /opt/zookeeper-3.4.9/logs |
3.创建配置文件
zoo.cfg
zookeeper的主要配置文件,因为Zookeeper是一个集群服务,集群的每个节点都需要这个配置文件。为了避免出差错,zoo.cfg这个配置文件里没有跟特定节点相关的配置,所以每个节点上的这个zoo.cfg都是一模一样的配置。这样就非常便于管理了,比如我们可以把这个文件提交到版本控制里管理起来。其实这给我们设计集群系统的时候也是个提示:集群系统一般有很多配置,应该尽量将通用的配置和特定每个服务的配置(比如服务标识)分离,这样通用的配置在不同服务之间copy就ok了
1 | $ vi /opt/zookeeper-3.4.9/conf/zoo.cfg |
编辑内容如下
1 | tickTime = 2000 |
配置文件描述
tickTime
- tickTime则是上述两个超时配置的基本单位,例如对于initLimit,其配置值为5,说明其超时时间为 2000ms * 5 = 10秒。
dataDir
- 其配置的含义跟单机模式下的含义类似,不同的是集群模式下还有一个myid文件。myid文件的内容只有一行,且内容只能为1 - 255之间的数字,这个数字亦即上面介绍server.id中的id,表示zk进程的id。
dataLogDir
- 如果没提供的话使用的则是dataDir。zookeeper的持久化都存储在这两个目录里。dataLogDir里是放到的顺序日志(WAL)。而dataDir里放的是内存数据结构的snapshot,便于快速恢复。为了达到性能最大化,一般建议把dataDir和dataLogDir分到不同的磁盘上,这样就可以充分利用磁盘顺序写的特性。
initLimit
- ZooKeeper集群模式下包含多个zk进程,其中一个进程为leader,余下的进程为follower。
当follower最初与leader建立连接时,它们之间会传输相当多的数据,尤其是follower的数据落后leader很多。initLimit配置follower与leader之间建立连接后进行同步的最长时间。
syncLimit
- 配置follower和leader之间发送消息,请求和应答的最大时间长度。
server.id=host:port1:port2
server.id
其中id为一个数字,表示zk进程的id,这个id也是data目录下myid文件的内容
host
是该zk进程所在的IP地址
port1
表示follower和leader交换消息所使用的端口
port2
表示选举leader所使用的端口
4.创建myid 文件
在data里会放置一个myid文件,里面就一个数字,用来唯一标识这个服务。这个id是很重要的,一定要保证整个集群中唯一
ZooKeeper会根据这个id来取出server.x上的配置。比如当前id为1,则对应着zoo.cfg里的server.1的配置
1 | $ echo "1" > /opt/zookeeper-3.4.9/data/myid |
这样一台node1机器就配置完了
5.复制集群配置
在集群node1 上执行,复制配置好的zookeeper到其他两台主机上
1 | $ for a in {2..3} ; do scp -r /opt/zookeeper-3.4.9/ node$a:/opt/zookeeper-3.4.9 ; done |
在集群node1 上执行 ,批量修改myid 文件
1 | $ for a in {1..3} ; do ssh node$a "source /etc/profile; echo $a > /opt/zookeeper-3.4.9/data/myid" ; done |
集群操作
在集群任意一台机器上执行
启动集群
1 | $ for a in {1..3} ; do ssh node$a "source /etc/profile; /opt/zookeeper-3.4.9/bin/zkServer.sh start" ; done |
响应
1 | ZooKeeper JMX enabled by default |
连接集群
1 | $ /opt/zookeeper-3.4.9/bin/zkCli.sh -server node1:2181,node2:2181,node3:2181 |
响应
1 | Connecting to node1:2181,node2:2181,node3:2181 |
从日志可以看出客户端成功连接的是node3 连接上哪台机器的zk进程是随机的
1 |
|
集群状态
1 | $ for a in {1..3} ; do ssh node$a "source /etc/profile; /opt/zookeeper-3.4.9/bin/zkServer.sh status" ; done |
响应
1 | ZooKeeper JMX enabled by default |
通过日志我可以看到 node2 leader (ps 是老大),其他 node1 ,node2 follower (ps 都是小弟)
Leader 怎么选举的可以参考《Zookeeper的Leader选举》
停止集群
1 | $ for a in {1..3} ; do ssh node$a "source /etc/profile; /opt/zookeeper-3.4.9/bin/zkServer.sh stop" ; done |
响应
1 | ZooKeeper JMX enabled by default |
Hive 简介
Hive 是一个基于 hadoop 的开源数据仓库工具,用于存储和处理海量结构化数据。它把海量数据存储于 hadoop 文件系统,而不是数据库,但提供了一套类数据库的数据存储和处理机制,并采用 HQL (类 SQL )语言对这些数据进行自动化管理和处理。我们可以把 Hive 中海量结构化数据看成一个个的表,而实际上这些数据是分布式存储在 HDFS 中的。 Hive 经过对语句进行解析和转换,最终生成一系列基于 hadoop 的 map/reduce 任务,通过执行这些任务完成数据处理。
Hive 诞生于 facebook 的日志分析需求,面对海量的结构化数据, Hive 以较低的成本完成了以往需要大规模数据库才能完成的任务,并且学习门槛相对较低,应用开发灵活而高效。
Hive 自 2009.4.29 发布第一个官方稳定版 0.3.0 至今,不过一年的时间,正在慢慢完善,网上能找到的相关资料相当少,尤其中文资料更少,本文结合业务对 Hive 的应用做了一些探索,并把这些经验做一个总结,所谓前车之鉴,希望读者能少走一些弯路。
准备工作
环境
1 | JDK:1.8 |
依赖环境
安装**Apache Hive
**前提是要先安装hadoop
集群,并且hive只需要在hadoop的namenode节点集群里安装即可(需要在有的namenode上安装),可以不在datanode节点的机器上安装。还需要说明的是,虽然修改配置文件并不需要把hadoop运行起来,但是本文中用到了hadoop的hdfs命令,在执行这些命令时你必须确保hadoop是正在运行着的,而且启动hive的前提也需要hadoop在正常运行着,所以建议先把hadoop集群启动起来。
安装**MySQL
** 用于存储 Hive 的元数据(也可以用 Hive 自带的嵌入式数据库 Derby,但是 Hive 的生产环境一般不用 Derby),这里只需要安装 MySQL 单机版即可,如果想保证高可用的化,也可以部署 MySQL 主从模式;
Hadoop
MySQL 随意任选其一
CentOs7.3 安装 MySQL 5.7.19 二进制版本
搭建 MySQL 5.7.19 主从复制,以及复制实现细节分析
安装
下载解压
1 | su hadoop |
环境变量
如果是对所有的用户都生效就修改vi /etc/profile
文件
如果只针对当前用户生效就修改 vi ~/.bahsrc
文件
1 | sudo vi /etc/profile |
1 | #hive |
使环境变量生效,运行 source /etc/profile
使/etc/profile
文件生效
Hive 配置 Hadoop HDFS
复制 hive-site.xml
1 | cd /home/hadoop/hive-2.3.0/conf |
新建 hdfs 目录
使用 hadoop 新建 hdfs 目录,因为在 hive-site.xml 中有默认如下配置:
1 | <property> |
进入 hadoop 安装目录 执行hadoop命令新建/user/hive/warehouse目录,并授权,用于存储文件
1 | cd /home/hadoop/hadoop-2.7.4 |
用以下命令检查目录是否创建成功
1 | bin/hadoop fs -ls /user/hive |
修改 hive-site.xml
搜索hive.exec.scratchdir,将该name对应的value修改为/user/hive/tmp
1 | <property> |
搜索hive.querylog.location,将该name对应的value修改为/user/hive/log/hadoop
1 | <property> |
搜索javax.jdo.option.connectionURL,将该name对应的value修改为MySQL的地址
1 | <property> |
搜索javax.jdo.option.ConnectionDriverName,将该name对应的value修改为MySQL驱动类路径
1 | <property> |
搜索javax.jdo.option.ConnectionUserName,将对应的value修改为MySQL数据库登录名
1 | <property> |
搜索javax.jdo.option.ConnectionPassword,将对应的value修改为MySQL数据库的登录密码
1 | <property> |
创建 tmp 文件
1 | mkdir /home/hadoop/hive-2.3.0/tmp |
并在 hive-site.xml
中修改
把{system:java.io.tmpdir}
改成 /home/hadoop/hive-2.3.0/tmp
把 {system:user.name}
改成 {user.name}
新建 hive-env.sh
1 | cp hive-env.sh.template hive-env.sh |
下载 mysql 驱动包
1 | cd /home/hadoop/hive-2.3.0/lib |
初始化 mysql
MySQL数据库进行初始化
首先确保 mysql 中已经创建 hive
库
1 | cd /home/hadoop/hive-2.3.0/bin |
如果看到如下,表示初始化成功
1 | Starting metastore schema initialization to 2.3.0 |
查看 mysql 数据库
1 | /usr/local/mysql/bin/mysql -uroot -p |
1 | mysql> show databases; |
1 | mysql> use hive; |
启动 Hive
简单测试
启动Hive
1 | cd /home/hadoop/hive-2.3.0/bin |
创建 hive 库
1 | hive> create database ymq; |
选择库
1 | hive> use ymq; |
创建表
1 | hive> create table test (mykey string,myval string); |
插入数据
1 | hive> insert into test values("1","www.ymq.io"); |
查询数据
1 | hive> select * from test; |
页面数据
在界面上查看刚刚写入的hdfs数据
环境
三台虚拟机(IP):
- 192.168.252.121
- 192.168.252.122
- 192.168.252.123
1.修改主机名
修改三台主机名,以此类推,node1,node3,node3
命令格式
1 | hostnamectl set-hostname <hostname> |
1 | sudo hostnamectl set-hostname node1 |
剩下的虚拟机依次修改hostnamectl set-hostname[1-3]
重启操作系统
1 | $ reboot |
2.修改映射关系
1.在 node1 的 /etc/hosts
文件下添加如下内容
1 | su hadoop |
2.查看修改后的/etc/hosts
文件内容
1 | $ cat /etc/hosts |
2.将集群node1 上的文件hosts
文件 通过 scp
命令复制发送到集群的每一个节点
1 | for a in {1..3} ; do sudo scp /etc/hosts hadoop@node$a:/etc/hosts ; done |
3.检查是否集群每一个节点的 hosts
文件都已经修改过来了
1 | for a in {1..3} ; do sudo ssh hadoop@node$a cat /etc/hosts ; done |
3.启动 ssh 无密登录
1.在集群node1的 /etc/ssh/sshd_config
文件去掉以下选项的注释
1 | sudo vi /etc/ssh/sshd_config |
1 | RSAAuthentication yes #开启私钥验证 |
2.将集群node1 修改后的 /etc/ssh/sshd_config
通过 scp
命令复制发送到集群的每一个节点
1 | for a in {1..3} ; do sudo scp /etc/ssh/sshd_config hadoop@node$a:/etc/ssh/sshd_config ; done |
4.生成公钥、私钥
1.在集群的每一个节点节点输入命令 ssh-keygen -t rsa -P ''
,生成 key,一律回车
1 | ssh-keygen -t rsa -P '' |
1 | Generating public/private rsa key pair. |
2.在集群的node1 节点输入命令
将集群每一个节点的公钥id_rsa.pub
放入到自己的认证文件中authorized_keys
;
1 | for a in {1..3}; do sudo ssh hadoop@node$a cat /home/hadoop/.ssh/id_rsa.pub >> /home/hadoop/.ssh/authorized_keys; done |
3.在集群的node1 节点输入命令
将自己的认证文件 authorized_keys
通过
scp 命令复制发送到每一个节点上去:
/home/hadoop/.ssh/authorized_keys`
1 | for a in {1..3}; do sudo scp /home/hadoop/.ssh/authorized_keys hadoop@node$a:/home/hadoop/.ssh/authorized_keys ; done |
4.非ROOT 用户需赋权限
1 | chmod 700 /home/hadoop/.ssh/ |
5.在集群的每一个节点节点输入命令
接重启ssh服务
1 | sudo systemctl restart sshd.service |
6.验证 ssh 无密登录
开一个其他窗口测试下能否免密登陆
例如:在node3
1 | ssh hadoop@node2 |
exit
退出
1 | [hadoop@node1 ~]# exit |
注意:开新的其他窗口测试下能否免密登陆,把当前窗口都关了
HBase 深入浅出
HBase 在大数据生态圈中的位置
提到大数据的存储,大多数人首先联想到的是 Hadoop 和 Hadoop 中的 HDFS 模块。大家熟知的 Spark、以及 Hadoop 的 MapReduce,可以理解为一种计算框架。而 HDFS,我们可以认为是为计算框架服务的存储层。因此不管是 Spark 还是 MapReduce,都需要使用 HDFS 作为默认的持久化存储层。那么 HBase 又是什么,可以用在哪里,解决什么样的问题?简单地,我们可以认为 HBase 是一种类似于数据库的存储层,也就是说 HBase 适用于结构化的存储。并且 HBase 是一种列式的分布式数据库,是由当年的 Google 公布的 BigTable 的论文而生。不过这里也要注意 HBase 底层依旧依赖 HDFS 来作为其物理存储,这点类似于 Hive。
可能有的读者会好奇 HBase 于 Hive 的区别,我们简单的梳理一下 Hive 和 HBase 的应用场景:
Hive 适合用来对一段时间内的数据进行分析查询,例如,用来计算趋势或者网站的日志。Hive 不应该用来进行实时的查询(Hive 的设计目的,也不是支持实时的查询)。因为它需要很长时间才可以返回结果;HBase 则非常适合用来进行大数据的实时查询,例如 Facebook 用 HBase 进行消息和实时的分析。对于 Hive 和 HBase 的部署来说,也有一些区别,Hive 一般只要有 Hadoop 便可以工作。而 HBase 则还需要 Zookeeper 的帮助(Zookeeper,是一个用来进行分布式协调的服务,这些服务包括配置服务,维护元信息和命名空间服务)。再而,HBase 本身只提供了 Java 的 API 接口,并不直接支持 SQL 的语句查询,而 Hive 则可以直接使用 HQL(一种类 SQL 语言)。如果想要在 HBase 上使用 SQL,则需要联合使用 Apache Phonenix,或者联合使用 Hive 和 HBase。但是和上面提到的一样,如果集成使用 Hive 查询 HBase 的数据,则无法绕过 MapReduce,那么实时性还是有一定的损失。Phoenix 加 HBase 的组合则不经过 MapReduce 的框架,因此当使用 Phoneix 加 HBase 的组成,实时性上会优于 Hive 加 HBase 的组合,我们后续也会示例性介绍如何使用两者。最后我们再提下 Hive 和 HBase 所使用的存储层,默认情况下 Hive 和 HBase 的存储层都是 HDFS。但是 HBase 在一些特殊的情况下也可以直接使用本机的文件系统。例如 Ambari 中的 AMS 服务直接在本地文件系统上运行 HBase。
HBase 与传统关系数据库的区别
首先让我们了解下什么是 ACID。ACID 是指数据库事务正确执行的四个基本要素的缩写,其包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability)。对于一个支持事务(Transaction)的数据库系统,必需要具有这四种特性,否则在事务过程(Transaction Processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。下面,我们就简单的介绍下这 4 个特性的含义。
- 原子性(Atomicity)是指一个事务要么全部执行,要么全部不执行。换句话说,一个事务不可能只执行了一半就停止了。比如一个事情分为两步完成才可以完成,那么这两步必须同时完成,要么一步也不执行,绝不会停留在某一个中间状态。如果事物执行过程中,发生错误,系统会将事物的状态回滚到最开始的状态。
- 一致性(Consistency)是指事务的运行并不改变数据库中数据的一致性。也就是说,无论并发事务有多少个,但是必须保证数据从一个一致性的状态转换到另一个一致性的状态。例如有 a、b 两个账户,分别都是 10。当 a 增加 5 时,b 也会随着改变,总值 20 是不会改变的。
- 隔离性(Isolation)是指两个以上的事务不会出现交错执行的状态。因为这样可能会导致数据不一致。如果有多个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
- 持久性(Durability)指事务执行成功以后,该事务对数据库所作的更改便是持久的保存在数据库之中,不会无缘无故的回滚。
在具体的介绍 HBase 之前,我们先简单对比下 HBase 与传统关系数据库的(RDBMS,全称为 Relational Database Management System)区别。如表 1 所示。
表 1. HBase 与 RDBMS 的区别
HBase | RDBMS | |
---|---|---|
硬件架构 | 类似于 Hadoop 的分布式集群,硬件成本低廉 | 传统的多核系统,硬件成本昂贵 |
容错性 | 由软件架构实现,由于由多个节点组成,所以不担心一点或几点宕机 | 一般需要额外硬件设备实现 HA 机制 |
数据库大小 | PB | GB、TB |
数据排布方式 | 稀疏的、分布的多维的 Map | 以行和列组织 |
数据类型 | Bytes | 丰富的数据类型 |
事物支持 | ACID 只支持单个 Row 级别 | 全面的 ACID 支持,对 Row 和表 |
查询语言 | 只支持 Java API (除非与其他框架一起使用,如 Phoenix、Hive) | SQL |
索引 | 只支持 Row-key,除非与其他技术一起应用,如 Phoenix、Hive | 支持 |
吞吐量 | 百万查询/每秒 | 数千查询/每秒 |
理解了上面的表格之后,我们在看看数据是如何在 HBase 以及 RDBMS 中排布的。首先,数据在 RDBMS 的排布大致如表 2。
表 2. 数据在 RDBMS 中的排布示例
ID | 姓 | 名 | 密码 | 时间戳 |
---|---|---|---|---|
1 | 张 | 三 | 111 | 20160719 |
2 | 李 | 四 | 222 | 20160720 |
那么数据在 HBase 中的排布会是什么样子呢?如表 3 所示(这只是逻辑上的排布)。
表 3. 数据在 HBase 中的排布(逻辑上)
Row-Key | Value(CF、Qualifier、Version) |
---|---|
1 | info{‘姓’: ‘张’,‘名’:‘三’} |
pwd{‘密码’: ‘111’} | |
2 | Info{‘姓’: ‘李’,‘名’:‘四’} |
pwd{‘密码’: ‘222’} |
从上面示例表中,我们可以看出,在 HBase 中首先会有 Column Family 的概念,简称为 CF。CF 一般用于将相关的列(Column)组合起来。在物理上 HBase 其实是按 CF 存储的,只是按照 Row-key 将相关 CF 中的列关联起来。物理上的数据排布大致可以如表 4 所示。
表 4. 数据在 HBase 中的排布
Row-Key | CF:Column-Key | 时间戳 | Cell Value |
---|---|---|---|
1 | info:fn | 123456789 | 三 |
1 | info:ln | 123456789 | 张 |
2 | info:fn | 123456789 | 四 |
2 | info:ln | 123456789 | 李 |
我们已经提到 HBase 是按照 CF 来存储数据的。在表 3 中,我们看到了两个 CF,分别是 info 和 pwd。info 存储着姓名相关列的数据,而 pwd 则是密码相关的数据。上表便是 info 这个 CF 存储在 Hbase 中的数据排布。Pwd 的数据排布是类似的。上表中的 fn 和 ln 称之为 Column-key 或者 Qulifimer。在 Hbase 中,Row-key 加上 CF 加上 Qulifier 再加上一个时间戳才可以定位到一个单元格数据(Hbase 中每个单元格默认有 3 个时间戳的版本数据)。初学者,在一开始接触这些概念是很容易混淆。其实不管是 CF 还是 Qulifier 都是客户定义出来的。也就是说在 HBase 中创建表格时,就需要指定表格的 CF、Row-key 以及 Qulifier。我们会在后续的介绍中,尝试指定这些相关的概念,以便加深理解。这里我们先通过下图理解下 HBase 中,逻辑上的数据排布与物理上的数据排布之间的关系。
图 1. Hbase 中逻辑上数据的排布与物理上排布的关联
从上图我们看到 Row1 到 Row5 的数据分布在两个 CF 中,并且每个 CF 对应一个 HFile。并且逻辑上每一行中的一个单元格数据,对应于 HFile 中的一行,然后当用户按照 Row-key 查询数据的时候,HBase 会遍历两个 HFile,通过相同的 Row-Key 标识,将相关的单元格组织成行返回,这样便有了逻辑上的行数据。讲解到这,我们就大致了解 HBase 中的数据排布格式,以及与 RDBMS 的一些区别。
对于 RDBMS 来说,一般都是以 SQL 作为为主要的访问方式。而 HBase 是一种"NoSQL"数据库。"NoSQL"是一个通用词表示该数据库并
是 RDBMS 。现在的市面上有许多种 NoSQL 数据库,如 BerkeleyDB 是本地 NoSQL 数据库的例子, HBase 则为大型分布式 NoSql 数据库。从技术上来说,Hbase 更像是"数据存储"而非"数据库"(HBase 和 HDFS 都属于大数据的存储层)。因此,HBase 缺少很多 RDBMS 特性,如列类型,二级索引,触发器和高级查询语言等。然而, HBase 也具有许多其他特征同时支持线性化和模块化扩充。最明显的方式,我们可以通过增加 Region Server 的数量扩展 HBase。并且 HBase 可以放在普通的服务器中,例如将集群从 5 个扩充到 10 个 Region Server 时,存储空间和处理容量都可以同时翻倍。当然 RDBMS 也能很好的扩充,但仅对一个点,尤其是对一个单独数据库服务器而言,为了更好的性能,往往需要特殊的硬件和存储设备(往往价格也非常昂贵)。
HBase 相关模块以及 HBase 表格特性
在这里,让我们了解下 HBase 都有哪些模块,以及大致的工作流程。前面我们提到过 HBase 也是构建于 HDFS 之上,这是正确的,但也不是完全正确。HBase 其实也支持直接在本地文件系统之上运行,不过这样的 HBase 只能运行在一台机器上,那么对于分布式大数据的环境是没有意义的(这也是所谓的 HBase 的单机模式)。一般只用于测试或者验证某一个 HBase 的功能,后面我们在详细的介绍 HBase 的几种运行模式。这里我们只要记得在分布式的生产环境中,HBase 需要运行在 HDFS 之上,以 HDFS 作为其基础的存储设施。HBase 上层提供了访问的数据的 Java API 层,供应用访问存储在 HBase 的数据。在 HBase 的集群中主要由 Master 和 Region Server 组成,以及 Zookeeper,具体模块如下图所示。
图 2. HBase 的相关模块
接下来,我们简单的一一介绍下 HBase 中相关模块的作用。
-
Master
HBase Master 用于协调多个 Region Server,侦测各个 Region Server 之间的状态,并平衡 Region Server 之间的负载。HBase Master 还有一个职责就是负责分配 Region 给 Region Server。HBase 允许多个 Master 节点共存,但是这需要 Zookeeper 的帮助。不过当多个 Master 节点共存时,只有一个 Master 是提供服务的,其他的 Master 节点处于待命的状态。当正在工作的 Master 节点宕机时,其他的 Master 则会接管 HBase 的集群。
-
Region Server
对于一个 Region Server 而言,其包括了多个 Region。Region Server 的作用只是管理表格,以及实现读写操作。Client 直接连接 Region Server,并通信获取 HBase 中的数据。对于 Region 而言,则是真实存放 HBase 数据的地方,也就说 Region 是 HBase 可用性和分布式的基本单位。如果当一个表格很大,并由多个 CF 组成时,那么表的数据将存放在多个 Region 之间,并且在每个 Region 中会关联多个存储的单元(Store)。
-
Zookeeper
对于 HBase 而言,Zookeeper 的作用是至关重要的。首先 Zookeeper 是作为 HBase Master 的 HA 解决方案。也就是说,是 Zookeeper 保证了至少有一个 HBase Master 处于运行状态。并且 Zookeeper 负责 Region 和 Region Server 的注册。其实 Zookeeper 发展到目前为止,已经成为了分布式大数据框架中容错性的标准框架。不光是 HBase,几乎所有的分布式大数据相关的开源框架,都依赖于 Zookeeper 实现 HA。
一个完整分布式的 HBase 的工作原理示意图如下:
图 3. HBase 的工作原理
在上面的图中,我们需要注意几个我们之前没有提到的概念:Store、MemStore、StoreFile 以及 HFile。带着这几个新的概念,我们完整的梳理下整个 HBase 的工作流程。
首先我们需要知道 HBase 的集群是通过 Zookeeper 来进行机器之前的协调,也就是说 HBase Master 与 Region Server 之间的关系是依赖 Zookeeper 来维护。当一个 Client 需要访问 HBase 集群时,Client 需要先和 Zookeeper 来通信,然后才会找到对应的 Region Server。每一个 Region Server 管理着很多个 Region。对于 HBase 来说,Region 是 HBase 并行化的基本单元。因此,数据也都存储在 Region 中。这里我们需要特别注意,每一个 Region 都只存储一个 Column Family 的数据,并且是该 CF 中的一段(按 Row 的区间分成多个 Region)。Region 所能存储的数据大小是有上限的,当达到该上限时(Threshold),Region 会进行分裂,数据也会分裂到多个 Region 中,这样便可以提高数据的并行化,以及提高数据的容量。每个 Region 包含着多个 Store 对象。每个 Store 包含一个 MemStore,和一个或多个 HFile。MemStore 便是数据在内存中的实体,并且一般都是有序的。当数据向 Region 写入的时候,会先写入 MemStore。当 MemStore 中的数据需要向底层文件系统倾倒(Dump)时(例如 MemStore 中的数据体积到达 MemStore 配置的最大值),Store 便会创建 StoreFile,而 StoreFile 就是对 HFile 一层封装。所以 MemStore 中的数据会最终写入到 HFile 中,也就是磁盘 IO。由于 HBase 底层依靠 HDFS,因此 HFile 都存储在 HDFS 之中。这便是整个 HBase 工作的原理简述。
我们了解了 HBase 大致的工作原理,那么在 HBase 的工作过程中,如何保证数据的可靠性呢?带着这个问题,我们理解下 HLog 的作用。HBase 中的 HLog 机制是 WAL 的一种实现,而 WAL(一般翻译为预写日志)是事务机制中常见的一致性的实现方式。每个 Region Server 中都会有一个 HLog 的实例,Region Server 会将更新操作(如 Put,Delete)先记录到 WAL(也就是 HLog)中,然后将其写入到 Store 的 MemStore,最终 MemStore 会将数据写入到持久化的 HFile 中(MemStore 到达配置的内存阀值)。这样就保证了 HBase 的写的可靠性。如果没有 WAL,当 Region Server 宕掉的时候,MemStore 还没有写入到 HFile,或者 StoreFile 还没有保存,数据就会丢失。或许有的读者会担心 HFile 本身会不会丢失,这是由 HDFS 来保证的。在 HDFS 中的数据默认会有 3 份。因此这里并不考虑 HFile 本身的可靠性。
前面,我们很多次提到了 HFile,也就是 HBase 持久化的存储文件。也许有的读者还不能完全理解 HFile,这里我们便详细的看看 HFile 的结构,如下图。
图 4. HFile 的结构
从图中我们可以看到 HFile 由很多个数据块(Block)组成,并且有一个固定的结尾块。其中的数据块是由一个 Header 和多个 Key-Value 的键值对组成。在结尾的数据块中包含了数据相关的索引信息,系统也是通过结尾的索引信息找到 HFile 中的数据。HFile 中的数据块大小默认为 64KB。如果访问 HBase 数据库的场景多为有序的访问,那么建议将该值设置的大一些。如果场景多为随机访问,那么建议将该值设置的小一些。一般情况下,通过调整该值可以提高 HBase 的性能。
如果要用很短的一句话总结 HBase,我们可以认为 HBase 就是一个有序的多维 Map,其中每一个 Row-key 映射了许多数据,这些数据存储在 CF 中的 Column。我们可以用下图来表示这句话。
图 5. HBase 的数据映射关系
HBase 的使用建议
之前我介绍了很多 HBase 与 RDBMS 的区别,以及一些优势的地方。那么什么时候最需要 HBase,或者说 HBase 是否可以替代原有的 RDBMS?对于这个问题,我们必须时刻谨记——HBase 并不适合所有问题,其设计目标并不是替代 RDBMS,而是对 RDBMS 的一个重要补充,尤其是对大数据的场景。当需要考量 HBase 作为一个备选项时,我们需要进行如下的调研工作。
首先,要确信有足够多数据,如果有上亿或上千亿行数据,HBase 才会是一个很好的备选。其次,需要确信业务上可以不依赖 RDBMS 的额外特性,例如,列数据类型, 二级索引,SQL 查询语言等。再而,需要确保有足够硬件。且不说 HBase,一般情况下当 HDFS 的集群小于 5 个数据节点时,也干不好什么事情 (HDFS 默认会将每一个 Block 数据备份 3 分),还要加上一个 NameNode。
以下我给了一些使用 HBase 时候对表格设计的一些建议,读者也可以理解背后的含义。不过我并不希望这些建议成为使用 HBase 的教条,毕竟也有不尽合理的地方。首先,一个 HBase 数据库是否高效,很大程度会和 Row-Key 的设计有关。因此,如何设计 Row-key 是使用 HBase 时,一个非常重要的话题。随着数据访问方式的不同,Row-Key 的设计也会有所不同。不过概括起来的宗旨只有一个,那就是尽可能选择一个 Row-Key,可以使你的数据均匀的分布在集群中。这也很容易理解,因为 HBase 是一个分布式环境,Client 会访问不同 Region Server 获取数据。如果数据排布均匀在不同的多个节点,那么在批量的 Client 便可以从不同的 Region Server 上获取数据,而不是瓶颈在某一个节点,性能自然会有所提升。对于具体的建议我们一般有几条:
- 当客户端需要频繁的写一张表,随机的 RowKey 会获得更好的性能。
- 当客户端需要频繁的读一张表,有序的 RowKey 则会获得更好的性能。
- 对于时间连续的数据(例如 log),有序的 RowKey 会很方便查询一段时间的数据(Scan 操作)。
上面我们谈及了对 Row-Key 的设计,接着我们需要想想是否 Column Family 也会在不同的场景需要不同的设计方案呢。答案是肯定的,不过 CF 跟 Row-key 比较的话,确实也简单一些,但这并不意味着 CF 的设计就是一个琐碎的话题。在 RDBMS(传统关系数据库)系统中,我们知道如果当用户的信息分散在不同的表中,便需要根据一个 Key 进行 Join 操作。而在 HBase 中,我们需要设计 CF 来聚合用户所有相关信息。简单来说,就是需要将数据按类别(或者一个特性)聚合在一个或多个 CF 中。这样,便可以根据 CF 获取这类信息。上面,我们讲解过一个 Region 对应于一个 CF。那么设想,如果在一个表中定义了多个 CF 时,就必然会有多个 Region。当 Client 查询数据时,就不得不查询多个 Region。这样性能自然会有所下降,尤其当 Region 夸机器的时候。因此在大多数的情况下,一个表格不会超过 2 到 3 个 CF,而且很多情况下都是 1 个 CF 就足够了。
Phoenix 的使用
当一个新业务需要使用 HBase 时,是完全可以使用 Java API 开发 HBase 的应用,从而实现具体的业务逻辑。但是如果对于习惯使用 RDBMS 的 SQL,或者想要将原来使用 JDBC 的应用直接迁移到 HBase,这就是不可能的。由于这种缅怀过去的情怀,便催生了 Phoenix 的诞生。那么 Phoenix 都能提供哪些功能呢?简单来说 Phoenix 在 HBase 之上提供了 OLTP 相关的功能,例如完全的 ACID 支持、SQL、二级索引等,此外 Phoenix 还提供了标准的 JDBC 的 API。在 Phoenix 的帮助下,RDBMS 的用户可以很容易的使用 HBase,并且迁移原有的业务到 HBase 之中。下来就让我们简单了解一下,如何在 HBase 之上使用 Phoenix。
首先我们需要在 Phoenix 的网站下载与 HBase 版本对应的 Phoenix 安装包。我环境的 HBase 是通过 Ambari HDP2.4 部署的,其中的 HBase 是 1.1 的版本,因此我下载的是下图中的 phoenix-4.7.0-HBase-1.1。
图 6. Phoenix 的下载页面
下载之后需要解压 Phoenix 的 tar 包,并将所有的 jar 文件拷贝到每台 Region Server 机器的 $HBASE_HOME/lib 下面,并重启所有的 Region Server。对于 Ambari 部署的 HBase,其 HBASE_HOME 目录便是/usr/hdp/2.4.0.0-169/hbase/lib/,添加 Jar 包到该目录之后,可以直接在 Ambari 的 WEB 中,重启整个 HBase。重启之后,我们便尽可以进入到刚才解压的 Phoenix 目录,进入其子目录 bin。在这个目录中 Phoenix 提供了 sqlline.py 脚本。我们可以通过该脚本连接 HBase,并测试相关的 SQL 语句。我们可以在 bin 目录中看到文件 hbase-site.xml,如果需要对 Phoenix 设置相关参数,就需要更改该文件,并将该文件同步给 HBase 中。Sqlline.py 最简单的使用方法,就是直接以 Zookeeper 机器名为参数即可,如下图:
图 7. Sqlline.py 使用示意图
上图中,我们还使用了 sqlline.py 支持的 table 命令,该命令可以列出 HBase 中所有的表。这里需要注意 Phoenix 不支持直接显示 HBase Shell(HBase 自带一个 CLI 访问工具,后续文章在介绍)中创建的表格。原因很简单,当在 Phoenix 创建一张表时,Phoenix 是将表进行了重组装。而对 HBase Shell 创建的表 Phoenix 并未进行加工,所以无法直接显示。如果需要将 HBase Shell 中创建的表格关联到 Phoenix 中查看,就需要在 Phoenix 中创建一个视图(View)做关联。例如,我们现在 HBase Shell 中创建了一张表"table1",并插入了几行数据,如下。
然后我们在 Sqlline.py 的终端中执行"!table"命令,我们发现并没有 table1 这张表。接下来我们执行如下的命令:
然后再使用!table 命令,这时候结果如下:
图 8. Phoenix 执行表查询结果
我们可以看到结果中多了一个 table1 的视图,这样 Phoenix 就将 table1 表的内容关联到了 Phoenix 的视图当中。我们可以使用 select 等语句访问其中的内容,如下:
图 9. Phoenix 执行查询结果
最后我们再回头解释下刚才创建视图的命令。在创建关联的视图时,我们需要确保视图和列的名称与原表的名称完全一致。Phoenix 默认使用大写字母,因此,当 HBase Shell 中使用的是小写,我们便需要使用双引号引用相关的名称。如果原名称是大写,就可以省去双引号。Pk 是我们定义的一个主键名(可以随便定义),这是由于在 HBase Shell 中并没有主键的概念,所以 Row-key 是没有一个名称的。cf1 和 name 加起来用于指向 HBase 中的一个单元格(Cell),示例的命令中我关联了两个单元格(如果你愿意,可以只关联一个)。在安装了 Phoenix 之后,我们应尽量避免直接使用 HBase Shell 来创建表,取而代之的便是直接使用 Phoenix。例如下图中,我使用 Phoenix 创建了一张表 t1,包含了 name 和 age 两个列,并插入了两行数据。具体的命令如下图:
图 10. 如何在 Phoenix 中创建表
看到这些命令之后,熟悉 SQL 的读者肯定不会觉得陌生。这便是 Phoenix 提供的最重要的功能之一——SQL 的支持。我们可以看到在 Phoenix 中,我们使用了丰富的数据类型,如 INTEGER 和 VARCHAR。这些都是无法直接在 HBase 中使用的。有兴趣的读者可以在 sqlline.py 中尝试更多的 SQL 语句。当需要从 sqlline.py 退出时,可以执行!quit 命令(可以通过使用!help 查看更多的命令)。退出 sqlline.py 之后,让我们在 HBase Shell 中看看 Phoenix 创建的表会是什么样子。如下:
我们可以明显的看到,Phoenix 将如上的数据进行了重组,才形成了图 10 中所展示的样子。到这里,我们就简单的介绍了 Phoenix 简单的用法。需要强调的是,本章所展示的只是 Phoenix 所提供特性的很小一部分。Phoenix 作为一个标准 JDBC API 的支持者,原有建立在 JDBC 之上应用程序可以直接通过 Phoenix 访问 HBase,例如 Squirrel 这样图形化的 SQL 客户端。当然也可以直接在 Java 代码中通过 JDBC 访问 HBase 数据库,而不用使用 HBase 的 Java API 重新开发。想要了解更多 Phoenix 特性的读者,可以从 Apache Phoenix 官方的文档中查看,例如二级索引等。
总结
对于 HBase 还有很多内容需要介绍,例如使用 Java API 开发应用,快速部署使用(涉及 Ambari 以及 HBase 部署模式)、HBase Shell 以及如何集成 Hive 和 HBase 等。目前 HBase 的应用场景很多,尤其是互联网公司的后台信息存储中,例如淘宝等都在使用 HBase。我相信了解 HBase 之后,可以更好的架构使用大数据解决方案,这里篇幅有限,后续再介绍更多内容。
参考资源
Apache Spark 简介
Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的类Hadoop MapReduce的通用并行框架,Spark,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的MapReduce的算法。
Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。
Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。
尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoop 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。
准备工作
环境
1 | JDK:1.8 |
主机名 | ip地址 | 安装服务 |
---|---|---|
spark-master | 192.168.252.121 | jdk、hadoop、spark、scala |
spark-slave01 | 192.168.252.122 | jdk、hadoop、spark |
spark-slave02 | 192.168.252.123 | jdk、hadoop、spark |
依赖环境
Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。所有我们安装 Scala
Scala
Hadoop
安装
下载解压
1 | su hadoop |
环境变量
如果是对所有的用户都生效就修改vi /etc/profile
文件
如果只针对当前用户生效就修改 vi ~/.bahsrc
文件
1 | sudo vi /etc/profile |
1 | #spark |
使环境变量生效,运行 source /etc/profile
使/etc/profile
文件生效
修改配置
修改 spark-env.sh
1 | cd /home/hadoop/spark-2.2.0/conf |
1 | mv spark-env.sh.template spark-env.sh |
1 | #java |
简单介绍几个变量
- JAVA_HOME:Java安装目录
- SCALA_HOME:Scala安装目录
- HADOOP_HOME:hadoop安装目录
- HADOOP_CONF_DIR:hadoop集群的配置文件的目录
- SPARK_MASTER_IP:spark集群的Master节点的ip地址
- SPARK_WORKER_MEMORY:每个worker节点能够最大分配给exectors的内存大小
- SPARK_WORKER_CORES:每个worker节点所占有的CPU核数目
- SPARK_WORKER_INSTANCES:每台机器上开启的worker节点的数目
修改 slaves
1 | cd /home/hadoop/spark-2.2.0/conf |
1 | mv slaves.template slaves |
1 | node1 |
配置集群
复制节点
进去 spark 安装目录 ,打包,并发送,到其他节点
1 | cd cd /home/hadoop/ |
进去 node1
,node2
节点 解压
1 | cd /home/hadoop/ |
环境变量
到这里一步 确保你的每一个节点 环境变量够数
1 | #jdk |
启动集群
关闭防火墙
1 | systemctl stop firewalld.service |
启动 Hadoop
1 | cd /home/hadoop/hadoop-2.7.4/sbin |
启动 Spark
1 | cd /home/hadoop/spark-2.2.0/sbin |
启动 Spark Shell
1 | cd /home/hadoop/spark-2.2.0/bin |
spark 访问:192.168.252.121:8080
spark-shell 访问:192.168.252.121:4040