mycat源码分析select

搭建源码环境

请先按下面这个说明 把mycat处理起来,
http://blog.csdn.net/mingover/article/details/78846853

下载源码,
覆盖下面三个文件
Mycat-Server\src\main\resources\server.xml
Mycat-Server\src\main\resources\rules.xml
Mycat-Server\src\main\resources\schema.xml

启动进程
MycatStartup.java

从mysql客户端登陆 mycat服务器

mycat中select的执行线程

说明在断点的时候,会有几条请求,如 show states;要认准sql那次

ServerConnection.routeEndExecuteSQL中设置断点,我们可以看到线程内容如下图

$_NIOREACTOR-2-RW@2373" prio=5 tid=0x16 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at io.mycat.server.ServerConnection.routeEndExecuteSQL(ServerConnection.java:275)
      at io.mycat.server.ServerConnection.execute(ServerConnection.java:226)
      at io.mycat.server.handler.SelectHandler.handle(SelectHandler.java:105)
      at io.mycat.server.ServerQueryHandler.query(ServerQueryHandler.java:79)
      at io.mycat.net.FrontendConnection.query(FrontendConnection.java:324)
      at io.mycat.net.FrontendConnection.query(FrontendConnection.java:344)
      at io.mycat.net.handler.FrontendCommandHandler.handle(FrontendCommandHandler.java:71)
      at io.mycat.net.FrontendConnection.rawHandle(FrontendConnection.java:500)
      at io.mycat.net.FrontendConnection.handle(FrontendConnection.java:482)
      at io.mycat.net.AbstractConnection.onReadData(AbstractConnection.java:327)
      at io.mycat.net.NIOSocketWR.asynRead(NIOSocketWR.java:196)
      at io.mycat.net.AbstractConnection.asynRead(AbstractConnection.java:279)
      at io.mycat.net.NIOReactor$RW.run(NIOReactor.java:113)
      at java.lang.Thread.run(Thread.java:744)

 select的对数据分片的思路

既然是分表,在查询的时候,自然 是把sql拆出来到多个节点中查询,通过代码,我们发现下面这几个关键类
ServerConnection.routeEndExecuteSQL -> RouteService.route
以下为获取rrs的内容

/**
* 检查是否有分片
*/
if (schema.isNoSharding() && ServerParse.SHOW != sqlType) {
    rrs = RouterUtil.routeToSingleNode(rrs, schema.getDataNode(), stmt);
} else {
    RouteResultset returnedSet = routeSystemInfo(schema, sqlType, stmt, rrs);
    if (returnedSet == null) {
    rrs = routeNormalSqlWithAST(schema, stmt, rrs, charset, cachePool,sqlType,sc);
}
}

如上图所示 DruidMycatRouteStrategy.routeSystemInfot得到了rrs对象,这个对象是包含了多个节点的sql,其内存内容如下图所示
mycat源码分析select_第1张图片

以下copy自《mycat权威指南》
mycat源码分析select_第2张图片

可以看到,路由中对应两个库,
源sql是 limit 10635,10
对应于两个库 是 limit 0,10645,可以猜想 其是要从两个库中查出这么多数据,然后进行排序取10条数据返回到客户端

在日志里也能看到情况:

2018-04-10 21:48:46,068 [WARN ][$_NIOREACTOR-5-RW] ServerConnection [id=1, schema=TESTDB, host=127.0.0.1, user=root,txIsolation=3, autocommit=true, schema=TESTDB]SELECT * from t_gd_user_copy t limit 10635,10, route={
   1 -> tx_pay{SELECT *
FROM t_gd_user_copy t
LIMIT 0, 10645}
   2 -> tx_pay2{SELECT *
FROM t_gd_user_copy t
LIMIT 0, 10645}

select实现的步骤

如下图,先是得到路由rrs ,而且里面已经有了notes 描述,对每个节点的sql也OK了

public void routeEndExecuteSQL(String sql, final int type, final SchemaConfig schema) {
// 路由计算
RouteResultset rrs = null;
try {
rrs = MycatServer
    .getInstance()
    .getRouterservice()
    .route(MycatServer.getInstance().getConfig().getSystem(),
    schema, type, sql, this.charset, this);

} catch (Exception e) {
    ...
}
    if (rrs != null) {
        // session执行
        session.execute(rrs, rrs.isSelectForUpdate()?ServerParse.UPDATE:type);
    }
}

拿到rrs后,哪里去查的 mysql?

确认路由后,则需要具体去查询 节点的mysql了.
涉及到connection等,
涉及类:PhysicalDBNode.getConnection -> PhysicalDatasource.PhysicalDatasource

处理好conn后 MultiNodeQueryHandler.connectionAcquired 去具体执行sql,发下为关键内容:

private void _execute(BackendConnection conn, RouteResultsetNode node) {
    if (clearIfSessionClosed(session)) {
    return;
}
    conn.setResponseHandler(this);
try {
    conn.execute(node, session.getSource(), autocommit);
} catch (IOException e) {
    connectionError(e, conn);
}
}

如果在conn.execute中继续往 里走,发现 mycat使用的是nio方式,所以,这里不会有返回,返回及其相关内容在 回调函数中处理,

我们也可以在《mycat权威指南》文档中找到相关端倪
mycat源码分析select_第3张图片

sql返回的时候怎么处理?

mycat 请求mysql使用nio方式,则自然不会在发送的线程中处理返回结果。但逻辑还是在handler中

如果是两台机的sql,则两台机发送完sql到mysql后,才会走到nio的resp中处理

MultiNodeQueryHandler 类的以下方法

/**
* 将汇聚结果集数据真正的发送给Mycat客户端
* @param source
* @param eof
* @param
*/
public void outputMergeResult(final ServerConnection source, final byte[] eof,          Iterator iter,AtomicBoolean isMiddleResultDone) {
    ...
}

在哪里回客户端的呢?

采用nio的话,发出和发送就是不同的线程,
如图所示 MultiNodeQueryHandler 处理类中 会把内容write出去,即发送到客户端
mycat源码分析select_第4张图片

上面这个函数是 multiQueryHandler.outputMergeResult .
在这之前,还是有sort之类的逻辑

mycat的nio接入入口

如果你对java的nio编程有了解,可以去从入口中往里走
NIOReactor.run()

@Override
public void run() {
    int invalidSelectCount = 0;
    Set keys = null;
    for (;;) {
        ++reactCount;
    try {
        final Selector tSelector = this.selector;
        long start = System.nanoTime();
        tSelector.select(500L);
        long end = System.nanoTime();
        register(tSelector);
        keys = tSelector.selectedKeys();
        .....

你可能感兴趣的:(java,mycat,源码分析)