Openresty/Lua + Thrift + HBase

来源:互联网 发布:网络机顶盒刷机通用版 编辑:程序博客网 时间:2024/06/01 10:25

1. 问题

在Openresty环境下(也就是lua语言下),如何访问HBase?Lua不方便调用HBase的原生API(Java),所以只能通过别的方式,例如:

  • Rest
  • Thrift
Rest提供的接口不够丰富,比如checkAndPut就没有支持,所以,有必要尝试一下Thrift.


2. Thrift是什么

简单来说,Thrift是一种SOA(Service Oriented Architecture)的实现方式,和WSDL+SOAP那一套类似。过程都是这样的:

  • 以一种接口语言定义接口(对于WSDL+SOAP是.wsdl文件;对于Thrift是.thrift文件);
  • 使用一个编译器,把接口文件(.wsdl或者.thrift)转化为代码(客户端类和服务端虚基类/接口);
  • 继承服务端虚基类/接口,实现服务端逻辑;并部署服务;
  • 基于客户端类,通过少量的开发即可实现客户端,与服务端通信。
Thrift或者WSDL+SOAP框架帮助程序员实现远程方法调用,在整个过程中,程序员不用考虑参数的序列化、网络传输、返回数据的反序列化,甚至包括安全、事务等方面的工作。

3. 环境

  • CentOS 7
  • Luajit:为了很好的和openresty结合,我们使用openresty 1.9.15.1包自带的luajit;它和lua 5.1兼容;
  • Thrift 0.9.2:目前最新版是0.9.3,但是Thrift 0.9.3需要lua 5.2及以上版本,所以我们使用和lua 5.1兼容的Thrift 0.9.2。这为我们带来很多麻烦,因为Thrift 0.9.2有一些bug,见后文Thrift安装部分;
  • HBase 1.2.2:它里面有两个Thrift Server:thrift基于HBase的老API;thrift2基于HBase的新API;我们使用后者。

4. HBase安装与配置

HBase的安装与配置涉及到Hadoop hdfs和zookeeper,这里略去其过程。HBase服务成功启动后,启动Thrift服务:

# /usr/local/hbase-1.2.2/bin/hbase-daemon.sh start thrift2 -p 9090 --infoport 9095



5. Openresty安装

目前我们只需要使用luajit,但为了后续与openresty兼容,干脆这里把openresty安装了,后面实验直接使用它自带的luajit。假定已经安装了PCRE,OpenSSL等依赖:

# cd /tmp/# wget https://openresty.org/download/openresty-1.9.15.1.tar.gz# tar zxvf openresty-1.9.15.1.tar.gz# cd openresty-1.9.15.1/# ./configure --prefix=/usr/local/openresty-1.9.15.1 --without-lua51 --with-luajit# gmake# gmake install# ln -s /usr/local/openresty-1.9.15.1/luajit/lib/libluajit-5.1.so /usr/lib64/libluajit-5.1.so# ln -s /usr/local/openresty-1.9.15.1/luajit/lib/libluajit-5.1.so.2 /usr/lib64/libluajit-5.1.so.2
现在,我们就有了luajit:/usr/local/openresty-1.9.15.1/luajit/


6. 安装Thrift

6.1 安装依赖

# yum install readline.x86_64 install readline-devel.x86_64# yum install libtool.x86_64# yum install boost.x86_64 boost-devel.x86_64# yum install byacc.x86_64# yum install flex.x86_64 flex-devel.x86_64 # yum install openssl.x86_64 openssl-devel.x86_64

6.2 编译安装Thrift

# cd /tmp/# git clone https://github.com/apache/thrift# cd thrift/# git branch -a# git checkout -b 0.9.2 origin/0.9.2    <-- 切换到0.9.2版本# ./bootstrap.sh# ./configure --prefix=/usr/local/thrift-0.9.2 LUA=/usr/local/openresty-1.9.15.1/luajit/bin/luajit LUA_INCLUDE=-I/usr/local/openresty-1.9.15.1/luajit/include/luajit-2.1 LUA_LIB=-lluajit-5.1

修改bug1:

# vim lib/lua/src/luabpack.c106c106<   size_t len = lua_rawlen(L, 2);--->   size_t len = lua_objlen(L, 2);


