5.路由模块5.5AST语义解析路由DruidParser结构:基本使用解析代码://sql是一组SQL语句MySqlStatementParserparser=newMySqlStatementParser(sql);//获取每个语句粗粒度的parse结果List<SQLStatement>statementList=parser.parseStatementList();//获取每个语句更细粒度的parse结果for(SQLStatementstatement:statementList){MySqlSchemaStatVisitorvisitor=newMySqlSchema
5.路由模块5.4DDL语句路由可以分为两步,整体源代码:publicstaticRouteResultsetrouteToDDLNode(RouteResultsetrrs,intsqlType,Stringstmt,SchemaConfigschema)throwsSQLSyntaxErrorException{stmt=getFixedSql(stmt);Stringtablename="";finalStringupStmt=stmt.toUpperCase();if(upStmt.startsWith("CREATE")){if(upStmt.
5.路由模块真正取得RouteResultset的步骤:AbstractRouteStrategy的route方法:对应源代码:publicRouteResultsetroute(SystemConfigsysConfig,SchemaConfigschema,intsqlType,StringorigSQL,Stringcharset,ServerConnectionsc,LayerCachePoolcachePool)throwsSQLNonTransientException{/***处理一些路由之前的逻辑*全局序列号,父子表插入*/if(beforeRouteProcess(schem
5.路由模块5.1路由模块组成:路由模块,我们可以先把他当做个黑盒,看下输入和输出都是神马。输入,很明显,就是个SQL语句,原生的,不加任何修饰的,纯洁的,从客户端发过来刚刚被解码的SQL语句。输出呢?就是个优化,改写后的SQL语句,以及要发送到的后台分片。这个RouteResultSet就是输出,长什么样子呢?下图是主要涉及到的类:RouteResultSet:sqlType:SQL类型(select?insert?…)nodes:语句和Datanode对应关系。一条语句可以根据不同节点拆成多条不同语句subTables:分表,1.6后功能,单node多表sqlStatement:经过Dru
4.配置模块4.2schema.xml接上一篇,接下来载入每个schema的配置(也就是每个MyCat中虚拟化的数据库的配置):XMLSchemaLoader.javaprivatevoidloadSchemas(Elementroot){NodeListlist=root.getElementsByTagName("schema");for(inti=0,n=list.getLength();i<n;i++){ElementschemaElement=(Element)list.item(i);//读取各个属性Stringname=schemaElement.get
4.配置模块每个MyCatServer初始化时,会初始化:MyCatServer.java:publicstaticfinalStringNAME="MyCat";privatestaticfinallongLOG_WATCH_DELAY=60000L;privatestaticfinallongTIME_UPDATE_PERIOD=20L;privatestaticfinalMycatServerINSTANCE=newMycatServer();privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger("My
3.连接模块3.5后端连接3.5.2后端连接获取与维护管理还是那之前的流程,CreatedwithRaphaël2.1.0MyCat接受客户端连接并为之建立唯一绑定的SessionMyCat接受客户端的请求,计算路由根据请求和路由创建合适的handler,这里为SingleNodeHandler从PhysicalDBNode中获取后端连接尝试获取连接,连接够用?将请求发送给对应连接,处理完之后归还连接尝试异步创建新的连接通过DelegateResponseHandler将连接与之前的Handler,这里是SingleNodeHandler绑定yesno现在我们到了尝试获取连接的阶段Physic
3.5.1后端连接获取与负载均衡上一节我们讲了后端连接的基本建立和响应处理,那么这些后端连接是什么时候建立的呢?首先,MyCat配置文件中,DataHost标签中有minIdle这个属性。代表在MyCat初始化时,会在这个DataHost上初始化维护多少个连接(这些连接可以理解为连接池)。每个前端Client连接会创建Session,而Session会根据命令的不同而创建不同的Handler。每个Handler会从连接池中拿出所需要的连接并使用。在连接池大小不够时,RW线程会异步驱使新建所需的连接补充连接池,但是连接数最大不能超过配置的maxCon。同时,如之前所述,有定时线程检查并回收空闲后
3.连接模块3.5后端连接对于后端连接,我们只关心MySQL的。从后端连接工厂开始MySQLConnectionFactory.java:publicMySQLConnectionmake(MySQLDataSourcepool,ResponseHandlerhandler,Stringschema)throwsIOException{//DBHost配置DBHostConfigdsc=pool.getConfig();//根据是否为NIO返回SocketChannel或者AIO的AsynchronousSocketChannelNetworkChannelchannel=openSocket
3.连接模块3.4FrontendConnection前端连接构造方法:publicFrontendConnection(NetworkChannelchannel)throwsIOException{super(channel);InetSocketAddresslocalAddr=(InetSocketAddress)channel.getLocalAddress();InetSocketAddressremoteAddr=null;if(channelinstanceofSocketChannel){remoteAddr=(InetSocketAddress)((SocketChanne
3.连接模块3.3AbstractConnection:3.3.2NIOHandlerNIOHandler实际上就是对于业务处理方法的封装,对于不同的连接有不同的处理方法,也就是不同的NIOHandlerpublicinterfaceNIOHandler{voidhandle(byte[]data);}它的实现以及子类会在之后的对应的处理模块细讲。3.3.3NIOSocketWR实现对于AbstractConnection(实际就是对里面封装的channel)进行异步读写,将从channel中读取到的放到AbstractConnection的readBuffer中,将writeBuffer和写
3.连接模块如之前所述,MyCat的连接分为前端和后端,下面是连接基本相关类图:3.1ClosableConnection:publicinterfaceClosableConnection{StringgetCharset();//关闭连接voidclose(Stringreason);booleanisClosed();publicvoididleCheck();longgetStartupTime();StringgetHost();intgetPort();intgetLocalPort();longgetNetInBytes();longgetNetOutBytes();}根据字面意
2.前端连接建立与认证CreatedwithRaphaël2.1.0MySql连接建立以及认证过程clientclientMySqlMySql1.TCP连接请求2.接受TCP连接3.TCP连接建立4.握手包HandshakePacket5.认证包AuthPacket6.如果验证成功,则返回OkPacket7.默认会发送查询版本信息的包8.返回结果包2.5(7~8)默认会发送查询版本信息的包,返回结果包MySql客户端在连接建立后,默认会发送查询版本信息的包,这其实就是一个SQL查询请求了。只不过这个请求不用路由到后台某个数据库^_^。连接成功建立后,连接绑定的RW线程会监听上面的读事件。在客户
2.前端连接建立与认证CreatedwithRaphaël2.1.0MySql连接建立以及认证过程clientclientMySqlMySql1.TCP连接请求2.接受TCP连接3.TCP连接建立4.握手包HandshakePacket5.认证包AuthPacket6.如果验证成功,则返回OkPacket7.默认会发送查询版本信息的包8.返回结果包2.3(5~6)认证包AuthPacket,如果验证成功,则返回OkPacket继续执行FrontendConnection的register()方法://异步读取并处理,这个与RW线程中的asynRead()相同,之后客户端收到握手包返回AuthP
2.前端连接建立与认证CreatedwithRaphaël2.1.0MySql连接建立以及认证过程clientclientMySqlMySql1.TCP连接请求2.接受TCP连接3.TCP连接建立4.握手包HandshakePacket5.认证包AuthPacket6.如果验证成功,则返回OkPacket7.默认会发送查询版本信息的包8.返回结果包2.2(4)握手包HandshakePacketNIOReactor其实就是一个网络事件反应转发器。很多地方会用到NIOReactor,这里先讲FrontendConnection和NIOReactor绑定这一部分。上一节说到,NIOAcceptor
进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式。然后,针对每一个重点模块进行分析。MyCat整体框架图:1.整体通信与业务框架:前端与后端通信框架都为NIO/AIO,因为目前生产上用的linux发行版内核都没有真正实现网络上的AIO,如果应用用AIO的话可能比NIO还要慢一些,所以,我们这里只分析NIO相关的通信模块。相关类图:NIOAcceptor:作为服务器接受客户端连接(前端NIO通信)NIOConnector:作为客户端去连接后台数据库(MySql,后端NIO通信)NIOReactor:Reactor模式的NIO,处理并转发请求到
配置MyCat-eye接下来在开始使用MyCat之前,我们先把监控平台部署好。下载MyCat-eye项目,mvn打包。之后得到类似于Mycat-web-1.0-SNAPSHOT-20160215151602-linux.tar.gz这个文件,部署到和zookeeper同一台服务器上。如果要部署到其他机器,需要修改mycat-web\mycat-web\WEB-INF\classes\mycat.properties配置文件zookeeper=x.x.x.x:xxxx运行./start.sh启动之后访问http://localhost:8082/mycat/可以看到:Mycat主要是维护myca
配置MyCat4.配置schema.xmlschema.xml里面管理着MyCat的逻辑库、表,每张表使用的分片规则、分布在哪个DataNode以及DataSource上。之前的例子:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmycat:schemaSYSTEM"schema.dtd"><mycat:schemaxmlns:mycat="http://org.opencloudb/"><!--schema就是逻辑库,相当于My
配置MyCat3.配置conf/rule.xml1.5GA版本中的规则配置比较笨,2.0中优化了一些,将tableRule标签和function标签合并了,并且支持Velocity模板语言,更加灵活。这里先介绍1.5GA的,2.0等以后稳定了,会推的:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmycat:ruleSYSTEM"rule.dtd"><mycat:rulexmlns:mycat="http://org.opencloudb/"
全局序列号数据切分后,原有的关系数据库中的主键约束在分布式条件下将无法使用,因此需要引入外部机制保证数据唯一性标识,这种保证全局性的数据唯一标识的机制就是全局序列号(sequence)。1.本地文件方式classpath下有一个sequence_conf.properties文件:GLOBAL_SEQ.HISIDS=GLOBAL_SEQ.MINID=1001GLOBAL_SEQ.MAXID=1000000000GLOBAL_SEQ.CURID=1000HISIDS表示历史使用过的值,MINID为ID最小值,MAXID为ID最大值,CURID为当前值。需要在server.xml加入如下配置:&l
基本概念3.分片3.1分片节点(dataNode)表被水平切分后,每个分片表所在的数据库就是一个分片节点。一个分片节点对应一个数据库(mysql数据库)。一个分片节点只能保存每个分片表的一个分片,因为db中不允许出现同名的表。例如:<dataNodename="test1"dataHost="test"database="db1"/>这就表示,名字为test1这个分片节点,对应test节点主机(MySQL实例)主机上的db1数据库3.2节点主机(dataHost)分片节点究竟被放在那个主机上。对应mysql里的mysql实
基本概念直接介绍概念太枯燥了,还是拿个和背景篇相似的例子介绍业务场景:客户完成下单,快递员接受并更新运单状态,客户可以随时查看运单状态的任务。一票快递可能有多个子母件。同时,我们需要标记每个运单的状态,运单状态的解释和含义保存在运单状态字典表中。因此,我们需要建立如下表:我们现在按照业务将数据库垂直拆分成运单库(单表2000tps,6000W数据),快递员库(单表1500tps,100W数据),客户库(单表1500tps,1000W数据记录);假设每个MySQL数据库单表不能超过2000W数据,单表不能超过1000tps。那么运单库则需要分成3片,客户库需要分成2片,统一由MyCat管理。如下
MyCat的前世今生如前文所说,Amoeba、Cobar、MyCat等属于同宗一脉。若Amoeba能继续下去,Cobar就不会出来;若Cobar那批人不是都走光了的话,MyCAT也不会再另起炉灶。Cobar之后,有很多类似中间件仿照其架构以及思路,针对特定的业务场景,设计出了不同的中间件。MyCat算是其中业务场景比较全面,使用配置比较简便,性能优秀,而且功能算是稳定的。同类的中间件,都是针对特定场景或者功能进行设计,像某科技的hot某中间件,性能和功能更为稳定,但是业务场景有局限,扩展分布性不是很好。所以,我们这里对MyCat进行较为全面的剖析,以供广大程序猿同志们的参考:)MyCat架构对
SQL与NoSQL目前,对于互联网海量数据的存储以及处理,按使用场景,分为OLTP(联机事务处理,比如即时交易,强调快速响应与处理)与OLAP(联机分析处理,比如BI,强调多维数据分析)。对于这些数据的存储,主要有两种解决方案,即基于SQL的关系型数据库,和NoSQL的非关系型数据库。非关系型数据库在某些特定场景下有奇效,比如键值存储(redis,ROMA,Memcached)数据库应用在排行更新,会话保存,面向文档的数据库(mongoDB、couchDB)应用在日志记录,面向列的数据库(Cassandra、HBase)在博客中的应用。关系型数据库最大的问题在于速度与可扩展性上,而这些NoSQ