MyCat - 源代码篇(10)

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

3. 连接模块

3.5 后端连接

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

还是那之前的流程,

Created with Raphaël 2.1.0MyCat接受客户端连接并为之建立唯一绑定的SessionMyCat接受客户端的请求,计算路由根据请求和路由创建合适的handler,这里为SingleNodeHandler从PhysicalDBNode中获取后端连接尝试获取连接,连接够用?将请求发送给对应连接,处理完之后归还连接尝试异步创建新的连接通过DelegateResponseHandler将连接与之前的Handler,这里是SingleNodeHandler绑定yesno

现在我们到了尝试获取连接的阶段
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,启动线程,初始化线程池和连接池等。
  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值