目录
一、数据采集/消费(存储)
二、数据采集
三、数据消费
四、编写代码
在project-ct.pom
在ct.consume下
在ct.consumer.bean
在ct.consumer.dao
在ct-consumer的resources
在ct-common.pom
在ct.common.api
在ct.common.bean
在ct.common.constant
在ct-common的resources
在ct-consumer-coprocessor
四、数据消费方案优化
打包jar
五、数据消费测试
1. 打包HBase消费者代码
2.在hbase的页面也看到文件出现
欢迎来到数据采集模块(消费),在企业中你要清楚流式数据采集框架flume和kafka的定位是什么。我们在此需要将实时数据通过flume采集到kafka然后供给给hbase消费。
flume:cloudera公司研发
适合下游数据消费者不多的情况;
适合数据安全性要求不高的操作;
适合与Hadoop生态圈对接的操作。
kafka:linkedin公司研发
适合数据下游消费众多的情况;
适合数据安全性要求较高的操作(支持replication);
因此我们常用的一种模型是:
线上数据 --> flume --> kafka --> flume(根据情景增删该流程) --> HDFS
消费存储模块流程如图2所示:
思路:
a) 配置kafka,启动zookeeper和kafka集群;
b) 创建kafka主题;
c) 启动kafka控制台消费者(此消费者只用于测试使用);
d) 配置flume,监控日志文件;
e) 启动flume监控任务;
f) 运行日志生产脚本;
g) 观察测试。
1)启动zookeeper,kafka集群
$/opt/module/kafka/bin/kafka-server-start.sh
/opt/module/kafka/config/server.properties
2)创建kafka主题
[root@hadoop01 kafka]# bin/kafka-topics.sh --zookeeper hadoop01:2181 --topic ct --create --replication-factor 2 --partitions 3
检查一下是否创建主题成功:
[root@hadoop01 kafka]# bin/kafka-topics.sh --zookeeper hadoop01:2181 --list
3)启动kafka控制台消费者,等待flume信息的输入
[root@hadoop01 kafka]# bin/kafka-console-consumer.sh --zookeeper hadoop01:2181 -topic ct
4)配置flume(flume-kafka.conf)
[root@hadoop01 data]# vim flume-2-kafka.conf
# define
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F -c +0 /opt/module/data/call.log
a1.sources.r1.shell = /bin/bash -c
# sink
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.bootstrap.servers = hadoop01:9092,hadoop02:9092,hadoop03:9092
a1.sinks.k1.kafka.topic = ct
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.kafka.producer.linger.ms = 1
# channel
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# bind
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
5)启动flume
[root@hadoop01 flume]# bin/flume-ng agent -c conf/ -n a1 -f /opt/module/data/flume-2-kafka.conf
6)有数据不断生产中
如果以上操作均成功,则开始编写操作HBase的代码,用于消费数据,将产生的数据实时存储在HBase中。
思路:
a) 编写kafka消费者,读取kafka集群中缓存的消息,并打印到控制台以观察是否成功;
b) 既然能够读取到kafka中的数据了,就可以将读取出来的数据写入到HBase中,所以编写调用HBaseAPI相关方法,将从Kafka中读取出来的数据写入到HBase;
c) 以上两步已经足够完成消费数据,存储数据的任务,但是涉及到解耦,所以过程中需要将一些属性文件外部化,HBase通用性方法封装到某一个类中。
ct-common
ct-producer
ct-consumer
ct-consumer-coprocessor
创建新的module项目:ct_consumer
pom.xml文件配置:
lenovo-project-ct
org.example
1.0-SNAPSHOT
4.0.0
ct-consumer
8
8
org.apache.kafka
kafka-clients
0.11.0.0
org.apache.kafka
kafka_2.12
0.11.0.0
org.example
ct-common
1.0-SNAPSHOT
创建Bootstrap
/**
* @program: IntelliJ IDEA
* @description: 启动消费者
*
* @create: 2022-10-21 15:36
*/
/**
* 启动消费者
*
* 使用kafka消费者获取Flume采集的数据
*
* 将数据存储到Hbase中去
*/
public class Bootstrap {
public static void main(String[] args) throws Exception {
//创建消费者
Consumer consumer = new CalllogConsumer();
//消费数据
consumer.consume();
//关闭资源
consumer.close();
}
}
创建CalllogConsumer
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;
/**
* @program: IntelliJ IDEA
* @description: 通话日志消费对象
* @author:
* @create: 2022-10-21 15:41
*/
public class CalllogConsumer implements Consumer {
/**
* 消费数据
*/
public void consume() {
try{
//创建配置对象
Properties prop = new Properties();
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("consumer.properties"));
//获取flume采集的数据
KafkaConsumer consumer = new KafkaConsumer(prop);
//关注主题
consumer.subscribe(Arrays.asList(Names.TOPIC.getValue()));
//HBase数据访问对象
HBaseDao dao = new HBaseDao();
//初始化
dao.init();
//消费数据
while(true){
ConsumerRecords consumerRecords = consumer.poll(100);
for (ConsumerRecord consumerRecord : consumerRecords) {
System.out.println(consumerRecord.value());
//插入数据
dao.insertData(consumerRecord.value());
// Calllog log = new Calllog(consumerRecord.value());
// dao.insertData(log);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 关闭资源
* @throws IOException
*/
@Override
public void close() throws IOException {
}
}
创建 Calllog
/**
* 通话日志
*/
@TableRef("ct:calllog")
public class Calllog {
@Rowkey
private String rowkey;
@Column(family = "caller")
private String call1;
@Column(family = "caller")
private String call2;
@Column(family = "caller")
private String calltime;
@Column(family = "caller")
private String duration;
@Column(family = "caller")
private String flg = "1";
private String name;
public String getFlg() {
return flg;
}
public void setFlg(String flg) {
this.flg = flg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Calllog() {
}
public String getRowkey() {
return rowkey;
}
public void setRowkey(String rowkey) {
this.rowkey = rowkey;
}
public Calllog(String data ) {
String[] values = data.split("\t");
call1 = values[0];
call2 = values[1];
calltime = values[2];
duration = values[3];
}
public String getCall1() {
return call1;
}
public void setCall1(String call1) {
this.call1 = call1;
}
public String getCall2() {
return call2;
}
public void setCall2(String call2) {
this.call2 = call2;
}
public String getCalltime() {
return calltime;
}
public void setCalltime(String calltime) {
this.calltime = calltime;
}
public String getDuration() {
return duration;
}
public void setDuration(String duration) {
this.duration = duration;
}
}
创建HBaseDao
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
import java.util.ArrayList;
import java.util.List;
/**
* @program: IntelliJ IDEA
* @description: HBase数据访问对象
* @author:
* @create: 2022-10-21 16:41
*/
public class HBaseDao extends BaseDao {
/**
* 初始化
*/
public void init() throws Exception{
start();
creatNamespaceNX(Names.NAMESPACE.getValue());
createTableXX(Names.TABLE.getValue(),"com.lenovo.ct.consumer.coprocessor.InsertCalleeCoprocessor", ValueConstant.REGION_COUNT,Names.CF_CALLER.getValue(),Names.CF_CALLEE.getValue());
end();
}
/**
* 插入对象
* @param log
* @throws Exception
*/
public void insertData( Calllog log ) throws Exception {
log.setRowkey(genRegionNum(log.getCall1(), log.getCalltime()) + "_" + log.getCall1() + "_" + log.getCalltime() + "_" + log.getCall2() + "_" + log.getDuration());
putData(log);
}
/**
* 插入数据
* @param value
*/
public void insertData(String value) throws Exception{
//将通话日志保存到Hbase表中
//1.获取通话日志数据
String[] values = value.split("\t");
String call1 = values[0];
String call2 = values[1];
String calltime = values[2];
String duration = values[3];
//2.创建数据对象
// rowkey设计
// 1)长度原则
// 最大值64KB,推荐长度为10 ~ 100byte
// 最好8的倍数,能短则短,rowkey如果太长会影响性能
// 2)唯一原则 : rowkey应该具备唯一性
// 3)散列原则
// 3-1)盐值散列:不能使用时间戳直接作为rowkey
// 在rowkey前增加随机数
// 3-2)字符串反转 :1312312334342, 1312312334345
// 电话号码:133 + 0123 + 4567
// 3-3) 计算分区号:hashMap
// rowkey = regionNum + call1 + time + call2 + duration
String rowkey = genRegionNum(call1, calltime) + "_" + call1 + "_" + calltime + "_" + call2 + "_" + duration + "_1";
// 主叫用户
Put put = new Put(Bytes.toBytes(rowkey));
byte[] family = Bytes.toBytes(Names.CF_CALLER.getValue());
put.addColumn(family, Bytes.toBytes("call1"), Bytes.toBytes(call1));
put.addColumn(family, Bytes.toBytes("call2"), Bytes.toBytes(call2));
put.addColumn(family, Bytes.toBytes("calltime"), Bytes.toBytes(calltime));
put.addColumn(family, Bytes.toBytes("duration"), Bytes.toBytes(duration));
put.addColumn(family, Bytes.toBytes("flg"), Bytes.toBytes("1"));
String calleeRowkey = genRegionNum(call2, calltime) + "_" + call2 + "_" + calltime + "_" + call1 + "_" + duration + "_0";
// 被叫用户
// Put calleePut = new Put(Bytes.toBytes(calleeRowkey));
// byte[] calleeFamily = Bytes.toBytes(Names.CF_CALLEE.getValue());
// calleePut.addColumn(calleeFamily, Bytes.toBytes("call1"), Bytes.toBytes(call2));
// calleePut.addColumn(calleeFamily, Bytes.toBytes("call2"), Bytes.toBytes(call1));
// calleePut.addColumn(calleeFamily, Bytes.toBytes("calltime"), Bytes.toBytes(calltime));
// calleePut.addColumn(calleeFamily, Bytes.toBytes("duration"), Bytes.toBytes(duration));
// calleePut.addColumn(calleeFamily, Bytes.toBytes("flg"), Bytes.toBytes("0"));
//3.保存数据
List puts = new ArrayList();
puts.add(put);
// puts.add(calleePut);
putData(Names.TABLE.getValue(), puts);
}
}
创建consumer.properties
bootstrap.servers=hadoop01:9092,hadoop02:9092,hadoop03:9092
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
group.id=org.example
enable.auto.commit=true
auto.commit.interval.ms=1000
org.apache.hbase
hbase-client
1.3.1
org.apache.hbase
hbase-server
1.3.1
创建Column
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String family() default "info";
String column() default "";
}
创建Rowkey
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Rowkey {
}
创建TableRef
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TableRef {
String value();
}
创建Consumer
import java.io.Closeable;
/**
* @program: IntelliJ IDEA
* @description: 消费者接口
*
* @create: 2022-10-21 15:39
*/
public interface Consumer extends Closeable {
/**
* 生产数据
* */
public void consume();
}
创建BaseDao
/**
* @program: IntelliJ IDEA
* @description: 基础数据访问对象
* @author:
* @create: 2022-10-21 16:40
*/
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.lang.reflect.Field;
import java.util.*;
public abstract class BaseDao {
private ThreadLocal connHolder = new ThreadLocal();
private ThreadLocal adminHolder = new ThreadLocal();
protected void start() throws Exception {
getConnection();
getAdmin();
}
protected void end() throws Exception{
Admin admin = getAdmin();
if(admin != null){
admin.close();
adminHolder.remove();
}
Connection conn = getConnection();
if(conn != null){
conn.close();
connHolder.remove();
}
}
/**
* 创建表,如果表已经存在,那么删除后在创建新的
* @param name
* @param families
*/
protected void createTableXX(String name ,String... families)throws Exception{
createTableXX(name,null,null,families);
}
protected void createTableXX(String name ,String coprocessorClass,Integer regionCount,String... families)throws Exception{
Admin admin = getAdmin();
TableName tableName =TableName.valueOf(name);
if (admin.tableExists(tableName)){
//表存在,删除表
deleteTable(name);
}
//创建表
createTable(name,coprocessorClass,regionCount,families);
}
private void createTable(String name,String coprocessorClass,Integer regionCount,String... families) throws Exception{
Admin admin = getAdmin();
TableName tableName =TableName.valueOf(name);
HTableDescriptor tableDescriptor =
new HTableDescriptor(tableName);
if ( families == null || families.length == 0){
families = new String[1];
families[0] = Names.CF_INFO.getValue();
}
for (String family : families) {
HColumnDescriptor columnDescriptor =
new HColumnDescriptor(family);
tableDescriptor.addFamily(columnDescriptor);
}
if ( coprocessorClass != null && !"".equals(coprocessorClass) ) {
tableDescriptor.addCoprocessor(coprocessorClass);
}
//增加预分区
if(regionCount == null || regionCount <= 1){
admin.createTable(tableDescriptor);
}else{
//分区键
byte[][] splitKeys = getSplitKeys(regionCount);
admin.createTable(tableDescriptor,splitKeys);
}
}
/**
* 获取查询时startrow, stoprow集合
* @return
*/
protected List getStartStorRowkeys( String tel, String start, String end ) {
List rowkeyss = new ArrayList();
String startTime = start.substring(0, 6);
String endTime = end.substring(0, 6);
Calendar startCal = Calendar.getInstance();
startCal.setTime(DateUtil.parse(startTime, "yyyyMM"));
Calendar endCal = Calendar.getInstance();
endCal.setTime(DateUtil.parse(endTime, "yyyyMM"));
while (startCal.getTimeInMillis() <= endCal.getTimeInMillis()) {
// 当前时间
String nowTime = DateUtil.format(startCal.getTime(), "yyyyMM");
int regionNum = genRegionNum(tel, nowTime);
String startRow = regionNum + "_" + tel + "_" + nowTime;
String stopRow = startRow + "|";
String[] rowkeys = {startRow, stopRow};
rowkeyss.add(rowkeys);
// 月份+1
startCal.add(Calendar.MONTH, 1);
}
return rowkeyss;
}
/**
* 计算分区号(0, 1, 2)
* @param tel
* @param date
* @return
*/
protected int genRegionNum( String tel, String date ) {
// 13301234567
String usercode = tel.substring(tel.length()-4);
// 20181010120000
String yearMonth = date.substring(0, 6);
int userCodeHash = usercode.hashCode();
int yearMonthHash = yearMonth.hashCode();
// crc校验采用异或算法, hash
int crc = Math.abs(userCodeHash ^ yearMonthHash);
// 取模
int regionNum = crc % ValueConstant.REGION_COUNT;
return regionNum;
}
/**
* 生成分区键
* @param regionCount
* @return
*/
private byte[][] getSplitKeys(int regionCount){
int splitKeyCount = regionCount - 1;
byte [][] bs = new byte[splitKeyCount][];
// 0,1,2,3,4
//(-无穷,0),[0,1),[1 ,+无穷)
List bsList = new ArrayList();
for( int i = 0;i puts ) throws Exception {
// 获取表对象
Connection conn = getConnection();
Table table = conn.getTable(TableName.valueOf(name));
// 增加数据
table.put(puts);
// 关闭表
table.close();
}
/**
* 增加数据
* @param name
* @param put
*/
protected void putData(String name, Put put) throws Exception{
//获取表的对象
Connection conn = getConnection();
Table table = conn.getTable(TableName.valueOf(name));
//增加数据
table.put(put);
//关闭表
table.close();
}
/**
* 删除表格
* @param name
* @throws Exception
*/
protected void deleteTable(String name) throws Exception{
TableName tableName =TableName.valueOf(name);
Admin admin = getAdmin();
admin.disableTable(tableName);
admin.deleteTable(tableName);
}
/**
* 创建命名空间,如果命名空间已经存在,不需要创建,否则,创建新的
* @param namespace
*/
protected void creatNamespaceNX(String namespace) throws Exception{
Admin admin = getAdmin();
try{
admin.getNamespaceDescriptor(namespace);
}catch (NamespaceNotFoundException e){
// e.printStackTrace();
NamespaceDescriptor namespaceDescriptor =
NamespaceDescriptor.create(namespace).build();
admin.createNamespace(namespaceDescriptor);
}
}
/**
* 获取连接对象
*/
protected synchronized Connection getConnection() throws Exception {
Connection conn = connHolder.get();
if( conn == null ){
Configuration conf = HBaseConfiguration.create();
conn = ConnectionFactory.createConnection(conf);
connHolder.set(conn);
}
return conn;
}
/**
* 获取连接对象
*/
protected synchronized Admin getAdmin() throws Exception {
Admin admin = adminHolder.get();
if( admin == null ){
admin = getConnection().getAdmin();
adminHolder.set(admin);
}
return admin;
}
}
创建ConfigConstant
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
/**
* @program: IntelliJ IDEA
* @description: ming
* @author:
* @create: 2022-10-22 20:21
*/
public class ConfigConstant {
private static Map valueMap = new HashMap();
static {
//国际化
ResourceBundle ct = ResourceBundle.getBundle("ct");
Enumeration enums = ct.getKeys();
while( enums.hasMoreElements()){
String key = enums.nextElement();
String value = ct.getString(key);
valueMap.put(key,value);
}
}
public static String getVal(String key){
return valueMap.get(key);
}
public static void main(String[] args){
System.out.println(ConfigConstant.getVal("ct.cf.caller"));
}
}
创建Names
/*
* 名称常量枚举类
* */
public enum Names implements Val {
NAMESPACE("ct")
,TABLE("ct:calllog")
,CF_CALLER("caller")
,CF_CALLEE("callee")
,CF_INFO("info")
, TOPIC("ct");
private String name;
private Names(String name){
this.name = name;
}
@Override
public void setValue(Object val) {
this.name = (String) val;
}
@Override
public String getValue() {
return name;
}
}
创建 constant
public class ValueConstant {
public static final Integer REGION_COUNT = 6;
}
将hdfs-site.xml、core-site.xml、hbase-site.xml、log4j.properties放置于resources目录
创建hdfs-site.xml
dfs.replication
1
dfs.permissions.enable
false
dfs.namenode.secondary.http-address
hadoop03:50090
dfs.namenode.http-address
hadoop01:50070
dfs.webhdfs.enabled
true
创建core-site.xml
fs.defaultFS
hdfs://hadoop01:9000
hadoop.tmp.dir
/opt/module/hadoop-2.7.2/data/tmp
hadoop.proxyuser.admin.hosts
*
hadoop.proxyuser.admin.groups
*
创建hbase-site.xml
hbase.rootdir
hdfs://hadoop01:8020/hbase
hbase.cluster.distributed
true
hbase.master.port
60000
hbase.zookeeper.quorum
hadoop01:2181,hadoop02:2181,hadoop03:2181
hbase.zookeeper.property.dataDir
/opt/module/zookeeper-3.4.10/zkData
导入log4j.properties
创建ct.properties
ct.namespace = ct
ct.table = ct:calllog
ct.topic=ct
ct.cf.caller=caller
ct.cf.info = info
pom
ct-consumer-coprocessor
8
8
org.example
ct-common
1.0-SNAPSHOT
现在我们要使用
使用HBase查找数据时,尽可能的使用rowKey去精准的定位数据位置,而非使用ColumnValueFilter或者SingleColumnValueFilter,按照单元格Cell中的Value过滤数据,这样做在数据量巨大的情况下,效率是极低的——如果要涉及到全表扫描。所以尽量不要做这样可怕的事情。注意,这并非ColumnValueFilter就无用武之地。现在,我们将使用协处理器,将数据一分为二。
思路:
a) 编写协处理器类,用于协助处理HBase的相关操作(增删改查)
b) 在协处理器中,一条主叫日志成功插入后,将该日志切换为被叫视角再次插入一次,放入到与主叫日志不同的列族中。
c) 重新创建hbase表,并设置为该表设置协处理器。
d) 编译项目,发布协处理器的jar包到hbase的lib目录下,并群发该jar包
e) 修改hbase-site.xml文件,设置协处理器,并群发该hbase-site.xml文件
编码:
1) 新建协处理器类:InsertCalleeCoprocessor,并覆写postPut方法,该方法会在数据成功插入之后被回调。
创建InsertCalleeCoprocessor
package com.ct.consumer.coprocessor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
/**
*
* 使用协处理器保存被叫用户的数据
*
* 协处理器的使用
* 1. 创建类
* 2. 让表找到协处理类(和表有关联)
* 3. 将项目打成jar包发布到hbase中(关联的jar包也需要发布),并且需要分发
*/
public class InsertCalleeCoprocessor extends BaseRegionObserver {
// 方法的命名规则
// login
// logout
// prePut
// doPut :模板方法设计模式
// 存在父子类:
// 父类搭建算法的骨架
// 1. tel取用户代码,2时间取年月,3,异或运算,4 hash散列
// 子类重写算法的细节
// do1. tel取后4位,do2,201810, do3 ^, 4, % &
// postPut
/**
* 保存主叫用户数据之后,由Hbase自动保存被叫用户数据
* @param e
* @param put
* @param edit
* @param durability
* @throws IOException
*/
@Override
public void postPut(ObserverContext e, Put put, WALEdit edit, Durability durability) throws IOException {
// 获取表
Table table = e.getEnvironment().getTable(TableName.valueOf(Names.TABLE.getValue()));
// 主叫用户的rowkey
String rowkey = Bytes.toString(put.getRow());
// 1_133_2019_144_1010_1
String[] values = rowkey.split("_");
CoprocessorDao dao = new CoprocessorDao();
String call1 = values[1];
String call2 = values[3];
String calltime = values[2];
String duration = values[4];
String flg = values[5];
if ( "1".equals(flg) ) {
// 只有主叫用户保存后才需要触发被叫用户的保存
String calleeRowkey = dao.getRegionNum(call2, calltime) + "_" + call2 + "_" + calltime + "_" + call1 + "_" + duration + "_0";
// 保存数据
Put calleePut = new Put(Bytes.toBytes(calleeRowkey));
byte[] calleeFamily = Bytes.toBytes(Names.CF_CALLEE.getValue());
calleePut.addColumn(calleeFamily, Bytes.toBytes("call1"), Bytes.toBytes(call2));
calleePut.addColumn(calleeFamily, Bytes.toBytes("call2"), Bytes.toBytes(call1));
calleePut.addColumn(calleeFamily, Bytes.toBytes("calltime"), Bytes.toBytes(calltime));
calleePut.addColumn(calleeFamily, Bytes.toBytes("duration"), Bytes.toBytes(duration));
calleePut.addColumn(calleeFamily, Bytes.toBytes("flg"), Bytes.toBytes("0"));
table.put( calleePut );
// 关闭表
table.close();
}
}
private class CoprocessorDao extends BaseDao {
public int getRegionNum(String tel, String time) {
return genRegionNum(tel, time);
}
}
}
1.打包jar的依赖到在linux下测试
把图中的jar导入到/opt/module/hbase/lib/
重新编译项目,发布jar包到hbase的lib目录下(注意需群发):
关闭hbase并且重新启动
bin/stop-hbase.sh
bin/start-hbase.sh
在hbase里面查看有文件生成
bin/hbase shell
hbase(main):001:0> scan 'ct:calllog'
项目成功后,则将项目打包后在linux中运行测试。
a) 在windows中,进入工程的pom.xml所在目录下(建议将该工程的pom.xml文件拷贝到其他临时目录中,例如我把pom.xml文件拷贝到了F:\maven-lib\目录下),然后使用mvn命令下载工程所有依赖的jar包
mvn -DoutputDirectory=./lib -DgroupId=com.atguigu -DartifactId=ct_consumer – Dversion=0.0.1-SNAPSHOT dependency:copy-dependencies |
b) 使用maven打包工程
c) 测试执行该jar包
方案一:推荐,使用*通配符,将所有依赖加入到classpath中,不可使用*.jar的方式。
注意:如果是在Linux中实行,注意文件夹之间的分隔符。自己的工程要单独在cp中指定,不要直接放在maven-lib/lib目录下。
java -cp F:\maven-lib\ct_consumer-0.0.1-SNAPSHOT.jar;F:\maven-lib\lib\* com.atguigu.ct_consumer.kafka.HBaseConsumer |
方案二:最最推荐,使用java.ext.dirs参数将所有依赖的目录添加进classpath中。
注意:-Djava.ext.dirs=属性后边的路径不能为”~”
java -Djava.ext.dirs=F:\maven-lib\lib\ -cp F:\maven-lib\ct_consumer-0.0.1- SNAPSHOT.jar com.atguigu.ct_consumer.kafka.HBaseConsumer |
3.hbase节点挂了,可以查看日志文件,找出错误出现