大数据 同步解决方案 Mysql、Hive、Hbase

1)、基于数据库日志(比如mysql的binlog)的同步 (canal)

我们都知道很多数据库都支持了主从自动同步,尤其是mysql,可以支持多主多从的模式。那么我们是不是可以利用这种思想呢,答案当然是肯定的,mysql的主从同步的过程是这样的。

A、master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);

B、slave将master的binary log events拷贝到它的中继日志(relay log);

C、slave重做中继日志中的事件,将改变反映它自己的数据。

大数据 同步解决方案 Mysql、Hive、Hbase_第1张图片

阿里巴巴开源的canal就完美的使用这种方式,canal 伪装了一个Slave 去和Master进行同步。

大数据 同步解决方案 Mysql、Hive、Hbase_第2张图片

A、 canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议

B、 mysql master收到dump请求,开始推送binary log给slave(也就是canal)

C、 canal解析binary log对象(原始为byte流)

另外canal 在设计时,特别设计了 client-server 模式,交互协议使用 protobuf 3.0 , client 端可采用不同语言实现不同的消费逻辑。

canal java 客户端: https://github.com/alibaba/canal/wiki/ClientExample

github的地址:https://github.com/alibaba/canal/

另外canal 1.1.1版本之后, 默认支持将canal server接收到的binlog数据直接投递到MQ   https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart

D、在使用canal时,mysql需要开启binlog,并且binlog-format必须为row,可以在mysql的my.cnf文件中增加配置

2)、基于sqoop的全量导入

Sqoop 是hadoop生态中的一个工具,专门用于外部数据导入进入到hdfs中,外部数据导出时,支持很多常见的关系型数据库,也是在大数据中常用的一个数据导出导入的交换工具。

https://blog.csdn.net/qq_22473611/article/details/88115558

大数据 同步解决方案 Mysql、Hive、Hbase_第3张图片

大数据 同步解决方案 Mysql、Hive、Hbase_第4张图片

3)、hive同步数据到hbase,基于BulkLoad的数据同步

我们有两种方式可以实现,

A、 使用spark任务,通过HQl读取数据,然后再通过hbase的Api插入到hbase中。

大数据 同步解决方案 Mysql、Hive、Hbase_第5张图片

但是这种做法,效率很低,而且大批量的数据同时插入Hbase,对Hbase的性能影响很大。

在大数据量的情况下,使用BulkLoad可以快速导入,BulkLoad主要是借用了hbase的存储设计思想,因为hbase本质是存储在hdfs上的一个文件夹,然后底层是以一个个的Hfile存在的。HFile的形式存在。Hfile的路径格式一般是这样的:

/hbase/data/default(默认是这个,如果hbase的表没有指定命名空间的话,如果指定了,这个就是命名空间的名字)////

B、 BulkLoad实现的原理就是按照HFile格式存储数据到HDFS上,生成Hfile可以使用hadoop的MapReduce来实现。如果不是hive中的数据,比如外部的数据,那么我们可以将外部的数据生成文件,然后上传到hdfs中,组装RowKey,然后将封装后的数据在回写到HDFS上,以HFile的形式存储到HDFS指定的目录中。

大数据 同步解决方案 Mysql、Hive、Hbase_第6张图片

当然我们也可以不事先生成hfile,可以使用spark任务直接从hive中读取数据转换成RDD,然后使用HbaseContext的自动生成Hfile文件,部分关键代码如下:

…
//将DataFrame转换bulkload需要的RDD格式
    val rddnew = datahiveDF.rdd.map(row => {
      val rowKey = row.getAs[String](rowKeyField)
  
      fields.map(field => {
        val fieldValue = row.getAs[String](field)
        (Bytes.toBytes(rowKey), Array((Bytes.toBytes("info"), Bytes.toBytes(field), Bytes.toBytes(fieldValue))))
      })
    }).flatMap(array => {
      (array)
    })
…
//使用HBaseContext的bulkload生成HFile文件
    hbaseContext.bulkLoad[Put](rddnew.map(record => {
      val put = new Put(record._1)
      record._2.foreach((putValue) => put.addColumn(putValue._1, putValue._2, putValue._3))
      put
    }), TableName.valueOf(hBaseTempTable), (t : Put) => putForLoad(t), "/tmp/bulkload")
  
    val conn = ConnectionFactory.createConnection(hBaseConf)
    val hbTableName = TableName.valueOf(hBaseTempTable.getBytes())
    val regionLocator = new HRegionLocator(hbTableName, classOf[ClusterConnection].cast(conn))
    val realTable = conn.getTable(hbTableName)
    HFileOutputFormat2.configureIncrementalLoad(Job.getInstance(), realTable, regionLocator)
  
    // bulk load start
    val loader = new LoadIncrementalHFiles(hBaseConf)
    val admin = conn.getAdmin()
    loader.doBulkLoad(new Path("/tmp/bulkload"),admin,realTable,regionLocator)
  
    sc.stop()
  }
…
  def putForLoad(put: Put): Iterator[(KeyFamilyQualifier, Array[Byte])] = {
    val ret: mutable.MutableList[(KeyFamilyQualifier, Array[Byte])] = mutable.MutableList()
    import scala.collection.JavaConversions._
    for (cells <- put.getFamilyCellMap.entrySet().iterator()) {
      val family = cells.getKey
      for (value <- cells.getValue) {
        val kfq = new KeyFamilyQualifier(CellUtil.cloneRow(value), family, CellUtil.cloneQualifier(value))
        ret.+=((kfq, CellUtil.cloneValue(value)))
      }
    }
    ret.iterator
  }
}
 
…

4)、HBase中建表,然后Hive中建一个外部表,这样当Hive中写入数据后,HBase中也会同时更新,

我们可以在hbase的shell 交互模式下,创建一张hbse表

create 'hbase_tablename ','cf1'

在Hive中创建HBase识别的表

CREATE TABLE hive_tablename(key int, value string)

partitioned by (pt string)

STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'

WITH SERDEPROPERTIES("hbase.columns.mapping" = ":key,cf1:name,cf1:age")

TBLPROPERTIES("hbase.table.name" = " hbase_tablename ");

其中:

hbase.table.name 定义在hbase中的table名称

hbase.columns.mapping 定义在hbase的列族,里面的:key 是固定值而且要保证在表pokes中的foo字段是唯一值

A、hbase中的空cell在hive中会补null

B、hive和hbase中不匹配的字段会补null

来源:https://www.cnblogs.com/laoqing/p/11359224.html

你可能感兴趣的:(大数据(其他))