ee ee
欢迎访问 ==>高老师的博客网页
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
ee ee
欢迎访问 ==>高老师的博客网页
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
Part-One:�O�思�S
$$ $$
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�烧咧��g的�P�S是什�N? 是控制的�P�S��?
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语言来实现实现这十项法则。
请参考:<Java+C>多层平台架构的十项法则
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造形直接落实为类别(代码),如下�E:
我相信,基于这个优化的架构设计,你就很容易取得下列问题的答案了:
此架构的控制点在哪里? myDbHelper类别是谁开发的呢?
此EIT造形与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开发者了。
=========================================================
相�P文章:<Android与iOS/WP8跨平台整合设计与开发 专栏>
$$ $$
Part-Two:Java�cC整合技�g-- 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