修改bug2:

# vim lib/lua/Makefile385a386,387> LUA_INCLUDE=-I/usr/local/openresty-1.9.15.1/luajit/include/luajit-2.1> LUA_LIB=-lluajit-5.1516,517c518,519< libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) -I/usr/include/lua5.2 -DLUA_COMPAT_MODULE< libluasocket_la_LDFLAGS = $(AM_LDFLAGS) -llua5.2 -lm---> libluasocket_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE> libluasocket_la_LDFLAGS = $(AM_LDFLAGS) $(LUA_LIB) -lm519,520c521,522< libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) -I/usr/include/lua5.2 -DLUA_COMPAT_MODULE< libluabpack_la_LDFLAGS = $(AM_LDFLAGS) -llua5.2 -lm---> libluabpack_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE> libluabpack_la_LDFLAGS = $(AM_LDFLAGS) $(LUA_LIB) -lm523,524c525,526< libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) -I/usr/include/lua5.2 -DLUA_COMPAT_MODULE< libluabitwise_la_LDFLAGS = $(AM_LDFLAGS) -llua5.2 -lm---> libluabitwise_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE> libluabitwise_la_LDFLAGS = $(AM_LDFLAGS) $(LUA_LIB) -lm529,530c531,532< liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) -I/usr/include/lua5.2 -DLUA_COMPAT_MODULE< liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS) -llua5.2 -lm---> liblualongnumber_la_CPPFLAGS = $(AM_CPPFLAGS) $(LUA_INCLUDE) -DLUA_COMPAT_MODULE> liblualongnumber_la_LDFLAGS = $(AM_LDFLAGS) $(LUA_LIB) -lm

修改bug3:

# vim lib/lua/Makefile508a509>                       liblualongnumber.la \510,511c511<                       libluabitwise.la \<                       liblualongnumber.la--->                       libluabitwise.la

好,现在开始make并make install。若make因缺失依赖而失败,需要make clean,重新configure,重新fix上面的bug,然后重试make。

# make# make install

另外,make install不会拷贝lua库,所以需要手动拷贝

# mkdir /usr/local/thrift-0.9.2/lualib# cp lib/lua/*.lua /usr/local/thrift-0.9.2/lualib/

修改bug4:错误 Thrift.lua:43: malformed number near '0.9.2'

# vim /usr/local/thrift-0.9.2/lualib/Thrift.lua43c43< version = 0.9.2---> --version = 0.9.2

修改bug5:创建TBufferedTransport实例时,误创建为的TTransportBase实例。

# vim /usr/local/thrift-0.9.2/lualib/TBufferedTransport.lua40c40<   return TTransportBase:new(obj)--->   return TTransportBase.new(self,obj)

Thrift安装完毕!


7. 访问HBase

7.1 找到.thrift文件

下载HBase 1.2.2源代码,里面包含两个.thrift文件。它们是接口定义文件,类似于WSDL+SOAP里面的.wsdl文件:

# find . -name "*.thrift"./hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift2/hbase.thrift./hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift
我们只需要上面那个,它是thrift2的接口定义。


7.2 编译.thrift文件生成lua文件

# cd /home# mkdir test# cd test/# cp /home/hbase-1.2.2/hbase-thrift/src/main/resources/org/apache/hadoop/hbase/thrift2/hbase.thrift .# /usr/local/thrift-0.9.2/bin/thrift -r --gen lua hbase.thrift# lsgen-lua  hbase.thrift# ll gen-lua/           <--生成的目录和文件total 120-rw-r--r--. 1 root root   136 Aug 30 10:04 hbase_constants.lua-rw-r--r--. 1 root root 74532 Aug 30 10:04 hbase_THBaseService.lua-rw-r--r--. 1 root root 38447 Aug 30 10:04 hbase_ttypes.lua


修改bug6: 生成代码错误

# vim gen-lua/hbase_ttypes.lua508c508<     oprot:writeListBegin(TType.STRUCT, string.len(self.columns))--->     oprot:writeListBegin(TType.STRUCT, #self.columns)<strong></strong>


7.3 使用生成的lua文件访问HBase

# mkdir mycode# vim mycode/client.lua

