SpringBoot 搭建HBase 数据对外服务http API接口
1. 背景
- 在大数据开发中,数据分析结果在公司内部从数据查询速度要求来看分为2种,一种是不太在乎速度,在时间期限之前给到即可;一种是查询速度要求较高。
- 应对查询速度较高的,有2种思路。一种是提前计算好,然后存入数据查询较快的数据库中;一种是采用高速计算引擎,当场计算。
- 提前计算好的数据,如果数据规模较小,如亿条数据级别,可以使用如mysql集群应对。当数据再大时,使用Hbase,elasticsearch等就可以纳入技术选型视野。
- 本文讲述使用springboot搭建一个简单服务,对外以http API接口方式对外提供数据访问服务。
注意,HBase其实并不是传统意义上的数据库,本质上使用HBase一般数据读取远大于写入,一般是一次写入多次读取
2. 案例
- 环境
- idea 2020
- maven 3.6.3
- scala 2.11
- jdk 1.8
- pom文件
<properties>
<java.version>1.8</java.version>
<spark.version>2.4.4</spark.version>
<scala.version>2.11.12</scala.version>
<hadoop.version>3.1.0</hadoop.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.0.4</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<layout>default</layout>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>ali-plugin</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 代码层级
典型的mvc架构,controller,service,dao,pojo,util四层

- 代码
@RestController
public class SessionAgrQueryController {
@Autowired
SessionAgrService sessionAgrService;
@RequestMapping("/session/agr")
public List<SessionAgrBean> getSessions(String dt,String startRow,Integer limit) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(dt);
long ts = date.getTime();
List<SessionAgrBean> beanList = sessionAgrService.getSessions(ts, startRow, limit);
return beanList;
}
}
public interface SessionAgrDao {
public List<HashMap<String, String>> getSessions(Long ts, String start_row, int limit) throws Exception;
}
@Repository
public class SessionAgrDaoImpl implements SessionAgrDao {
@Override
public List<HashMap<String, String>> getSessions(Long ts,String start_row,int limit) throws Exception {
Connection conn = GetHbaseConnection.getConnection();
Table tb = conn.getTable(TableName.valueOf("session_agr"));
Scan scan = new Scan();
scan.withStartRow(Bytes.toBytes(start_row));
scan.setLimit(limit);
ResultScanner resultScanner = tb.getScanner(scan);
Iterator<Result> iter = resultScanner.iterator();
ArrayList<HashMap<String, String>> beanLst = new ArrayList<>();
while(iter.hasNext()){
Result result = iter.next();
HashMap<String, String> columnsMap = new HashMap<>();
CellScanner cellScanner = result.cellScanner();
while(cellScanner.advance()){
Cell cell = cellScanner.current();
byte[] valueBytes = CellUtil.cloneValue(cell);
byte[] qualifierBytes = CellUtil.cloneQualifier(cell);
columnsMap.put(new String(qualifierBytes),new String(valueBytes));
}
beanLst.add(columnsMap);
}
return beanLst;
}
}
public class SessionAgrBean {
private String guid ;
private String session_id ;
private String start_ts ;
private String end_ts ;
private String first_page_id ;
private String last_page_id ;
private String pv_cnt ;
private String isnew ;
private String hour_itv ;
private String country ;
private String province ;
private String city ;
private String region ;
private String device_type ;
private String dt ;
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public String getSession_id() {
return session_id;
}
public void setSession_id(String session_id) {
this.session_id = session_id;
}
public String getStart_ts() {
return start_ts;
}
public void setStart_ts(String start_ts) {
this.start_ts = start_ts;
}
public String getEnd_ts() {
return end_ts;
}
public void setEnd_ts(String end_ts) {
this.end_ts = end_ts;
}
public String getFirst_page_id() {
return first_page_id;
}
public void setFirst_page_id(String first_page_id) {
this.first_page_id = first_page_id;
}
public String getLast_page_id() {
return last_page_id;
}
public void setLast_page_id(String last_page_id) {
this.last_page_id = last_page_id;
}
public String getPv_cnt() {
return pv_cnt;
}
public void setPv_cnt(String pv_cnt) {
this.pv_cnt = pv_cnt;
}
public String getIsnew() {
return isnew;
}
public void setIsnew(String isnew) {
this.isnew = isnew;
}
public String getHour_itv() {
return hour_itv;
}
public void setHour_itv(String hour_itv) {
this.hour_itv = hour_itv;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getDevice_type() {
return device_type;
}
public void setDevice_type(String device_type) {
this.device_type = device_type;
}
public String getDt() {
return dt;
}
public void setDt(String dt) {
this.dt = dt;
}
}
public interface SessionAgrService {
public List<SessionAgrBean> getSessions(Long ts, String startRow, int limit) throws Exception;
}
@Service
public class SessionAgrServiceImpl implements SessionAgrService {
@Autowired
SessionAgrDao sessionAgrDao;
@Override
public List<SessionAgrBean> getSessions(Long ts,String startRow,int limit) throws Exception {
List<HashMap<String, String>> sessions = sessionAgrDao.getSessions(ts, startRow, limit);
ArrayList<SessionAgrBean> beanList = new ArrayList<>();
for (HashMap<String, String> sessionMap : sessions) {
SessionAgrBean bean = new SessionAgrBean();
bean.setCity(sessionMap.get("city"));
bean.setCountry(sessionMap.get("country"));
bean.setDevice_type(sessionMap.get("device_type"));
bean.setDt(sessionMap.get("dt"));
bean.setEnd_ts(sessionMap.get("end_ts"));
bean.setFirst_page_id(sessionMap.get("first_page_id"));
bean.setGuid(sessionMap.get("guid"));
bean.setHour_itv(sessionMap.get("hour_itv"));
bean.setIsnew(sessionMap.get("isnew"));
bean.setLast_page_id(sessionMap.get("last_page_id"));
bean.setPv_cnt(sessionMap.get("pv_cnt"));
bean.setRegion(sessionMap.get("region"));
bean.setSession_id(sessionMap.get("session_id"));
bean.setStart_ts(sessionMap.get("start_ts"));
beanList.add(bean);
}
return beanList;
}
}
public class GetHbaseConnection {
private static Connection conn;
public static Connection getConnection() throws IOException {
if (conn == null) {
synchronized ("lock") {
if(conn == null) {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "doit01,doit02,doit03");
conn = ConnectionFactory.createConnection(conf);
}
}
}
return conn;
}
}
3. 效果
- 本地运行,就可以访问集群上HBase的数据
- 注意,需要先启动zookeeper和hbase,hdfs
- 如果需要对外提供服务,可以打成jar包,在linux服务器上运行即可
4. 总结
- 不管是什么接口服务器,本质都是运行一个程序,部署在服务器上通过地址端口对外提供服务
- 使用springboot可以快速开发一个简单接口,不过本案例相对简单,一些代码规范和细节点并没有完全遵守严格开发规范。只是实现了目的,并不算规范,仅供参考
- JDBC应用广泛,大部分数据存储服务框架和数据计算框架都提供了JDBC接口,可以很方便使用JDBC进行功能调用。Java确实是工程化语言老大
- 本案例还是使用最经典也是最老的代码分层,MVC架构。各个公司可能会使用更新的架构。注意这些层级中注解的使用,不过这是springboot基本用法,注意即可。
- 注意,接口的使用,这里主要是用来约束接口方法,方便后续开发和维护,代码也会更加清晰。