<Java/Hbase + C>多层框架(大数据)云平台的架构设计_答问集
Part-One:
設計思維
$$ $$
Q&A#1
Question
:
在建置大数据平台时采用
Hbase
。这
H base
是以
Java
开发的,其提供了
Java
基础接口,在
C
层则使用
thrift
机制。如果咱们的
C
层模块想存取
Hbase
时,使用的技术是:
C
调用
jni
,再调用
Hbase
的
Java
接口
(
亦即
C->jni->Java)
,但这种架构方式,会导致性能下降,该如何解决这个议题呢
?
Answer(
高老师
)
回答:
这个议题可以将
Command flow
与
Data flow
分开来。并且离清你的
Data Source
是
C
层
(
可能是先已经从
Hbase
查询出来,放在
C
层了
)
或是还在
Java
层的
Hbase
里。如果
Data Source
是在
Hbase
里,其
thrif
接口就是
Data Source
接口。因此,
Data Source
接口都在
C
层,而你的
Client (Data destination)
是在
C
层。于是:
-
Data flow
是
C->C
,不要经由
Java
层,效率就极高。
-
Command flow
可以经过
Java
层,有助于控制点放在
Java
层。
-
Command flow
:
C->JNI->Java
接口,要求
Java
模块把
HBase
端的
C
接口传递给
Client
。
-
Data flow: Client
调用
HBase
端的
C
接口
(
若跨进程,可透过
IBinder
接
口
)
,取得
data
。
Q&A#
2
Question
:
Command flow
和Data flow
兩者之間的關係是什麼? 是
控制的關係嗎?
Answer(
高老师
)
回答:
软件有两种
flow
,
一种是
Command flow
;另一种是
data flow
。例如控制
camera
的信息是
Control flow
;而传送
preview
视像的是
data flow
。可以透过
command flow API
去通知两端的模块,动态取动两端插件,透过动态
API(
如
Config
文件提供
)
串接两端;静态
Command API
支撑动态
Data API
。
Q&A#3
Question
:
在
C/C++
平台上建立
Java
框架,其主要目的是什么
?
Answer(
高老师
)
回答:
可
让
Java Client
端开发者自己来撰写后台的插件。于是,后台成为一朵真正的云
(Cloud)
了。
一个
C/C++
平台可以搭配多个不同语言的框架。兹以
Java
为例,可
使用
JNI(Java Native Interface)
。其中,
C/C++
平台的
<
业务规则
BR
引擎
>
可以搭配一个
Java
框架。如下图:
因为
C/C++
模块
(
如
<
业务规则引擎
>)
可以调用
Java
函数,所以
C/C++
平台仍然拥有主控权。
Q&A#4
Question
:
高老师,
有没有
提升
<Java /Hbase+C>
平台架构质量的
要点
?
Answer(
高老师
)
回答:
于
2003
年,我在日本东京工作时,
曾经
提出
了
<Java+C>
多层
平台架构的十项主要法则,并且
创作
了
LW_OOPC
语言来实现实现这十项法则。
Q&A#5
Question
:
我的
Android
应用
app
怎么设计架构呢
?
我希望分层的方式设计,我一直找不到好的设计方式,请高老师帮忙解惑。
Answer(
高老师
)
回答:
我认为
App
不是分
layer
,这样会让
App
绑住于系统平台。我认为
App
应该分离出插件
(Plug-in)
,包括
(
因
)
平台
(OS
而变
)
的插件、
(
因
)
用户
(
而变的
)
插件、买主插件等等;然后以
Framework-based
平台
(
如
phoneGap)
包容起来,让插件能
PnP
。
Q&A#6
Question
:
什么是
Framework-based
平台呢
?
Answer(
高老师
)
回答:
简单的公式是:
平台
=
框架
+
引擎。相对上,古典的观念里,其公式是:平台
=(
服务
)
引擎。例如:
上图是古典思维下的架构。在
Framework-based
新思维下,为了维护底层
<
引擎
>
的变动自由度,就采用新架构,如下:
于是,得出典型的
Framework-based
平台架构:
当今的
.NET
、
iOS
、
Android
平台都是这种架构,而
App
就是一种插件,应用层也是插件层。
Q&A#7
Question
:
Framework-based
平台如何保护底层
(
引擎
)
模块的变动自由度呢
?
Answer(
高老师
)
回答:
兹以
Database
引擎来说明之。在传统的平台架构里,其结构为:
这会
降低引擎的变动自由度。兹
优化以下上述的架构:加上一个
EIT
造形,如下图所述:
将
EIT
造形直接落实为类别
(
代码
)
,如下圗:
我相信,基于这个优化的架构设计,你就很容易取得下列问题的答案了:
-
此架构的控制点在哪里
? myDbHelper
类别是谁开发的呢
?
-
此
E
IT
造形与
Factory
模式有何差异呢
?
-
EIT
造形如何保护
DB
引擎的变动自由度呢
?
-
SQLite
引擎可以
”
没钱就改版,改版就有钱
”
吗
?
Q&A#8
Question
:
如何规划
(
设计
)
云平台的
<
业务规则
(BR)
引擎
>
挿件架构呢
?
Answer(
高老师
)
回答:
首先替引擎设计一个
EIT
造形,并将成长为框架,如下途所述:
其中,插件包括
3
种:
App(
用户
)
插件、业务
(
业主
)
插件和平台插件。如下图:
看似复杂的架构,却只是
3
个
EIT
造形的巧妙组合而已。
Q&A#9
Question
:
如何采
敏捷
(Agile)
或
RUP
的跌代过程来建置云平台呢
?
Answer(
高老师
)
回答:
这两种方法都是跌代
(Iterative)
的模式
,也都是渐增
(Incremental)
的模式。首先,需求分析可以衔接传统的
<
双插式分析法
>
,如下图:
接着,定订出优先的
User Story
;并进一步以
System Use Case
表达出来。
依循
I&I
和
Use Case-Driven
途径,以
EIT
造形来表示接口,如下图:
然后将
EIT
造形落实为类别和代码,
如下图:
随着
<
领域概念
>
分析和
<
业务规则
>
分析,得到更多的业务概念、类别和规则,就以前面所述的
<
平台
&
插件
>
关系来组织和重构。如下图所示:
此架构模式,既能搭配敏捷开发,也能搭配
RUP
方法。
Q&A#10
Question
:
Framework-based
云平台如何
<
插件接口
>
给
Client
端呢
?
Answer(
高老师
)
回答:
通常
,
后台的业务或平台插件的开发者
,
与
Client
开发者
是不同的
;
而且开发的时间点也不一样
(
插件常开发在先
)
。如下图:
那么
,当
Client
需要调用插件时
,
后台如何提工插件接口给
Client
开发者呢
?
即使
Client
端可以从文件中得知插件的接口
,
又如何调用呢
?
首先
,
后台
<E&I>
提供一个通用型接口
,
内含一个通用型函数。然后,后台提供一个
Proxy
类别给
Client
。如下图:
基于这个架构,你应该可以知道如何提供
Proxy
类别的代码给
Client
开发者了。
=========================================================
相關文章:
<Android与iOS/WP8跨平台整合设计与开发 专栏>
$$ $$
Part-Two:
Java與C整合技術– JNI
$$ $$
Q-1
:在执行
Java
代码时,如果
Java
需要与本地代码
(
如以
C
写成的
*so
动态库
)
沟通时,
VM(
虚拟机
)
扮演甚么角色呢
?
答:
Java
代码在
VM
上执行。
如下图:
在执行
Java
代码的过程中,如果
Java
需要与本地代码
(
如以
C
写成的
*so
动态库
)
沟通时,
VM
就会把
*.so
视为插件
(Plug-in)
而加载到
VM
里,然后让
Java
函数顺利地呼叫到这插件里的
C
函数。
Q-2
:接续上一题,
VM
在那一个时间点,会去加载所需要的插件呢
?
答:请参考下述的代码范例:
// MediaPlayer.java
类
public class MediaPlayer{
static {
System.loadLibrary(“media_jni”);
}
……..
}
当这个
Java
类被加载
(Load)
时,就会执行
System.loadLibrary()
函数,而加载这个
media_jni.so
插件。
如下图:
Q-3
:为什么
Java
与
C
函数不能直接互相调用呢
?
答:
Java
代码执行于
VM
,它透过
VM
来调用
*.so
插件,并不直接调用插件里的本地
add()
函数。
如下图:
C
代码执行于
CPU
,必须透过
VM
才能获得
Java
代码的攸关资源,例如取得
Java
类里的属性及函数
ID
等。
Q-4
:本地
C
函数
(
如
add()
函数
)
的第
1
个参数是:
JNIEnv *env
;如下述代码:
// com_misoo_pk01_addActivity.cpp
………
JNIEXPORT jlong JNICALL
Java_com_misoo_pk01_addActivity_add
(JNIEnv *env, jobject thiz, jint x, jint y){
// ……….
}
// ………
请问,这个
JNIEnv
类的内涵是什么
?
这个
env
指针
(Pointer)
有什么用途呢
?
答:在Java
环境里,每一个线程
(Thread)
第一次进入
VM
去调用本地函数时,
VM
会替它诞生一个相对映的
JNIEnv
对象,记录该线程的状态。而且,该线程每次调用本地函数时,都会将其对映的
JNIEnv
对象指针值传递给本地函数。
不同的线程,会使用不同的
JNIEnv
对向来与
VM
通信。这样有助于化解多线程的冲突问题。
如下图:
Q-5
:有两个本地函数
f1()
和
f2()
,其代码片段如下:
JNIEXPORT jlong JNICALL
Java_com_misoo_pk01_addActivity_f1(JNIEnv *env_1, jobject thiz){
// ……….
}
JNIEXPORT jlong JNICALL
Java_com_misoo_pk01_addActivity_f2(JNIEnv *env_2, jobject thiz){
// ……….
}
}
请问:当同一条线程去执行
f1()
和
f2()
函数,此时
env_1
和
env_2
各指向那一个
JNIEnv
对象呢
?
如果有两条线程
(
如
th-x
和
th-y)
都执行
f1()
函数时,又如何呢
?
答:此时
env_1
和
env_2
都指向同一个
JNIEnv
对象。
如下图:
如果有两条线程
(
如
th-x
和
th-y)
都执行
f1()
函数时,
此时
env_1
指向不同的
JNIEnv
对象。
如下图:
如果由不同的线程分别去执行
f1()
和
f2()
,此时
env_1
和
env_2
各指向不同的
JNIEnv
对象。
如下图:
Q-6
:当
UI
线程经由
VM
而去执行本地
C
函数时,
UI
线程如何去创建一个小线程呢
?
答:兹写代码范例如下:
/* com.misoo.counter.CounterNative.cpp */
#include <stdio.h>
#include <pthread.h>
#include “com_misoo_counter_CounterNative.h”
jmethodID mid;
jclass mClass;
JavaVM *jvm;
pthread_t thread;
int n, sum;
void* trRun( void* );
void JNICALL
Java_com_misoo_counter_CounterNative_nativeSetup(JNIEnv *env, jobject thiz) {
jclass clazz = env->GetObjectClass(thiz);
mClass = (jclass)env->NewGlobalRef(clazz);
mid = env->GetStaticMethodID(mClass, “callback”, “(I)V”);
}
void JNICALL
Java_com_misoo_counter_CounterNative_nativeExec
(JNIEnv *env, jobject thiz, jint numb){
n = numb;
pthread_create( &thread, NULL, trRun, NULL);
}
void* trRun( void* ){
int status;
JNIEnv *env; bool isAttached = false;
status = jvm->GetEnv((void **) &env, JNI_VERSION_1_4);
if(status < 0) {
status = jvm->AttachCurrentThread(&env, NULL);
if(status < 0) return NULL;
isAttached = true;
}
sum = 0;
for(int i = 0; i<=n; i++) sum += i;
env->CallStaticVoidMethod(mClass, mid, sum);
if(isAttached) jvm->DetachCurrentThread();
return NULL;
}
在本地
C
函数里所创建的小线程,
VM
并没有给它专属的
JNIEnv
对象。所以调
AttachCurrentThtread()
函数,向
VM
索取一个
JNIEnv
对象。取得
JNIEnv
对象之后,就能调用
CallStaticVoidMethod()
等函数,请
VM
协助存取
Java
层的资源
(
如调用
Java
层函数
)
。
88 99