此文已由作者张镐薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

3. 连接模块

3.5 后端连接

3.5.2 后端连接获取与维护管理

还是那之前的流程,

st=>start: MyCat接受客户端连接并为之建立唯一绑定的Session
e=>end: 将请求发送给对应连接,处理完之后归还连接
op1=>operation: MyCat接受客户端的请求,计算路由
op2=>operation: 根据请求和路由创建合适的handler,这里为SingleNodeHandler
op3=>operation: 从PhysicalDBNode中获取后端连接
cond=>condition: 尝试获取连接,连接够用?
op4=>operation: 尝试异步创建新的连接
op5=>operation: 通过DelegateResponseHandler将连接与之前的Handler,这里是SingleNodeHandler绑定
st->op1->op2->op3->condcond(yes)->econd(no)->op4->op5->e

现在我们到了尝试获取连接的阶段 PhysicalDataSource.java:

public void getConnection(String schema,boolean autocommit, final ResponseHandler handler,    final Object attachment) throws IOException {//从当前连接map中拿取已建立好的后端连接
    BackendConnection con = this.conMap.tryTakeCon(schema,autocommit);    if (con != null) {//如果不为空,则绑定对应前端请求的handler
        takeCon(con, handler, attachment, schema);        return;
    } else {//如果为空,新建连接
        int activeCons = this.getActiveCount();//当前最大活动连接
        if(activeCons+1>size){//下一个连接大于最大连接数
            LOGGER.error("the max activeConnnections size can not be max than maxconnections");            throw new IOException("the max activeConnnections size can not be max than maxconnections");
        }else{            // create connection
            LOGGER.info("not ilde connection in pool,create new connection for " + this.name
                    + " of schema "+schema);
            createNewConnection(handler, attachment, schema);
        }     } }
private void createNewConnection(final ResponseHandler handler,        final Object attachment, final String schema) throws IOException {    //异步创建连接,将连接的handler绑定为DelegateResponseHandler
    MycatServer.getInstance().getBusinessExecutor().execute(new Runnable() {        public void run() {            try {
                createNewConnection(new DelegateResponseHandler(handler) {                    @Override
                    public void connectionError(Throwable e,
                            BackendConnection conn) {
                        handler.connectionError(e, conn);
                    }                    @Override
                    public void connectionAcquired(BackendConnection conn) {
                        takeCon(conn, handler, attachment, schema);
                    }
                }, schema);
            } catch (IOException e) {
                handler.connectionError(e, null);
            }
        }
    });
}

异步调用工厂方法创建后端连接,这里为MySQLConnection MySQLDataSource.java:

@Override
    public void createNewConnection(ResponseHandler handler,String schema) throws IOException {
        factory.make(this, handler,schema);
}

根据之前所述,MySQLConnection的工厂方法会先将NIOhandler设置为MySQLConnectionAuthenticator: MySQLConnectionFactory.java:

public MySQLConnection make(MySQLDataSource pool, ResponseHandler handler,
            String schema) throws IOException {        //DBHost配置
        DBHostConfig dsc = pool.getConfig();        //根据是否为NIO返回SocketChannel或者AIO的AsynchronousSocketChannel
        NetworkChannel channel = openSocketChannel(MycatServer.getInstance()
                .isAIO());        //新建MySQLConnection
        MySQLConnection c = new MySQLConnection(channel, pool.isReadNode());        //根据配置初始化MySQLConnection
        MycatServer.getInstance().getConfig().setSocketParams(c, false);
        c.setHost(dsc.getIp());
        c.setPort(dsc.getPort());
        c.setUser(dsc.getUser());
        c.setPassword(dsc.getPassword());
        c.setSchema(schema);        //目前实际连接还未建立,handler为MySQL连接认证MySQLConnectionAuthenticator,传入的handler为后端连接处理器ResponseHandler
        c.setHandler(new MySQLConnectionAuthenticator(c, handler));
        c.setPool(pool);
        c.setIdleTimeout(pool.getConfig().getIdleTimeout());        //AIO和NIO连接方式建立实际的MySQL连接
        if (channel instanceof AsynchronousSocketChannel) {
            ((AsynchronousSocketChannel) channel).connect(                    new InetSocketAddress(dsc.getIp(), dsc.getPort()), c,
                    (CompletionHandler) MycatServer.getInstance()
                            .getConnector());
        } else {            //通过NIOConnector建立连接
            ((NIOConnector) MycatServer.getInstance().getConnector())
                    .postConnect(c);         }        return c;
    }

这里传入的ResponseHandler为DelegateResponseHandler,在连接建立验证之后,会调用: MySQLConnectionAuthenticator.java:

