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

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

4.配置模块

每个MyCatServer初始化时,会初始化: MyCatServer.java:

public static final String NAME = "MyCat";private static final long LOG_WATCH_DELAY = 60000L;private static final long TIME_UPDATE_PERIOD = 20L;private static final MycatServer INSTANCE = new MycatServer();private static final Logger LOGGER = LoggerFactory.getLogger("MycatServer");private final RouteService routerService;private final CacheService cacheService;private Properties dnIndexProperties;//AIO连接群组private AsynchronousChannelGroup[] asyncChannelGroups;private volatile int channelIndex = 0;//全局序列号private final MyCATSequnceProcessor sequnceProcessor = new MyCATSequnceProcessor();private final DynaClassLoader catletClassLoader;private final SQLInterceptor sqlInterceptor;private volatile int nextProcessor;private BufferPool bufferPool;private boolean aio = false;//XA事务全局ID生成private final AtomicLong xaIDInc = new AtomicLong();private MycatServer() {    //读取文件配置
    this.config = new MycatConfig();    //定时线程池,单线程线程池
    scheduler = Executors.newSingleThreadScheduledExecutor();    //SQL记录器
    this.sqlRecorder = new SQLRecorder(config.getSystem()
            .getSqlRecordCount());    /**
     * 是否在线,MyCat manager中有命令控制
     * | offline | Change MyCat status to OFF |
     * | online | Change MyCat status to ON |
     */
    this.isOnline = new AtomicBoolean(true);    //缓存服务初始化
    cacheService = new CacheService();    //路由计算初始化
    routerService = new RouteService(cacheService);    // load datanode active index from properties
    dnIndexProperties = loadDnIndexProps();    try {        //SQL解析器
        sqlInterceptor = (SQLInterceptor) Class.forName(
                config.getSystem().getSqlInterceptor()).newInstance();
    } catch (Exception e) {        throw new RuntimeException(e);
    }    //catlet加载器
    catletClassLoader = new DynaClassLoader(SystemConfig.getHomePath()
            + File.separator + "catlet", config.getSystem()
            .getCatletClassCheckSeconds());    //记录启动时间
    this.startupTime = TimeUtil.currentTimeMillis();
}

第一步是读取文件配置,主要是三个文件:schema.xml,rule.xml和server.xml. 读取后的配置会加载到MyCatConfig中。 MyCatConfig.java:

public MycatConfig() {//读取schema.xml,rule.xml和server.xmlConfigInitializer confInit = new ConfigInitializer(true);this.system = confInit.getSystem();this.users = confInit.getUsers();this.schemas = confInit.getSchemas();this.dataHosts = confInit.getDataHosts();this.dataNodes = confInit.getDataNodes();for (PhysicalDBPool dbPool : dataHosts.values()) {
    dbPool.setSchemas(getDataNodeSchemasOfDataHost(dbPool.getHostName()));
}this.quarantine = confInit.getQuarantine();this.cluster = confInit.getCluster();//初始化重加载配置时间this.reloadTime = TimeUtil.currentTimeMillis();this.rollbackTime = -1L;this.status = RELOAD;//配置加载锁this.lock = new ReentrantLock();
}

它们都通过ConfigInitializer读取:

public ConfigInitializer(boolean loadDataHost) {    //读取schema.xml
    SchemaLoader schemaLoader = new XMLSchemaLoader();    //读取server.xml
    XMLConfigLoader configLoader = new XMLConfigLoader(schemaLoader);
    schemaLoader = null;    //加载配置
    this.system = configLoader.getSystemConfig();    this.users = configLoader.getUserConfigs();    this.schemas = configLoader.getSchemaConfigs();    //是否重新加载DataHost和对应的DataNode
    if (loadDataHost) {        this.dataHosts = initDataHosts(configLoader);        this.dataNodes = initDataNodes(configLoader);
    }    //权限管理
    this.quarantine = configLoader.getQuarantineConfig();    this.cluster = initCobarCluster(configLoader);    //不同类型的全局序列处理器的配置加载
    if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_MYSQLDB) {
        IncrSequenceMySQLHandler.getInstance().load();
    }    if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_LOCAL_TIME) {
        IncrSequenceTimeHandler.getInstance().load();
    }    //检查user与schema配置对应以及schema配置不为空
    this.checkConfig();
}

