分享

从phoenix hbase谈谈研发管理和技术选型

 wuhancar 2020-07-12

肉眼品世界导读:最近接到一个需求,说XX项目千亿的数据要写进来,每毫秒就写进来一个,小伙子,你看看怎么搞吧,刚一听到几毫秒写进来一个有点儿愣,稍微反思了一一下,预估了一下1000TPS,小心脏很快的平静了下来,就开干了

读懂中国互联网,读懂商业模式请关注微信公众号“肉眼品世界”(ID:find_world_fine),深度价值体系传递
业务场景

一边是C++主要做底层应用和生态应用,交易量很大,不停的增长,毫秒内就一个,需要把这些很大的交易数据存储到JAVA端提供API出来给APP应用使用,这么大的交易数据当然想到了TIDB和hbase,  hbase相对更成熟,文档更多,所以选择了hbase,tidb作为备选方案,但是使用hbase多条件的复合查询没有tidb和mysql那么爽,是不是感觉挺别扭,还好,通过合理的rowkey设计也可以很好的实现复合查询,这个后面有空再讲,c++先把数据打到kafka里,kafka的写入效率确实很高,读取也不赖,PC机试验测试单机消费可达7,8000,在KAFKA里常常写入快,消费不过来,让消费和生产达到平衡才会让kafka玩得更好,这里面涉及到几个参数的配置和调优,大家可以先行百度一下,kafka的内容也后续完善一下,为什么不直接把数据请求http接口写入hbase呢?通过测试验证http协议的api协议比tcp的kafka慢大概10倍以上,当然可以加机器完成

这里主要讲phoenix hbase的应用以及从phoenix的应用我们可以得出一些常见研发管理思路和技术方法论,没错,小编的想法就是希望尽可能的抽象每个事物,包括技术的东西让同学们快速GET到在职场快速赚钱的方法...

当用上hbase的时候,这么好的一个东西,但是常常会有同学说怎么没写SQL爽快呀,看看市面上有phoenix hbase sql,看看XX大厂都在用,你要不用,小伙伴们的心在骚动,特别要是在创业公司里,大家喜欢用直接好用看上去高大上的的看法会更多,处理不好,一个Leader的印象被打折扣,为以后的研发管理埋下隐患,一遍是跃跃欲试,一边是明明知这玩意儿并非想象的那样

但是,技术,技术人的热情,千万不要去浇灭,即使有错,也要让这种热情熊熊燃烧,这是一个研发管理者需要GET到的点儿...

phoenix hbase

安装过程,百度一下都有了,然而有些你是百度不到的,即使你百度了,也是很奇怪网络上的答案几乎没有,这么大的网络世界,这么明显典型的错误,居然找遍了网络会找不到,我于是在想,所谓的有些技术分享,是不是稍微关键一些的给藏起来了,才能体现那是真正的技术?这让小编我很彷徨

1. 什么是Phoenix?
 phoenix,中文译为“凤凰”,很美的名字。Phoenix是由saleforce.com开源的一个项目,后又捐给了Apache基金会。它相当于一个Java中间件,提供jdbc连接,操作hbase数据表。Phoenix是一个HBase的开源SQL引擎。你可以使用标准的JDBC API代替HBase客户端API来创建表,插入数据,查询你的HBase数据。Phoenix的团队用了一句话概括Phoenix:'We put the SQL back in NoSQL' 意思是:我们把SQL又放回NoSQL去了!这边说的NoSQL专指HBase,意思是可以用SQL语句来查询Hbase,你可能会说:“Hive和Impala也可以啊!”。但是Hive和Impala还可以查询文本文件,Phoenix的特点就是,它只能查Hbase,别的类型都不支持!但是也因为这种专一的态度,让Phoenix在Hbase上查询的性能超过了Hive和Impala!


2. Phoenix性能

