NodeJS->HBase(5)存储设计和数据访问

因为在前面的第4节中,涉及的内容主要是从Redis中校验数据和缓存数据更新,所以这里把HBase给拆分出来了,单独的放在这个章节,便于后续对这HBase内容和线索的扩张学习。

HBase被设计成为用来存储百亿级、百万列(长表、宽表)的结构化的数据,但是HBase里面数据存储和RowKey设计是有一定讲究的。因此,在设计这个HBase表去存储车辆运行数据的时候,要好好处理。

还有就是,永远不要指望使用HBase来实现RDBMS那样的灵活的查询功能(例如,两表join,这算SQL最核心了把,表如果不能用来join,那还要它干嘛,是不是都是这么想的),如果有这个想法,就尽早死了这条心,有些事情坚持很重要的,但是也要懂得放弃。
最后,HBase的目的是为了高并发的简单读和写和海量存储设计的,复杂的关系查询和多维计算天生就是不是它能干的,因此它还有有个好搭档Hive,这个后面再说,兄弟两关系不错。如果合二为一的话就是RDBMS了。

1/ 为什么要用HBase

HBase是根据Google BigTable的论文来设计的:用插入实现更新、强一致性、不支持关系型查询,几乎无限的存储能力是吸引我们的最重要的原因。为什么要用HBase,而不是主流使用的RDBMS(例如,MySQL、Oralce、DB2、Postgre等)。

因为,在我们这个Demo项目中,HBase的定位是:

  • 作为OT(物联网机器)数据的存储湖
    汽车TBOX的数据属于OT(机器数据)数据的范畴,不属于IT(企业数据),所以我们将其视为企业的外部数据源,由于其量比较大,而且TB级别起步,比较耗费数据存储,因此是个经济的选择。
  • 没什么大量在线用户直接去查询它
    只是一个机器数据的最终归宿地,保存个十年,八年都没有问题,存储成本也比较低。
  • 没有OLAP,联机应用会去经常的读写访问它,所以比较适合做一个:
    高频写,低频批处理的数据库,当历史库最好了
  • Schema~Less的数据库
    随着外部的数据源越来越多,新增字段比较方便的接入进来,不需要修改表结构,这的确是个优势。
  • 海量数据的存储,而且是长期的存储
    对于车辆网IoT方式发送来的数据,可能需要保存很久:
    例如:
    例如新能源车辆的动力电池的运行数据,需要保存8年以上(国家要求),处于对动力电池的一个运行情况的售后和质保的信息处理。

1.1 数据存储

以下的一些数据存储相关软件会被用到:

  • Redis
    缓存一些频繁被查询的主数据(做前端校验),应对外部的超高并发的场景,按照目前的估计。
    缓存的数据,大概在1000万条级别,基本上都是K + V(V是hash类型,非string)。
  • HBase
    单一键值的简单数据结构的数据(车联网消息,量大,但是消息简单),高性能写入、和唯一键值的查询。
  • Hive
    会基于HBase的数据,形成一个OLAP的数据仓库
  • MySQL(多个库)
    – 主数据管理的DB(车辆主数据)
    – 消费者终端App的底层DB(查询爱车一般数据查询、车况状态、打分、保养推荐、等等信息)
    – 企业内部实时监控应用系统的DB(所有车辆运行状态、轨迹、车况、数据告警,维修、实时运行信息)

2/ 部署->配置->启动

过去很多HBase部署在Windows都使用Cygwin,但是比较新的版本好像不需要这样做了,貌似可以直接支持Windows了。接下来我们看看。

2.1 下载,解压缩

使用的是hbase-1.2.6-bin.tar.gz,下载后直接解压缩目录下。

2.2 修改配置信息 – 单机部署方式(Window下举例)

HBase是有几种安装和部署方式的:

  • 单机部署
    使用本地的OS的文件系统作为HBase的存储系统
  • 单机伪分布式
    使用单机Hadoop的HDFS文件系统作为HBase的存储系统
  • 集群+分布式部署
    HBase集群(多节点)+Haoop集群的方式

在本例中,我们可以尝试1和2这两种模式,其区别就是使用HDFS作为文件系统,还是本机OS的文件系统作为存储,进入到hbase解压缩后的conf目录中.

1)文件和目录:hbase-env.cmd    (如果是MacOS则修改hbase-env.sh)

2)文件和目录:log4j.properties

3)文件和目录:hbase-site.xml

在Windows环境下,这些Value路径的写法就是c:\\目录\\,使用的是双斜杠。如果HBase所在的操作系统不是MacOS,则直接就是\目录\目录\目录,默认HBase是会保存在\tmp这个目录下。