4.1 rule.xml

读取schema之前会先读取rule.xml。 XmlSchemaLoader.java:

public XMLSchemaLoader(String schemaFile, String ruleFile) {    //先读取rule.xml
    XMLRuleLoader ruleLoader = new XMLRuleLoader(ruleFile);    this.tableRules = ruleLoader.getTableRules();
    ruleLoader = null;    this.dataHosts = new HashMap<String, DataHostConfig>();    this.dataNodes = new HashMap<String, DataNodeConfig>();    this.schemas = new HashMap<String, SchemaConfig>();    //读取加载schema配置
    this.load(DEFAULT_DTD, schemaFile == null ? DEFAULT_XML : schemaFile);
}public XMLSchemaLoader() {    this(null, null);
}

XMLRuleLoader.java:

public XMLRuleLoader(String ruleFile) {    // this.rules = new HashSet<RuleConfig>();
    //rule名 -> rule
    this.tableRules = new HashMap<String, TableRuleConfig>();    //function名 -> 具体分片算法
    this.functions = new HashMap<String, AbstractPartitionAlgorithm>();    //默认为:/rule.dtd和/rule.xml
    load(DEFAULT_DTD, ruleFile == null ? DEFAULT_XML : ruleFile);
}public XMLRuleLoader() {    this(null);
}
private void load(String dtdFile, String xmlFile) {
    InputStream dtd = null;
    InputStream xml = null;    try {
        dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile);
        xml = XMLRuleLoader.class.getResourceAsStream(xmlFile);        //读取出语意树
        Element root = ConfigUtil.getDocument(dtd, xml)
                .getDocumentElement();        //加载Function
        loadFunctions(root);        //加载TableRule
        loadTableRules(root);
    } catch (ConfigException e) {        throw e;
    } catch (Exception e) {        throw new ConfigException(e);
    } finally {        if (dtd != null) {            try {
                dtd.close();
            } catch (IOException e) {
            }
        }        if (xml != null) {            try {
                xml.close();
            } catch (IOException e) {
            }
        }
    }
}

ConfigUtil.java解析语意树:

public static Document getDocument(final InputStream dtd, InputStream xml) throws ParserConfigurationException,
            SAXException, IOException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setValidating(true);
    factory.setNamespaceAware(false);
    DocumentBuilder builder = factory.newDocumentBuilder();
    builder.setEntityResolver(new EntityResolver() {        @Override
        public InputSource resolveEntity(String publicId, String systemId) {            return new InputSource(dtd);
        }
    });
    builder.setErrorHandler(new ErrorHandler() {        @Override
        public void warning(SAXParseException e) {
        }        @Override
        public void error(SAXParseException e) throws SAXException {            throw e;
        }        @Override
        public void fatalError(SAXParseException e) throws SAXException {            throw e;
        }
    });    return builder.parse(xml);
}

加载functions,XmlRuleLoader.java

private void loadFunctions(Element root) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException,
            InvocationTargetException {
        NodeList list = root.getElementsByTagName("function");        for (int i = 0, n = list.getLength(); i < n; ++i) {
            Node node = list.item(i);            if (node instanceof Element) {
                Element e = (Element) node;                //获取name标签
                String name = e.getAttribute("name");                //如果Map已有,则function重复
                if (functions.containsKey(name)) {                    throw new ConfigException("rule function " + name
                            + " duplicated!");
                }                //获取class标签
                String clazz = e.getAttribute("class");                //根据class利用反射新建分片算法
                AbstractPartitionAlgorithm function = createFunction(name, clazz);                 ParameterMapping.mapping(function, ConfigUtil.loadElements(e));                //每个AbstractPartitionAlgorithm可能会实现init来初始化
                function.init();                //放入functions map
                functions.put(name, function);
            }
        }
    }private AbstractPartitionAlgorithm createFunction(String name, String clazz)
        throws ClassNotFoundException, InstantiationException,
        IllegalAccessException, InvocationTargetException {
    Class<?> clz = Class.forName(clazz);    //判断是否继承AbstractPartitionAlgorithm
    if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) {        throw new IllegalArgumentException("rule function must implements "
                + AbstractPartitionAlgorithm.class.getName() + ", name=" + name);
    }
    return (AbstractPartitionAlgorithm) clz.newInstance();
}

