分析catlet,画出Mycat收到新连接请求,执行SQL,返回结果集的过程中所涉及到的重要类,方法,以及逻辑
样例SQL:Select a.id,a.name,b.title from a,b where a.id=b.id
分布:假如sql涉及到多个节点。
大概mycat的流程如下:
1,前端sql请求过来,调用RouteService类,会跟原始SQL进行判断需要返回哪个 RouteResultset,同时会对返回结果进行缓存,在这个类里面加载catletclass,并且调用route方法、调用processSQL方法。
public RouteResultset route(SystemConfig sysConfig, SchemaConfig schema,
int sqlType, String realSQL, String charset, ServerConnection sc,
LayerCachePool cachePool, String hintSQLValue,int hintSqlType, Map hintMap)
throws SQLNonTransientException {
// sc.setEngineCtx ctx
String cateletClass = hintSQLValue;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("load catelet class:" + hintSQLValue + " to run sql "
+ realSQL);
}
try {
Catlet catlet = (Catlet) MycatServer.getInstance()
.getCatletClassLoader().getInstanceofClass(cateletClass);
catlet.route(sysConfig, schema, sqlType, realSQL,charset, sc, cachePool);
catlet.processSQL(realSQL, new EngineCtx(sc.getSession2()));
} catch (Exception e) {
LOGGER.warn("catlet error "+e);
throw new SQLNonTransientException(e);
}
return null;
}
1.1,new DirectDBJoinHandler(ctx)加载handler
1.2,ctx.executeNativeSQLSequnceJob(dataNodes,sql,joinHandler);一个个处理节点,串行不并行担心内存撑了(bty,可以设置大内存用来并行处理吗)
public void executeNativeSQLSequnceJob(String[] dataNodes, String sql,
SQLJobHandler jobHandler) {
for (String dataNode : dataNodes) {
SQLJob job = new SQLJob(jobId.incrementAndGet(), sql, dataNode,
jobHandler, this);
bachJob.addJob(job, false);
}
}
2,Jobhandler处理
2.1 onHeadler方法;记录当前处理的datanode数据节点和处理字段
2.2 onRowData方法;收到一行记录开始处理,根据fielads得到id信息
2.3 rows.put(id,rowData)方法、ids.offer(id)方法;放入结果集
2.4 createQryJob方法;满足>1000调用,执行下一批job,进去B里面
2.5 executeNativeSQLParallJob方法;获取join的B表数据,
2.6 onRowData方法;获取id字符,加入A表记录形成新的报文结果集,有B字段
2.7 ctx.writeRow(rowDataPkg)方法;把新记录write出来
3,循环执行1.2到2.7遍历完所有节点
4,onAllJobFinished方法;
5,ctx.writeEof方法;最后执行ctx写入,输出结果集标记,前端就可以得到执行结果了。
–随笔
1,EngineCtx类,里面有一个jobId,保持每一个sql的job任务都是唯一的,jobId递增。
2,EngineCtx(NonBlockingSession session){…}里面保存了sql的job任务
3,会去调用executeNativeSQLSequnceJob(String[] datanodes,String sql,SQLJobHandler jobHandler)方法在executeNativeSQLSequnceJob方法里面,会循环数据节点组datenodes,每一个循环里面先new SQLJob一个SQLJob出来(SQLJob sqljob=new SQLJob(jobId.incrementAndGet(),sql,dateNode,jobHandler,this);),sqljob会包含sql信息和datanode节点信息,然后讲这个sqljob添加进来,有一个参数false和true,true表示立即执行这个job,代码:bachJob.addJob(sqljob,true);然后在addJob方法里面,就会调用runJob方法。
4,讲下SQL Job
在connnectionAcquired方法里面,一句代码conn.query()异步通知处理后端数据,调用了rowResponse方法rowEofReponse方法,这里面执行代码conn.syncAndExcute()来执行数据处理,而数据处理都是交给SQLJobHandler来实现。里面就有个报文头onHeader(),onRowData()数据处理,finished()处理过程,实际上只要实现了QLJobHandler就可以实现我们自己的catlet了。
5,catlet
catlet只有2个接口,一个是processSQL,一个是route,route就是路由到什么地方去的问题,在HintCatletHandler里面做路由端口,先加载一个catlet,然后会调用catlet.route方法,route过程中主要是去看catlet产生哪样一些的job去执行,然后调用processSQL去执行。
6,catlet demo
以一个跨节点的SQL为例,
Select a.id,a.name,b.title from a,b where a.id=b.id
其中a在分片1,2,3上,b在4,5,6上,需要把数据全部拉到本地(MyCAT服务器),执行JOIN逻辑,具体过程如下(只是一种可能的执行逻辑):
EngineCtx ctx=new EngineCtx();//包含 MyCat.SQLEngine
String sql=,“select a.id ,a.name from a ”;
//在a表所在的所有分片上顺序执行下面的本地SQL
ctx. executeNativeSQLSequnceJob(allAnodes,new DirectDBJoinHandler());
DirectDBJoinHandler类是一个回调类,负责处理SQL执行过程中返回的数据包,这里的这个类,主要目的是用a表返回的ID信息(这里会调用onRowData方法,满足1000条后,去调用createQryJob返回b表的数据),去b表上查询对于的记录,做实时的关联
String sql=” select b.id, b.title from hotnews b where id in (………….)”;
拼出 a.id ,a.name,b.title 完整的一行记录并输出到前端。