但是,你知道\tmp只是一个临时目录,本地自己玩玩还可以,真正的生产环境的话,基本上都是需要使用HDFS文件系统来作为数据存储路径,而非本地某个文件夹下。

保存上面修改的配置文件,然后准备启动咯。

2.3 启动HBase(不依赖HDFS)

在Window环境下,开启一个命令行窗口,然后直接运行:start-hbase.cmd(Unix/Linux下则是start-hbase.sh),在浏览器中输入http://localhost:16010 会发现HBase在Web界面上显示了它的所有的运行和状态信息。

 

使用HBase Shell验证一下HBase的运行状态:

  • 执行hbase.cmd shell(Linux: hbase shell)启动这个交互式客户端
  • 在hbase的shell下执行以下的命令,完成HBase一个基本交互测试,看看是否可以创建表,显示数据
    create ‘test’,’cf’     创建test表,以及cf作为这个表的列簇
    list                          显示当前hbase有多少表,结果肯定是只有一个
    put ‘test’,’rowid0001′, ‘cf:name‘,’alex’
    put ‘test’,’rowid0001′, ‘cf:gender‘,’man’
    scan ‘test’             显示这个test表里面所有数据,当然只有一行

如果以上过程没问题,说明这个HBase是运行良好的。

3/ 分布式场景怎么撸

先将HBase停掉,执行stop-hbase.sh/cmd就可以,然后jps一把,看看是否还有服务出于启动的状态。

单机环境玩玩就好,但是生产集群都是分布式的,部署HBase的集群你要考虑的组件,例如HBase Master、RegionServer、HDFS Datanode、ZooKeeper(独立的,非HBase自带的Zookeeper)等。因此,我们需要安装Hadoop(HDFS),以及ZooKeeper,作为HBase所依靠的基础。

网络上找了图(说明HBase和HDFS、ZooKeeper之间的关系)

 

  • HDFS
    它是作为HBase的持久层,存储数据用的,这点不用解释(就跟OS的文件系统一样),由Hadoop来提供。
  • Region
    就是HBase的表(可以暂时先这么理解),一个表可以有多个region(它是HBase数据存储的最基本单位。
    Region 是 HBase 可用性和分布式的基本单位。如果当一个表格很大,并由多个 CF 组成时,那么表的数据将存放在多个 Region 之间(在有的生产环境下,一个表的region多大6000+个以上),并且在每个 Region 中会关联多个存储的单元(Store)。
  • Region Server
    用来管理多个Region(管理HBase表),客户端连接的HBase的时候,实际上就是连接Region Server进行数据的读写。
  • HMaster
    可以理解成为HANA里面的nameserver,它知道所有region server的状态,并且将Region分配到不同的region server(这个表)。
    协调多个region server,平衡负载。
  • ZooKeeper
    这玩意哪儿都有它存在,之前在搞Spark、Kafka环境配置的时候就有它。
    这里,HBase也需要它,那是因为Zookeeper已经在事实上成为了Hadoop技术平台上的所有软件组件去实现HA的基础(高可用),它可以在分布式情况下,保证只有一个HMaster处于工作状态(如果你单机的话,那怎么也无法保证哈!)。

Spark、Kafka、Hive都有Master Node + Salve Node这样的概念,所以大家都遵照分布式设计,从而统一利用ZooKeeper来管理自己的HA容错机制。

 

3.1 Hadoop安装,配置

选择2.7.2的hadoop版本,解压缩。然后将HADOOP_HOME、JAVA_HOME放入到系统的path路径中,下面以Unix/Linux为例,修改/etc/profile,添加一下内容(这里的)

然后,执行source profile命令一下,让其立即生效。

3.1.1 修改core-site.xml文件

该文件位于hadoop解压缩后的/etc/hadoop目录下的),以下的property的配置内容都需要放入到<configuration> ….. </configuration>之间

说明:

  • fs.default.name,它的值hdfs://localhost:8020是Hadoop的NameNode的主机名,8020则是其访问端口。
  • hadoop.tmp.dir,这个属性不配置的话,默认就是/tmp目录,但是要求修改为自己的目录,只要不是/tmp就好(因为系统重启会清理掉这个目录),不安全,所以建议修改。
    注意:它不是临时目录,是hadoop的HDFS的文件系统基础,是hadoop存储数据块的位置目录

3.1.2 修改hdfs-site.xml文件

说明:1表示,存放在HDFS文件系统中的数据的副本只有1个,通常是3份,这里是单机模拟的,所以没必要3份。

3.1.3 修改mapred-site.xml文件