Phoenix是构建在HBase之上的SQL引擎。你也许会存在“Phoenix是否会降低HBase的效率?”或者“Phoenix效率是否很低?”这样的疑虑,事实上并不会,Phoenix通过以下方式实现了比你自己手写的方式相同或者可能是更好的性能(更不用说可以少写了很多代码):
编译你的SQL查询为原生HBase的scan语句。
检测scan语句最佳的开始和结束的key。
精心编排你的scan语句让他们并行执行。
推送你的WHERE子句的谓词到服务端过滤器处理。
执行聚合查询通过服务端钩子(称为协同处理器)。

除此之外,Phoenix还做了一些有趣的增强功能来更多地优化性能:
实现了二级索引来提升非主键字段查询的性能。
统计相关数据来提高并行化水平,并帮助选择最佳优化方案。
跳过扫描过滤器来优化IN,LIKE,OR查询。
优化主键的来均匀分布写压力。


3. Phoenix的安装部署
3.1、准备工作
提前安装好ZK集群、hadoop集群、Hbase集群

3.2、安装包
从对应的地址下载:http://mirrors./apache/phoenix/
这里我们使用的是:
5.0.0-HBase-2.0-bin.tar.gz

3.3、上传、解压
将对应的安装包上传到对应的Hbase集群其中一个服务器的一个目录下
解压:tar -zxvf 5.0.0-HBase-2.0-bin.tar.gz -C /var/local
重命名:mv p5.0.0-HBase-2.0 phoenix
3.4、配置
(1) 将phoenix目录下的5.0.0-HBase-2.0server.jar、
phoenix-core-5.0.0-HBase-2.0.jar拷贝到各个 hbase的lib目录下。
(2) 将hbase的配置文件hbase-site.xml、 hadoop/etc/hadoop下的core-site.xml 、hdfs-site.xml放到phoenix/bin/下,替换phoenix原来的配置文件。
(3) 重启hbase集群,使Phoenix的jar包生效。
3.5、验证是否成功
(1) 在phoenix/bin下输入命令:
端口可以省略


[root@gec01 bin]# ./sqlline.py localhost:2181



出现如下界面输入!tables说明启动成功

 

 这里,hbase 版本要用2. 0,尝试过2.25暂时不行,也就是和phoenix包名英,当你执行sqlline的时候,大多数时候是不会成功的,网络上也没有答案,千篇一律的都会告诉你安装好了,就可以执行成功,这里有两个点儿,一个是python需要2.7的版本,开始的时候装了一个python3的版本,折腾好久,也没好心的博主给写出来,技术?OMG,即使你装上PYTHON2.7再执行的时候还是可能报错,可以尝试把$PHOENIX_OPTS删除,如果还出现更多的错误,需要调试一下python了,小编也是这样,网络上找不到答案就自己调试代码了

然后就是你的springboot集成phoenix hbase了,马上sql on hbase 就要可以了,哇哈哈

<dependency> <groupId>org.apache.hbase</groupId> <artifactId>hbase-client</artifactId> <version>2.1.5</version></dependency><!-- https:///artifact/org.apache.phoenix/phoenix-core --><dependency> <groupId>org.apache.phoenix</groupId> <artifactId>phoenix-core</artifactId> <version>5.0.0-HBase-2.0</version></dependency>

结果你一跑,又是报错,Springboot/phoenix-client工程log4j与logback冲突,网络上找一通答案,告诉你

1. 检查是否引入jcl-over-slf4j包;

2. 可在SpringApplication.run(BigDataOpenBootstrap.class, args);启动之前显示指定使用slf4jLogFactory

System.setProperty('org.apache.commons.logging.LogFactory','org.apache.commons.logging.impl.SLF4JLogFactory');

再次启动,OK!!!

