Openresty/Lua + Thrift + HBase,openrestythrift
Openresty/Lua + Thrift + HBase,openrestythrift
1. 问题
在Openresty环境下(也就是lua语言下),如何访问HBase?Lua不方便调用HBase的原生API(Java),所以只能通过别的方式,例如:
- Rest
- Thrift
2. Thrift是什么
简单来说,Thrift是一种SOA(Service Oriented Architecture)的实现方式,和WSDL+SOAP那一套类似。过程都是这样的:
- 以一种接口语言定义接口(对于WSDL+SOAP是.wsdl文件;对于Thrift是.thrift文件);
- 使用一个编译器,把接口文件(.wsdl或者.thrift)转化为代码(客户端类和服务端虚基类/接口);
- 继承服务端虚基类/接口,实现服务端逻辑;并部署服务;
- 基于客户端类,通过少量的开发即可实现客户端,与服务端通信。
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="-L/usr/local/stor-openresty/luajit/lib -lluajit-5.1"
修改bug1:
# vim lib/lua/src/luabpack.c
106c106
< size_t len = lua_rawlen(L, 2);
---
> size_t len = lua_objlen(L, 2);
修改bug2:
# vim lib/lua/Makefile
385a386,387
> LUA_INCLUDE=-I/usr/local/openresty-1.9.15.1/luajit/include/luajit-2.1
> LUA_LIB=-lluajit-5.1
516,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) -lm
519,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) -lm
523,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) -lm
529,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/Makefile
508a509
> 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.lua
43c43
< version = 0.9.2
---
> --version = 0.9.2
修改bug5:创建TBufferedTransport实例时,误创建为的TTransportBase实例。
# vim /usr/local/thrift-0.9.2/lualib/TBufferedTransport.lua
40c40
< 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
# ls
gen-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.lua
508c508
< 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/luajit
require('TSocket')
require('TBufferedTransport')
require('TFramedTransport')
--require('THttpTransport')
--require('TCompactProtocol')
--require('TJsonProtocol')
require('TBinaryProtocol')
require('liblualongnumber')
require('hbase_THBaseService')
local client = nil
function teardown()
if client then
-- close the connection
client:close()
end
end
function 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 opt
end
function assertEqual(val1, val2, msg)
assert(val1 == val2, msg)
end
function 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
end
end
testBasicClient(arg)
teardown()
我是参照thrit源代码中test_basic_client.lua搞通的,前文提到的bug5也是在这个测试中发现。当然,HBase里的数据是我通过hbase shell手动插入的,这里只测试它是否存在,并get出来。
7.4 测试
为了方便运行,我写了个脚本:
# vim client.sh
#!/bin/bash
TEST_HOME=/home/test
THRIFT_HOME=/usr/local/thrift-0.9.2
LUA_HOME=/usr/local/openresty-1.9.15.1/luajit
rm -fr gen-lua
$THRIFT_HOME/bin/thrift -r --gen lua hbase.thrift
export 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.sh
client:exists succeeded:
true
client: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的性能;
评论暂时关闭