public void handle(byte[] data) {    //省略                
    //设置ResponseHandler
    if (listener != null) {
            listener.connectionAcquired(source);
    }    //省略}

DelegateResponseHandler.java:

private final ResponseHandler target;@Override
   public void connectionAcquired(BackendConnection conn) {   //将后端连接的ResponseHandler设置为target
   target.connectionAcquired(conn);
}

这样,原来没获取到连接的ResponseHandler就获得需要的连接,之后进行处理。处理完后,归还到连接池中。

private void returnCon(BackendConnection c) {    //清空连接的Attachment
    c.setAttachment(null);    //设置为未使用
    c.setBorrowed(false);    //更新上次使用时间,用于清理空闲连接
    c.setLastTime(TimeUtil.currentTimeMillis());    //获取连接池对应的队列
    ConQueue queue = this.conMap.getSchemaConQueue(c.getSchema());    //按照是否Autocommit分类归还连接
    boolean ok = false;    if (c.isAutocommit()) {
        ok = queue.getAutoCommitCons().offer(c);
    } else {
        ok = queue.getManCommitCons().offer(c);
    }    //归还失败,关闭连接,记录
    if (!ok) {         LOGGER.warn("can't return to pool ,so close con " + c);
        c.close("can't return to pool ");
    }
}

4.配置模块

MyCat实例初始化时究竟会有什么操作呢?看下MyCat程序入口: MycatStartup.java:

public static void main(String[] args) {    //是否启用zk配置,/myid.properties中的loadZk属性决定,默认不启用,从本地xml文件中读取配置
    ZkConfig.instance().initZk();    try {
        String home = SystemConfig.getHomePath();        if (home == null) {
            System.out.println(SystemConfig.SYS_HOME + "  is not set.");
            System.exit(-1);
        }        // init
        MycatServer server = MycatServer.getInstance();
        server.beforeStart();        // startup
        server.startup();
        System.out.println("MyCAT Server startup successfully. see logs in logs/mycat.log");        while (true) {
            Thread.sleep(300 * 1000);
        }
    } catch (Exception e) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        LogLog.error(sdf.format(new Date()) + " startup error", e);
        System.exit(-1);
    }
}

从代码中,可以简单的分为三步:

  1. MycatServer.getInstance():获取MyCat实例,其实就是读取配置文件,并验证正确性等

  2. server.beforeStart():获取环境变量,日志配置

  3. server.startup():启动MyCat,启动线程,初始化线程池和连接池等。

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 SVN迁移到GIT
【推荐】 移动端推广APP防作弊机制之依我见

数据库路由中间件MyCat - 源代码篇(10)的更多相关文章

  1. 数据库路由中间件MyCat - 源代码篇(1)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...

  2. 数据库路由中间件MyCat - 源代码篇(13)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.配置模块 4.2 schema.xml 接上一篇,接下来载入每个schema的配置(也就是每个MyCat ...

  3. 数据库路由中间件MyCat - 源代码篇(7)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.4 FrontendConnection前端连接 构造方法: public Fronte ...

  4. 数据库路由中间件MyCat - 源代码篇(15)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. public static void handle(String stmt, ServerConnectio ...

  5. 数据库路由中间件MyCat - 源代码篇(17)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 调用processInsert(sc,schema,sqlType,origSQL,tableName,pr ...

  6. 数据库路由中间件MyCat - 源代码篇(14)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...

  7. 数据库路由中间件MyCat - 源代码篇(4)

    此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  8. 数据库路由中间件MyCat - 源代码篇(2)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  9. 数据库路由中间件MyCat - 源代码篇(16)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 5. 路由模块 真正取得RouteResultset的步骤:AbstractRouteStrategy的ro ...

随机推荐

  1. 关于IE和Firefox兼容性问题及解决办法

    1.//window.eventIE:有window.event对象FF:没有window.event对象.可以通过给函数的参数传递event对象.如onmousemove=doMouseMove(e ...

  2. 移动端toast 提示,HTML css 全屏垂直水平居中

  3. Vue打包后页面出现cannot get

    学习Vue有大半个月了,然而遇到了不少坑,完全没有高手们那么容易,中间有不少值得记录下的东东,回头好好理理.先理下今天的: Vue打包命令简单啊,直接在命令行输入:npm run build 然而没一 ...

  4. C#启动或停止 计算机中“服务”

    第一.要添加一个引用System.ServiceProcess 第二.要在程序中使用命名空间ServiceProcess 代码片段: using System.ServiceProcess; Serv ...

  5. Android应用瘦身

    转:https://zhuanlan.zhihu.com/p/25465537 瘦身的目的 从目的导向来看,我们是不会无缘无故去做一件事情的,那我们对应用瘦身的目的是为了什么?答案是:提高下载转化率. ...

  6. 【软件使用心得】Quartus和ISE调用Synplify进行综合的问题

    分别尝试采用Quartus和ISE调用第三方综合软件Synplify进行综合. [软件版本] Quartus II 13.0 (SP).ISE 14.4 .Synplify 201303. [问题描述 ...

  7. Grafana 安装使用

    Grafana 安装使用 官方网址:https://grafana.com/ 官方文档:http://docs.grafana.org/ 安装 grafana 基于 RPM 的系统(CentOS,Fe ...

  8. IOS 线程描述

    ●什么是线程 ● 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程) ● 线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行 ● 比如使用酷狗播放音乐.使用迅雷下载电影, ...

  9. IOS NSBundle使用(访问文件夹)

    NSBundle的相关信息 1.一个NSBundle代表一个文件夹,利用NSBundle能访问对应的文件夹 2.利用mainBundle就可以访问软件资源包中的任何资源 3.模拟器应用程序的安装路径: ...

  10. linux下安装redis和使用

    http://www.linuxidc.com/Linux/2014-05/101979.htm