源码跟踪(原理):commons-logging-1.1.1.jar org.apache.commons.logging.LogFactory.getFactory(


或者 <exclusion>去除对应的log4j,然而小编试了,没什么用,当然同学们可以再调试一下上面的方法,这时懵逼了,一路上来尽是坑,最后干脆暴力一点儿,winrar打开对应jar包,删除log4j目录,上传maven私服,往下跑DEMO

public class PhoenixTest {
static Connection conn = null; static ResultSet rs = null; /** * 创建一个新的链接不是一个昂贵的操作,所以这里就不使用连接池了。 * @return */ @Before public void getConnection() { try { // jdbc 的 url 类似为 jdbc:phoenix [ :<zookeeper quorum> [ :<port number> ] [ :<root node> ] ], conn = DriverManager.getConnection('jdbc:phoenix:node1,node2,node3:2181'); } catch (SQLException e) { e.printStackTrace(); } }
@After public void close(){ System.out.println('close........'); if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } @Testpublic void create() { try { String createSql = 'CREATE TABLE user (id varchar PRIMARY KEY,name varchar ,passwd varchar)'; PreparedStatement ps = conn.prepareStatement(createSql); ps.execute(); ps.close(); } catch (SQLException e) { e.printStackTrace(); }}@Testpublic void upsert() { try { String upsertSql = 'upsert into user(id, name, passwd) values(?, ?, ?)';// String[] param = {'1', '张三', '123456'}; String[] param = {'2', '李四', '111111'}; PreparedStatement ps = conn.prepareStatement(upsertSql); for (int i = 1; i <= param.length; i++) { ps.setString(i, param[i - 1]); } ps.executeUpdate(); conn.commit(); // you must commit ps.close(); } catch (SQLException e) { e.printStackTrace(); }}@Testpublic void query() { try { String sql = 'select * from user'; String[] param = null;
PreparedStatement ps = conn.prepareStatement(sql); if (param != null) { for (int i = 1; i <= param.length; i++) { ps.setString(i, param[i - 1]); } }
rs = ps.executeQuery(); ResultSetMetaData meta = rs.getMetaData(); int colLength = meta.getColumnCount(); List<String> colName = new ArrayList<>(); for (int i = 1; i <= colLength; i++) { colName.add(meta.getColumnName(i)); }
List<String[]> result = new ArrayList<>(); String[] colArr; while (rs.next()) { colArr = new String[colLength]; for (int i = 0; i < colLength; i++) { colArr[i] = rs.getString(colName.get(i)); } result.add(colArr); } ps.close(); System.out.println(JSON.toJSONString(result)); } catch (Throwable e) { e.printStackTrace(); }}}

一跑,居然可以用SQL语句查询记录了,这个时候还不支持 namespace,如果使用了hbase中的自定义namespace,不仅仅使用default,那么在phoenix中与之对应的是schema的概念,但是默认并没有开启,需要在hbase-site.xml中增加以下配置项:

<property> <name>phoenix.schema.isNamespaceMappingEnabled</name> <value>true</value> </property> <property> <name>phoenix.schema.mapSystemTablesToNamespace</name> <value>true</value>    </property>

再一跑,立马报错说,你的client和server都要配置phoenix.schema.isNamespaceMappingEnabled为true,服务器端就是修改hbase-site.xml配置,客户端是哪里呢,这里是通过springboot java连接的,就上面的一段代码, conn = DriverManager.getConnection('jdbc:phoenix:node1,node2,node3:2181'),于是习惯性的百度,告诉你什么界面里配置,或者就是客户端配置里这几个字,或者setConnectionProperties,这东西不是connection的属性吗,和phoenix挂钩不上呀,没下文了,哈哈,又懵逼了,没招,跟踪源码,idea里断点debug呀,最后发现phoenix.schema.isNamespaceMappingEnabled这个值默认为false,那必须要有外界的来源呀,改变呀,最后发现是DriverManager.getConnection('jdbc:phoenix:node1,node2,node3:2181')的后面可以跟一个参数,打开官网文档明明白白的告诉了,

Connection conn = DriverManager.getConnection('jdbc:phoenix:server1,server2:3333',props);

立马来劲了:

  Properties props = new Properties();  props.put('phoenix.schema.isNamespaceMappingEnabled',true);  Connection conn = DriverManager.getConnection('jdbc:phoenix:server1,server2:3333',props);

又满怀欣喜的跑起来了,结果一跑还是报同样的错误,再次陷入深思,不再是懵逼,老板时不时过来问,小XX,搞得怎么样了,你一头大汗,没有逻辑,肯定是有逻辑能找到的,这种东西网络上再次搜遍了,几乎没有,又只能硬着头皮调试源码,最后发现尼玛,设置属性的时候,居然true需要是String类型,修改一下:

Properties props = new Properties(); props.put('phoenix.schema.isNamespaceMappingEnabled','true'); Connection conn = DriverManager.getConnection('jdbc:phoenix:server1,server2:3333',props);

居然还和其他包有点儿不一样,OMG,再跑,大功告成,至于更细节的使用和优化可以在此基础上进行,源码跟踪也就是idea里debug跟踪,常常看到有些时候一看到源码跟踪,会什么源码,感觉就高深莫测,这不是我们的技术世界观,特别是java,很多时候debug还是比较方便的,这要算技术吗?或许算,但是离真正的技术或许还差很远,这只是一种典型的逻辑思维而已;大多数的互联网技术建立于此,而知识的海洋是无穷的,都是通过这种逻辑思维去理解世界,理解代码,很多事情都是可以打开那扇窗的,没有那么神秘,也没有那么傲娇,建立更加深入的IT基础设施或许才是我们更加任重道远的任务

如何研发管理时髦技术

上面,我们已经讲过了最重要的一点儿,要在条件许可下充分保持研发人员的热情,但是这个不是无限度的,就如phoenix hbase sql来举例子吧,看上去很多大公司在用,但在实际使用过程中有很多坑需要排除,数据不多时性能损耗也不大,看上去是不错的选择,如果还是创业公司,没有那么多人力财力来专门排坑,甚至完善,使用原生的性能和API相对成本更小,大多数看上去高大上的东西不过是一层从产品意义的包装,而实际真正高大上的东西是更底层的东西

那么面对这些东西,如何既能保持研发人员的热情又能有效的产出呢,我们刚开始做研发管理的时候,常常觉得老板这么看重你,给了钱,就应该忠心耿耿,特别是以前包括大家是不是经常听说各种各样的说法,要忠心才能达到一定高度,所以小编也是信了,就巴不得一点儿时间都不应该浪费,时时都应该高效产出,比如研发同学说要用个什么新技术,要重构,虽然说明明用起来不合适,付出的力气要比收货的少很多,老板最后肯定会打屁股的,所以以前的时候是立马反驳,这样XX不对,但是程序员同学是对市面上比较热门的技术感兴趣的,这样弄了以后可以多赚钱,这就两头为难,后面慢慢发现只要在时间允许的时间范围内,给研发人员一定灵活度,让感兴趣的同学稍微研究一下,在小范围内应用,通过过程让大家理解为什么这样选型不好,就像很多创业公司很多同学一上来就要spring cloud而不是spring boot一样,公司里毕竟要产生效益,不是试验场,而适度的试验新技术又会保持团队的技术热情,因为消耗了团队的积极性,积累到一定度,最后老板还是会拍中层管理者的,说个笑话,有时不必争分夺秒,团结好团队的人心或许更重要,至于技术上使用外部组件看官方文档往往更重要,更准确,就像phoenix hbase上面过程一样跑了半圈都没搜索到官方文档却在首页给出了答案

关于技术选型,没有最好的,只有更合适的,结合公司的情况,团队的情况,项目的情况,量体裁衣,稳定高效往往是最优先的

知识的海洋无穷无尽,大多大同小异,逻辑思维的技术呈现,掌握方法和思路往往比掌握技术一个点儿更好

愿大家多赚钱,有所收获,然后用这些赚的钱去丰富一个更加美好的家庭和社会,研发更加充当研发的角色,而不是苦力和背锅的角色

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多