Zdal使用指南.doc_第1页
Zdal使用指南.doc_第2页
Zdal使用指南.doc_第3页
Zdal使用指南.doc_第4页
Zdal使用指南.doc_第5页
已阅读5页,还剩18页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Zdal使用指南1. 分库分表概述1.1分库分表的目的 分库分表的主要目的是将数据进行垂直和水平切分,使同一张表的记录可以分散到不同的物理表乃至数据库上,减少单张表的大小,从而提高增删改查的效率。一般来说都会先分库再分表,数据记录先定位到数据库上,再定位到具体的表上。1.2传统的分库分表方式传统的分库分表方式有两种 第一种是通过先对分库分表键进行哈希,然后再取模的方式计算出记录所处的库与表的位置,通常应用于无统一顺序号的表,具有良好的负载均衡能力。但当新增设备做水平扩展时,往往需要对数据进行迁移,带来额外的工作量 第二种是通过顺序号分段的方式计算出记录所处的库与表的位置,通常应用于有统一顺序号的流水信息,具有比较好的扩展能力。但负载均衡能力较差,多张表时,只能一张表写满之后再写另一张表.2. ZDAL系统整体架构zdal组件主要有5部分组成:1) Zdal-client:开发编程接口,实现jdbc的Datasource,Connection,Statement,PreparedStatement,ResultSet等接口,实现通用的jdbc-sql访问,内部还实现读库重试,group数据源的选择器,表名替换,sql执行器等功能;2) Zdal-parser:支持oracle/mysql/db2等数据库的sql语句解析,并且缓存;根据规则引擎提供的参数列表,在指定的sql中查找到需要的参数,然后返回拆分字段;3) Zdal-rule:根据zdal-parser解析后的拆分字段值来确定逻辑库和物理表名;4) Zdal-datasource:数据库连接的管理,支持mysql,oracle,db2数据库的连接管理;5) Zdal-common:zdal组件所使用的一些公共组件类。3. ZDAL配置说明ZDAL需要三个配置:ZdalDataSource配置,-ds.xml用于配置各个数据库的数据源,-rule.xml用于配置分库分表规则。3.1ZdalDataSource配置ZdalDataSource是ZDAL的对外接口,它对分库分表进行了封装,从上层看,ZdalDataSource就是一个普通的数据源。在程序中,通过使用ZdalDataSource完成对数据库的操作。 zdal数据源配置说明(com.alipay.zdal.client.jdbc.ZdalDataSource)属性名可用值说明属性名可用值说明appName必须与ZdalAppBean的appName属性值一致应用名appDsName必须与AppDataSourceBean的appDataSourceName属性值一致指定使用的应用数据源名称dbmode必须与ZdalAppBean的dbmode属性值一致数据库环境configPath指定两个配置文件所在目录的路径,两个配置文件必须位于同一目录下配置文件路径3.2 -ds.xml数据源bean配置文件,例如:shard-dev-ds.xml zdal应用Bean配置说明(com.alipay.zdal.client.config.bean.ZdalAppBean)属性名可用值说明属性名可用值说明appName无约束应用名dbmode无约束数据库环境appDataSourceList内容必须是存在的AppDataSourceBean的id应用数据源列表 zdal应用数据源Bean配置说明(com.alipay.zdal.client.config.bean.AppDataSourceBean)属性名可用值说明属性名可用值说明appDataSourceName无约束应用名dataBaseTypeDB2/ORACLE/MYSQL数据库类型,对应枚举DBType中的值configTypeGROUP/SHARD/SHARD_GROUP/SHARD_FAILOVER读写分离与分库分表类型配置,对应枚举DataSourceConfigType中的值appRule必须与AppRule的id一致分库分表规则physicalDataSourceSet内容必须是存在的PhysicalDataSourceBean的id物理数据源列表 物理数据源配置说明(com.alipay.zdal.client.config.bean.PhysicalDatasourceBean)属性名可用值说明属性名可用值说明Name无约束将被用在rule中用来指定数据源名jdbcUrl例如: jdbc:db2:/02:6000/hcore数据库URLuserName无约束数据库用户名Password无约束数据库密码minConn数字最小连接数maxConn数字最大连接数blockingTimeoutMillis数字,毫秒抛出异常前等待连接的最大时间,此时间不适用于创建新连接。适用于JBOSS,待验证是否适用于其它idleTimeoutMinutes数字,分钟如果连接在指定时间内未使用,将会被回收,zdal每隔idleTimeoutMinutes/2分钟检测一次preparedStatementCacheSize缓存的preparedStatement大小,使用LRU算法,保存的最小preparedStatement个数是2(zdal内部写死),缓存的内容主要是PreparedStatement对象,以及数据库返回的该对象的部分属性,缓存该对象可以减少与数据库服务器通讯的次数,从而加快速度,需要driver支持,oracle-driver支持,mysql-driver不支持queryTimeout数字,秒查询,更新等操作超时时间prefilltrue/false是否预热数据库连接,可以防止连接风暴connectionProperties.connectTimeout不同数据库支持不同属性,这些属性非必要connectionProperties.autoReconnect不同数据库支持不同属性,这些属性非必要connectionProperties.initialTimeout不同数据库支持不同属性,这些属性非必要connectionProperties.maxReconnects不同数据库支持不同属性,这些属性非必要connectionProperties.socketTimeout不同数据库支持不同属性,这些属性非必要connectionProperties.failOverReadOnly不同数据库支持不同属性,这些属性非必要3.3 -rule.xml分库分表规则配置文件,例如shard-dev-rule.xml 应用规则配置(com.alipay.zdal.rule.config.beans.AppRule)属性名可用值说明属性名可用值说明masterRule必须与ShardRule的id相同configType=shard/shard_failover时指定访问主库的各张表的拆分规则slaveRule必须与ShardRule的id相同类似masterRule, 但是用来指定备库的 分表总规则(com.alipay.zdal.rule.config.beans.ShardRule)属性名可用值说明属性名可用值说明tableRules必须与TableRule的logicTableName属性和id值相同每个表都必须配规则,key表达逻辑表名,value-ref对应TableRule对应的id 分表明细规则(com.alipay.zdal.rule.config.beans.TableRule)属性名可用值说明属性名可用值说明dbIndexes例如: 0,false,master_0:slave_0,0:10000;1,true,master_1:slave_1,10001:20000配置数据库分组分段信息,每个分组用分号(;)分隔。配置的具体格式为:分组顺序号(数字), 可新增标识(true/false), 物理数据源1:物理数据源2:., 本组数据开始序号:本组数据结束序号(结束序号为-1时表示不限制);.tbSuffixresetForEachDB/throughAllDB/dbIndexForEachDB/groovyTableListresetForEachDB:例如:resetForEachDB:_00-_01,每个数据库都有相同的两个表,表后缀分另是_00, _01throughAllDB:例如:throughtAllDB:_00-_49,每个库中表的个数为表总数除以库个数,每个库中表的后缀依次递增,对于上例,表总数为50个,假如有两个库,则每个库中有25个表,第一个库中表的后缀为_00-_24,第二个库中表的后缀为_25-_49。dbIndexForEachDB:例如:dbIndexForEachDB:_00-_01,每个库一张表,表后缀和数据库后缀相同groovyTableList例如groovyTableList:def list = ;for (int i=0; i list.add($i.padLeft(2,0);(0.500).eachi - list.add($i.padLeft(3,0); return list;logicTableName必须是存在的无后缀的数据库表名逻辑数据库表名(未发现该参数起作用)disableFullTableScantrue/false默认值为true,不进行全表扫描;如果置为false,则where条件中不包含分库分表键时,遍历所有的库,如果where条件中含有键,就根据键值计算具体库表dbRuleArray以return开头的表达式例如1. return 0;2. return com.cmbc.test.TestClass. parserDbIndex (#分库分表键#)具体写法参见第8.5节tbRuleArray以return开头的表达式类似dbRuleArray,根据该参数值选择库中对应索引值的一个表4. SQL语句4.1 查询语句 ZDAL对大部分的SQL查询提供了很好的支持,对于其支持的SQL语法详见10.1节。但是ZDAL仍然不是一个完全遵循SQL规范的SQL语法解析器。并不能够保证所有的SQL都可以通过,当SQL语句无法被正确解析时,可以通过ThreadLocalString、ThreadLocalMap和RouteCondition的结合使用解决。4.1.1 ZDAL查询使用示例 /首先根据上一章的配置说明,在程序中创建ZdalDataSource类。ZdalDataSource dataSource = new ZdalDataSource();dataSource.setAppName(.);dataSource.setAppDsName(.);dataSource.setDbmode(.);dataSource.setConfigPath(.);dataSource.init(); /数据源初始化,ZdalDataSource对象创建完毕。/上述配置也可以在Spring配置文件中完成Connection conn = dataSource.getConnection();Statement st = conn.createStatement();ResultSet rs= st.executeQuery(select * from iloan_cr_ln_hdr where cust_no=1111 );/ 接下来可以对rs进行遍历,获取查询结果。.上面程序说明的是ZDAL支持的SQL语句的使用方法。下面说明对ZDAL不支持的SQL语法的解决办法。4.1.2 RouteCondition类使用说明当执行ZDAL不支持的SQL语句时,可以在executeQuery前添加下面语句:ThreadLocalMap.put(ThreadLocalString.ROUTE_CONDITION,RouteCondition对象);ZDAL框架在执行时,会检查ThreadLocalMap中ThreadLocalString.ROUTE_CONDITION对应的值,如果不为null,则取出该值,并且跳过ZDAL自身的语法解析器。下面详细说明ThreadLocalString和RouteCondition。 ThreadLocalStringThreadLocalString中定义了四个静态属性,下表详细说明了各属性的含义:变量名说明变量名说明ThreadLocalString.ROUTE_CONDITION用来绕过SQL解析执行复杂SQL语句ThreadLocalString.DATABASE_INDEX适用于读写分离情况:选择某个读库来执行某条SQLThreadLocalString.SELECT_DATABASE适用于读写分离:在同时分库分表的情况下,选择写库来执行某条SQLThreadLocalString.GET_ID_AND_DATABASE最后的SQL是在哪个库执行的,SQL执行完毕之后调用ThreadLocalMap.get(ThreadLocalString.GET_ID_AND_DATABASE)来获取SQL最终执行的数据库 RouteConditionRouteCondition作用相当于一个SQL语句解析辅助工具,在RouteCondition对象中填入要执行的SQL语句的解析信息,ZDAL获得该对象后,就直接使用对象执行分库分表规则,而不再解析SQL语句。它是一个接口,其继承关系如下图,图中每个类都有不同的用途: 使用RouteCondition, ZDAL就不在对SQL语句进行语法解析,所以对于ZDAL不支持的语法可以使用RouteCondition解决。 ZDAL从ThreadLocalMap中获取到RouteCondition对象之后,就直接把对象从ThreadLocalMap中删除掉,所以下次使用相同的RouteCondition对象时,必须重新调用ThreadLocalMap.put方法。下面对RouteCondition的各个对象使用方法进行说明。 DBSelectorIDRouteCondition 用于查询指定库中指定的表,一次只能指定一个库,但可以指定多个表 构造方法:DBSelectorIDRouteCondition(String logicTableName, String dbSelectorID, String. tables)参数名含义参数名含义logicTableName逻辑表名,通常情况下为实际表名去掉后缀,例如实际表名为acct_00则逻辑表名为acctdbSelectorID数据源名称,对应PhysicalDataSourceBean中的name属性tables实际的表名,可以是多个 示例conn = dataSource.getConnection();st = conn.createStatement();RouteCondition rc = new DBSelectorIDRouteCondition(acct, master_0, acct_00, acct_01);ThreadLocalMap.put(ThreadLocalString.ROUTE_CONDITION, rc);System.out.println(start + System.currentTimeMillis();rs = st.executeQuery(select * from acct where acctname in (zhangsan306, zhangsan10094, zhangsan128);1. 分库分表规则对DBSelectorIDRouteCondition无效,所以where子句也不要求包含分库分表字段2. 另外,如果指定了多个真实表名,那么在SQL语句中不要使用分页,排序等操作3. 代码会查询master_0对应的库中的acct_00和acct_01两张表 SimpleCondition 用于分离分库分表键和查询语句,通过指定的分库分表键找到物理数据库和表,在该表上执行指定的SQL语句 构造方法:默认无参构造方法 示例conn = dataSource.getConnection();pst = conn.prepareStatement(select * from acct where acctname = ?);pst.setString(1, zhangsan160);SimpleCondition sc = new SimpleCondition();sc.setVirtualTableName(acct);sc.put(acctno, new Comparative(Comparative.Equivalent,100100000000000108);ThreadLocalMap.put(ThreadLocalString.ROUTE_CONDITION, sc);rs = pst.executeQuery();1. 分库分表规则对SimpleCondition有效,根据sc.put(“分库分表键”,”分库分表键值”)来确定具体对哪张表执行SQL,如果分库分表为单键并且put了多次不同的值,则以最后一个值为准2. 对分库分表字段使用等于、大于、小于等运算时,使用Comparative指定,Comparative类中提供了一系列的静态字段用于指定运算规则3. 最后执行的SQL语句的where子句可以不包含分库分表键。 AdvanceCondition 类似SimpleCondition,AdvanceCondition可以在指定分库分表键值的时候使用or或者and运算,而SimpleCondition不可以。 AdvanceCondition继承自SimpleCondition,提供了两个静态方法,分别用于支持and和or运算。 构造方法:默认无参构造方法 示例conn = dataSource.getConnection();pst = conn.prepareStatement(select * from acct where acctname = ?);pst.setString(1, zhangsan180);AdvanceCondition ac = new AdvanceCondition();ac.setVirtualTableName(acct);ac.put(acctno, AdvanceCondition.or(AdvanceCondition.getComparative(AdvanceCondition.EQ, 100100000000000108),AdvanceCondition.getComparative(AdvanceCondition.EQ, 100100000000000103); ThreadLocalMap.put(ThreadLocalString.ROUTE_CONDITION, ac);rs = pst.executeQuery();1. ac.put(“acctno”, AdvanceCondition.or.)表示将“100100000000000108” or acctno=”100100000000000103”作为分库分表的键值来定位数据库与表,对应的结果可能有多个2. and的使用与or类似,但有一点需要注意传给and的几个Comparative对象条件不能是互斥的。比如cust_no3 and cust_no=2,像这种ZDAL会报异常。3. 如果分库分表字段有两个或两个以上,针对每一个字段使用了or或and方法,这样有部分字段就有多个值,ZDAL会使用每一个值进行计算。比如:拆分字段:cust_no1,cust_no2拆分条件:return #cust_no1#+#cust_no2#AdvanceCondition.put(cust_no1,or(new Comparative(3,1),new Comparative(3,2);AdvanceCondition.put(cust_no2,or(new Comparative(3,3),new Comparative(3,4);运行时,拆分结果是:4(1+3),5(1+4或者2+3),6(2+4)。4. 根据找到的数据库与表来执行指定的SQL语句 JoinCondition 用来支持单库中的join查询,注意是单库,也就是说多表查询的几张表必须在同一个数据库中 构造方法:默认无参构造方法 示例conn = dataSource.getConnection();pst = conn.prepareStatement(select a.*, b.* from acct a, cif b where a.cifno = b.cifno and a.acctname = ?);pst.setString(1, zhangsan100);JoinCondition jc = new JoinCondition();jc.setVirtualTableName(acct);jc.addVirtualJoinTableName(cif);jc.put(acctno, 100100000000000160); /主表分表键jc.setDBType(DBType.DB2);ThreadLocalMap.put(ThreadLocalString.ROUTE_CONDITION, jc);rs = pst.executeQuery();1. 分库分表规则对JoinCondition依然有效,由jc.put(acctno, 100100000000000160)来指定主表(virtualTableName)分表键值,从表服从主表规则执行查询。也就是通过jc.put()方法指定的字段值进行分表如果得到主表是acct_00则从表也是cif_00,主表和从表都位于同一个数据库中2. 如果配置主表的disableFullTableScan为false,这种情况下是允许主表存在于多个数据库中的。查询执行的时候首先会根据分表键找到表实际表名,然后再遍历所有库中的实际表名3. 除了从表后缀服从主表后缀这种方式外,还有一种指定真实从表表名的规则。就上面的例子来说,可以将jc.addVirtualJoinTableName(cif);改为jc.addVirtualJoinTableName(cif,cif_00);这种方式是直接指定了从表的真实表名,ZDAL在解析从表表名时,直接使用逗号后面真实表名,而不再服从主表后缀。 DirectlyRouteCondition 暂不支持4.2 增删改语句三种SQL语句执行方式与查询一样,不过在语法上还有一些限制: 分库分表字段的值必须确定; 分库分表字段不能出现多个值的情况,即在SQL语句中,分库分表字段值必须唯一而且只能出现一次; 如果设置提交方式为手动提交,执行时,不会对数据库中的数据作出更改,如果需要提交,则执行Cmit()方法,不能直接执行“commit”语句,因为ZDAL只支持select,insert,update,delete四种语句。(1) 关于insert语句的说明: 执行插入时,一条SQL不能同时对多张表执行插入,无论是否设置事务提交类型。ZDAL一旦发现多张表执行插入,就抛出异常(throw new SQLException(mapping many actual tables))。(2) 关于update语句的说明: 当一条SQL语句在多张表上进行update时,可能会出现数据不一致的情况,因为更新可能在某几张表上操作失败,并抛出异常,而其他的表操作成功,ZDAL对操作成功的表并未做回滚处理。(3) 关于delete语句的说明: 当一条SQL语句在多张表上进行删除操作时,可能会出现数据不一致的情况,因为删除可能在某几张表上操作失败,并抛出异常,而其他的表操作成功,ZDAL对操作成功的表并未做回滚处理。5. 日志支持Zdal提供两类日志: zdal-client-config.log:初始化的日志信息,主要打印appName, appDsName, dbmode, configPath, 分库分表规则,groupRule, failoverRule, 动态failover, markdown, markup等动态推送的日志信息 zdal-datasource-pool.log:各个物理数据源连接池的连接状态日志信息以及超时连接剔除的日志,异常连接的日志信息等。连接池状态每30秒打印一行,例如 连接池状态日志 例如:2015-07-28 20:27:55,746 / - WARN zdal-datasource-pool - shardDataSource.slave_0min:3-max:7-canUse:6-managed:0-using:0-maxUsed:0-createCount:0-destroyCount:0 说明slave_0数据源名称min:3最小连接数max:7最大连接数canUse:6可用的连接数managed:0连接池中管理的连接数=createCount-destroyCountusing:0正在使用的连接数maxUsed:0高峰期需要的最大连接数createCount:0创建过的连接数destroyCount:0销毁过的连接数 超时连接剔除日志 例如:2014-01-03 17:40:17,387 / - WARN zdal-datasource-pool - WARN # destroy a connection of poolName = tradecore50.physics39 of removeTimeout 异常连接剔除日志 例如:2013-12-25:2013-12-25 00:03:40,515 / - WARN zdal-datasource-pool - WARN # destroy a connection of poolName = DS_POOL_TDDL.physics03_bak of returnConnection6. Zdal与iBatis结合使用说明 Zdal从数据源层提供对分库分表的支持,它对外暴露出一个符合JDBC规范的DataSource。iBatis则是基于DataSource之上的应用层数据访问框架,因此通过将iBatis的数据源配置成Zdal对外暴露的数据源就可以将二者无缝集成。7. 基于Zdal的数据库设计与使用原则 仅对增长快速的表进行分库分表 从效率的角度出发,尽可能的将一个表的不同切分放在不同库中 设计表的开始就要选一个或多个键作为分库分表键 由于Zdal内置LRU的缓存,所以使用时尽量使用PreparedStatement,以增加命中率减少SQL解析开销8. FAQ8.1 ZDAL支持的SQL语法有哪些? 基本的增删改查 运算符, =, , =, +, -, *, / not like, like, 在分库分表字段上使用时,必须使用RouteCondition对象 in is null, is not null , 在分库分表字段上使用时,必须使用RouteCondition对象 sum, count, max, min, order by, 但不推荐使用在分库分表键上,avg只能在单表查询时使用,这里的单表指的是一张真实的表,不是逻辑表,另外,多个聚集函数也不能同时出现在一个对多表的查询中,只能在单表查询中使用 嵌套查询:嵌套内表名和嵌套外表名必须一致,分库分表键可以出现多次,但是对分库分表键执行的运算必须完全一致 as别名与表名限定,用括号提升优先级 mysql limit分页,oracle rownum分页和db2 rownumber分页 some, any, all ,但是在这三个关键字后面只能使用子查询 group by支持在单表上使用,这里的单表指的是一张真实的表,不是逻辑表 在一个查询中,分库分表字段可以出现多次,但是计算库表时,以第一次出现的值为准 Distinct只能在单表上查询时使用8.2 分库分表时SQL语句写法 未使用线程变量绕过SQL解析且规则中未配置disableFullTableScan=false(默认为true)时where子句必须包含分库分表键,反之视情况而定8.3 Zdal对事务的支持 zdal对事务提供有限的支持,他支持基于单库的事务,如果在一个事务过程中出现了多个不同的数据源,则系统会抛出异常。zdal不支持跨库进行事务,跨库事务本身会耗费很多宝贵的资源,在大型分布式系统中应该尽量避免使用分布式事务处理机制,可以通过补偿(如xts)等方式保证分布式环境中的数据的最终一致性。同时,如果在一个事务中使用了非ZdalDataSource管理的数据源,Spring和Zdal都不能够保证事务的ACID。如果是针对单个数据库的事务,使用的方式与以前的使用方式完全一致。如果需要使用spring的数据库事务管理,则只需要使用TransactionAwareDataSourceProxy对ZdalDataSource进行包装后使用TranscationManager进行管理即可 示例Connection conn = dataSource.getConnection();conn.setAutoCommit(false);try . mit(); catch (Exception e) conn.rollback(); finally if (pst != null) pst.close(); pst = null; if (conn != null) conn.close(); conn = null; 8.4 ZDAL可以做数据迁移工作吗? zdal不会帮助用户在改写数据的时候做迁移工作,因此不能够期望Zdal在业务中使用sql改写了分库分表条件项的值的时候做delete+insert操作。这样做本身是不符合预期的,同时在分布式业务系统中也是不推荐使用的。如果确实有这样的需要,请于业务端进行delete+insert操作。由于可能进行删除添加的操作可能发生在不同的数据库中,在发生这样的情况时,请通过业务逻辑保证数据的一致性。Zdal不会对这类操作提供任何保证。8.5 编写自己的分库分表parser Zdal支持java静态方法编写分库分表规则,方法返回值为数字。对于分库规则,zdal会利用这个数字去对应规则配置中的物理数据源的位置来找到使用哪个物理数据源来执行SQL;对于分表规则,zdal会利用这个数字计算出表的后缀信息来确定最终在哪个物理表上执行SQL。最后在规则配置的时候需要指定类的全路径.方法名(参数列表); 示例在XML文件中的配置如下: returncom.cmbc.test.TestClass.parserDbIndex(#cust_no#); TestClass类中需要下面静态方法:public static int parserDbIndex(String cust_no) /每个库有3个物理表与之对应 return Integer.valueOf(cust_no.substring(cust_no.length() - 1) % 3;8.6 Zdal是否支持读写分离? 在Group,Shard_group两种配置模式中是支持读写分离的,通过读写的权重进行控制,如:group_0=ds0:r10w10,ds1:r10w0,说明ds0这个数据源可读可写,ds1是只读8.7Zdal如何管理连接,是否有连接泄露的问题? Zdal的每次数据库操作所用的连接是与ZDatasource关联

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论