从mapred-site.xml.template拷贝过来,去掉.template后缀)

说明:这个是mapreduce job的tracker服务器的主机名,以及访问端口。最多有多少map任务,最多有多少个reduce任务等等

3.1.4 修改hadoop-env.sh文件

2.7.2版本的hadoop发行版,其实这个文件什么都不用改。将操作系统的JAVA_HOME的值拿出来放入到这个变量中而已。

也可以不修改#export HADOOP_HEAPSIZE=的值,默认就是1000,可以不用修改。

3.1.5 格式化namenode

启动Hadoop试试看,按照以下顺序执行shell命令

  • start-dfs.sh
  • start-yarn.sh
  • 打开浏览器:http://localhost:8088/
  • 打开浏览器:http://localhost:50070/
    切换到datanode,确保datanodenamenode都已经启动了才行
  • jps,执行结果如下
    3089 DataNode
    3346 ResourceManager
    3204 SecondaryNameNode
    2998 NameNode
    3735 Jps
    3437 NodeManager

格式化namenode,意味着初始化HDFS的这个环境,如果在hadoop运行起来之后,你在hdfs中保存过文件,那么再再执行一次格式化的操作将会把这些数据目录全部删除。相当于format c:/的意思。

到这里为止,Hadoop这个基础软件组件就已经安装好了。

3.2 ZooKeeper安装,配置

Zookeeper在我们的《Spark+Kafka开发测试(1)环境搭建》 讲解过。所以,这里就不再重复,记得修改dataDir的默认值就好了。

启动zookeeper服务。执行jps命令,应该发现多了一个服务

  • QuorumPeerMain,它就是zookeeper服务

3.3 修改HBase配置信息

1)文件和目录:hbase-env.cmd    (如果是MacOS则修改hbase-env.sh)

注意:这里的HBASE_MANAGES_ZK设置为true(true意味着使用HBase自带的Zookeeper服务,生产环境下则建议使用独立的zookeeper集群服务)

2)文件和目录:hbase-site.xml

  • hbase.rootdir
    HBase在什么地方对它的数据(元数据、数据等)进行持久化,这里使用了HDFS的标准URL,其中”/hbase”目录是会在HBase其中之后会在HDFS中进行创建。
  • hbase.cluster.distributed
    这里是true,因为我们用了hdfs作为HBase的持久层存储的(单节点的伪分布式也是分布式啊!)

修改完,保存!

3.4 基于Hadoop/HDFS的HBase

如果是基于分布式的模式来启动HBase,那么它所依赖的文件系统HDFS服务要先启动,其执行顺序如下:

  • start-dfs.sh
  • start-yarn.sh
  • start-hbase.sh
    启动hbase, 然后将在前面单机下的hbase shell的一些步骤都执行一遍,而且看看http://localhost:16010/中是否有刚才创建的数据表
  • jps,查看结果,应该多了两个服务(除了HDFS、Name/Data Node、Zookeeper的那些服务之外)
    HRegionServer
    HMaster

接下来,我们就可以连接进入hbase shell看看这个只有这么几个API(Create, Put, Get, Delete, Scan,Alert)的强大高性能分布式数据库到底神奇在什么地方。

4/ 连线HBase看看

启动HBase Shell,在命令下执行hbase.cmd  shell or hbase.sh shell就可以启动HBase的交互式客户端(Windows下则hbase.cmd shell),HBase Shell是一个使用JRuby开发的封装了JAVA API的HBase的客户端应用软件。

执行list,就可以列出当前Hbase中所有的数据库表,及其名称。

再插入2条记录:

这两条数据在后面的Spark程序中被用到,用来监控一个5分钟的时间窗口中,同一辆车的单体电池温度上升7度(并基本温度超过40度)。

4.1 经常用的API介绍

来,创建一个名为test的表看看。

  • 创建表
    create ‘message’,’cf’
  • 删除表
    disable ‘message’
    drop ‘message’
  • 插入数据
    put ‘message’,’唯一主键’,’cf:列a’,’列a的值’
    put ‘message’,’唯一主键’,’cf:列b’,’列b的值’
  • 查询单条
    get ‘表名’, ‘唯一主键’
  • 扫描表
    scan ‘表名’
    scan ‘表名’, filter
  • 更新数据
  • 创建namespace
    目前没发现有多大用处,用来管理权限和表的逻辑命名空间。

4.2  Put和Get,傻傻分不清楚

 

4.3  强大的Scan和Filter小蜜

因为GET操作都是要基于唯一主键(row key)的,如果需要查询多条记录,进行数据的过滤赛选,那就只能使用Scan了,然后配上filter(类似SQL的where条件语句)可以实现一定程度上的数据查询功能。