#!/usr/local/openresty-1.9.15.1/luajit/bin/luajitrequire('TSocket')require('TBufferedTransport')require('TFramedTransport')--require('THttpTransport')--require('TCompactProtocol')--require('TJsonProtocol')require('TBinaryProtocol')require('liblualongnumber')require('hbase_THBaseService')local client = nilfunction teardown()  if client then    -- close the connection    client:close()  endendfunction parseArgs(rawArgs)  local opt = {    protocol='binary',    transport='buffered',    port='9090',  }  for i, str in pairs(rawArgs) do    if i > 0 then      k, v = string.match(str, '--(%w+)=(%w+)')      assert(opt[k] ~= nil, 'Unknown argument')      opt[k] = v    end  end  return optendfunction assertEqual(val1, val2, msg)  assert(val1 == val2, msg)endfunction testBasicClient(rawArgs)  local opt = parseArgs(rawArgs)  local socket = TSocket:new{    port = tonumber(opt.port)  }  assert(socket, 'Failed to create client socket')  socket:setTimeout(5000)  local transports = {    buffered = TBufferedTransport,    framed = TFramedTransport,    http = THttpTransport,  }  assert(transports[opt.transport] ~= nil)  local transport = transports[opt.transport]:new{    trans = socket,    isServer = false  }  local protocols = {    binary = TBinaryProtocol,    compact = TCompactProtocol,    json = TJSONProtocol,  }  assert(protocols[opt.protocol] ~= nil)  local protocol = protocols[opt.protocol]:new{    trans = transport  }  assert(protocol, 'Failed to create binary protocol')  client = THBaseServiceClient:new{    protocol = protocol  }  assert(client, 'Failed to create client')  -- Open the transport  local status, _ = pcall(transport.open, transport)  assert(status, 'Failed to connect to server')  --1. check if a row exists  local tget = TGet:new{      row="UUUU1234_bucket1"  }  local ok,ret = pcall(client.exists, client, "bucket", tget)  if not ok or not ret then      print("client:exists failed")  else      print("client:exists succeeded:")      print("\t", ret)  end  --2. get a row  local ok,ret = pcall(client.get, client, "bucket", tget)  if not ok or not ret then      print("client:get failed")  else      print("client:get succeeded:")      local row=ret.row      for i,v in pairs(ret.columnValues) do          print("\t",row, v.family..":"..v.qualifier, v.value)      end  endendtestBasicClient(arg)teardown()

我是参照thrit源代码中test_basic_client.lua搞通的,前文提到的bug5也是在这个测试中发现。当然,HBase里的数据是我通过hbase shell手动插入的,这里只测试它是否存在,并get出来。


7.4 测试

为了方便运行,我写了个脚本:

# vim client.sh

#!/bin/bashTEST_HOME=/home/testTHRIFT_HOME=/usr/local/thrift-0.9.2LUA_HOME=/usr/local/openresty-1.9.15.1/luajitrm -fr gen-lua$THRIFT_HOME/bin/thrift -r --gen lua hbase.thriftexport LUA_PATH="$THRIFT_HOME/lualib/?.lua;$TEST_HOME/gen-lua/?.lua;$TEST_HOME/mycode/?.lua;;"export LUA_CPATH="$THRIFT_HOME/lib/?.so;;"$LUA_HOME/bin/luajit mycode/client.lua

运行结果:

# ./client.shclient:exists succeeded:                trueclient:get succeeded:                UUUU1234_bucket1        exattrs:content movies                UUUU1234_bucket1        info:ctime      Thu, 11 Aug 2016 02:14:45 +0000                UUUU1234_bucket1        info:mtime      Thu, 11 Aug 2016 02:14:45 +0000                UUUU1234_bucket1        quota:enabled   yes                UUUU1234_bucket1        quota:objects   1024                UUUU1234_bucket1        quota:size_mb   1024000                UUUU1234_bucket1        stats:mb_rounded        0                UUUU1234_bucket1        stats:objects   0                UUUU1234_bucket1        stats:size_bytes        0                UUUU1234_bucket1        ver:tag BBBB1234                UUUU1234_bucket1        ver:version     0


8. 下一步

研究HBase Thrift API支持的接口(是否比REST丰富);

测试Thrift的性能;

0 0
原创粉丝点击