加载所有的function的node,每一个node就是一个AbstractPartitionAlgorithm,并放入functions这个map中;

private final Map<String, TableRuleConfig> tableRules;

对于每一个node,通过反射新建对应参数的AbstractPartitionAlgorithm。这样,所有的function就加载到了functions这个map中。
同理,加载TableRule,就加上了function是否存在的判断:

/**
* tableRule标签结构:
 * <tableRule name="sharding-by-month">
 *     <rule>
 *         <columns>create_date</columns>
 *         <algorithm>partbymonth</algorithm>
 *     </rule>
 * </tableRule>
 * @param root
 * @throws SQLSyntaxErrorException
    */private void loadTableRules(Element root) throws SQLSyntaxErrorException {    //获取每个tableRule标签
    NodeList list = root.getElementsByTagName("tableRule");    for (int i = 0, n = list.getLength(); i < n; ++i) {
        Node node = list.item(i);        if (node instanceof Element) {
            Element e = (Element) node;            //先判断是否重复
            String name = e.getAttribute("name");            if (tableRules.containsKey(name)) {                throw new ConfigException("table rule " + name
                        + " duplicated!");
            }            //获取rule标签

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

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

相关文章:
【推荐】 JAVA异常的最佳工程学实践探索
【推荐】 深入解析SQL Server高可用镜像实现原理

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

  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. 如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题

    https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/09.3.md 9.3 锁和 sync 包 在一些复杂的程序中,通常通 ...

  2. 性能测试--Jmeter的Non GUI模式、集群

    Jmeter的Non GUI模式.集群 一.Non GUI模式 1.一般情况下在NonGUI模式下运行jmeter,有两个好处: 节省系统资源,能够产生更大的负载 可以通过命令行参数对测试场景进行更精 ...

  3. Apache NiFi 开发 处理器使用说明

    NIFI的使用: 注意:FlowFile由[属性]和[内容]组成,在解析的过程中这个概念非常重要,因为有些组件操作的是属性,有些组件操作的是内容,在配置组件时Destination配置项的选择很重要, ...

  4. 如何使用ipv6

    需要系统至少是Vista以上还有就是要问你们学校是否已经支持IPV6 从Windows Vista开始,IPv6在默认状态下已经安装并启用,无需额外配置.检测步骤开启浏览器窗口,输入以下域名访问本站首 ...

  5. WIFI模块ESP8266的使用指南【转】

    本文转载自:http://www.itdadao.com/articles/c15a814052p0.html 本文主要对讲述ESP8266模块硬件连接工作,以及作为服务器和客户端情况下的配置实现的详 ...

  6. Linux常用命令全集

    一,安装和登陆命令1,进入图形界面 startx 2,进入图形界面 init 5 3,进入字符界面 init 34,登陆 login 5,关机 poweroff -p 关闭机器的时候关闭电源-n 在关 ...

  7. 算法(Algorithms)第4版 练习 1.3.12

    方法实现: package com.qiusongde; import java.util.Iterator; import java.util.NoSuchElementException; imp ...

  8. BZOJ 1201 [HNOI2005]数三角形:枚举 + 前缀和

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1201 题意: 有一个边长为n的正三角形网格,去掉其中一些线段,问你在这幅图中有多少个三角形 ...

  9. listen 65

    Don't Treat Old Gadgets Like Garbage Did you get a new tablet or computer this holiday season? A new ...

  10. mysql一次性和多次取数据的性能测试

    1.表结构 2.数据量 3.代码 先从学生表里面查出300名学生,然后找出每个学生的班级信息,然后merge起来 3.性能对比 第一种:每次取一条 第二种:一次全去除 4.总结 不能循环取从数据库中取 ...