例如:

row_keycf:namecf:agecf:gendercf:account_balance City
rowid0001alex21man20000Beijing
rowid0002apple34woman54107Shanghai
rowid0003kevin34man15001Wuhan
rowid0004helen34woman55100shanghai
rowid0005tom35man100000shenzhen

以上有5条记录。

  • 取出值等于man的所有数据
    scan ‘test’,FILTER=>”ValueFilter(=,’substring:man’)”
    貌似:woman的也会被取出来,毕竟是substring,目前没有找到好办法,以后最好是设计为W/M来标识,不要用长字符串来标识。
    或者使用
    scan ‘test’,FILTER=>”ValueFilter(=,’binary:man’)”,也可以实现这个目的。
    比较符号:是 =,>=, <,<=,!=, 这些,不作细究,要用的时候再查也不迟。
    此外,操作符还可以使用:
    binaryprefix:m,M开头的
    regexstring:m*n,以M开头,N结束的
    将其转换为binary进行比较。
  • 取出 值大于 21,并且列名为age
    scan ‘test’,FILTER=>”ValueFilter(>,’binary:21′) AND ColumnPrefixFilter(‘age’)”
  • 扫描某些列
    scan ‘test’,FILTER=>”QualifierFilter(=, ‘binary:gender’)”
    效果和下面一样的
    scan ‘test’,{COLUMNS=> ‘cf:gender’}
  • RowFilter – 通过过滤RowKey
    scan ‘test’,FILTER=>”RowFilter(=,’substring:5′)”
    这样可以把rowkey中包含5的全部取出来,也可以使用binary/binaryprefix/regexstring这些比较符号来进行组合。

注意:
– ValueFilter、ColumnPrefixFilter 这些过滤条件都都有大小写区分
– 在FILTER中的表示直接,可以使用OR、AND(还可以结合SKIP来使用)
– MultipleColumnPrefixFilter比ColumnPrefixFilter可以多放入几个列作为筛选条件
– PrefixFilter 只能用来比较row_key。例如PrefixFilter (‘EES001SVG002’),既可以把车辆为SVG002的所有的消息ID为EES001的数据全部选择出来。

现在想想后续开发新应用(Web、手机、用户自主查询、对外数据服务),其底层数据库数据库还真的不适合用HBase来干。貌似使用RDBMS是最合适的,这个我们后续在好好想想。

5/ 表和RowKey以及列簇怎么设计

HBase是NoSQL数据库,反范式设计的,并且算是Schema-Free 或者是Schema-Less(自由模式),总的来说,就是不怎么讲究这些玩意。

对Schema没有什么强约束(例如:只需要定义cf-column family,而不需要定义列,方便后续扩展),这些设计和我们使用的传统的RDBMS有着相当的不同,哪怕是一出校门就开始进入到开源世界的同学们,也是一样的不习惯,毕竟RDBMS是计算机专业的必修课程,而SQL也被视为正统。

所以,你会觉得用起来,屡试屡屡不爽,具体体现为:

  • 弱schema的设计,不定义列
  • 没有复合主键,只有唯一主键
  • 没有外键,没有外键约束功能(哪怕不用,你得有啊)
  • 几乎没有什么SQL的标准函数
  • 也不支持UDF的函数
  • 几乎没有SQL92或者ANSI SQL的功能
  • 不知道如何查询数据

我们看到了这些所谓的“缺点”,也要看到它的极强的优点:

  • 强一致性
  • 写很快
  • 分布式
  • 海量存储
    百亿级的表,百万列的表不是问题

在Hadoop整个生态圈里面,看到了很多重新造轮子的项目,目的有很多,不想去讨论。根据其创新性,HBase用HDFS的方式来接解决了传统RDBMS的数据的上限问题,这的确是是个创新。
将传统RDBMS的数据存储从TB提升到了PB、ZB级别,这点是自由HBase作为一个“数据库”的角色做到的创新。

RowKey是唯一的PK,如何设计,才能加速查询

  • RowKey是全局唯一
  • RowKey = 传统RDMBS的复合主键的合并(提升性能的最佳方式)

用前面我们插入的记录的row_key来举例,EES001SVG00220170810152020,就是一个我们设计过的Row_Key,在message这个表里面是唯一记录。

消息类型ID车架号日期时间
EES001SVG00220170810152020

 

复合键值查询如何做?(待解决问题)

6/ 数据终于要进HBase了

NodeJS, HBASE包。

 

Leave a Reply

Your email address will not be published.