008.mycat的配置-server.xml

1,配置

server.xml 几乎保存了所有mycat 需要的系统配置信息。其在代码内直接的映射类为SystemConfig 类。

2,user 标签

<user name="test">

<property name="password">test</property>

<property name="schemas">TESTDB</property>

<property name="readOnly">true</property>

<property name="benchmark">11111</property>

<property name="usingDecrypt">1</property>

<privileges check="false">

<schema name="TESTDB" dml="0010" showTables="custome/mysql">

<table name="tbl_user" dml="0110"></table>

<table name="tbl_dynamic" dml="1111"></table>

</schema>

</privileges>

</user>

server.xml 中的标签本就不多,这个标签主要用于定义登录mycat 的用户和权限。例如上面的例子中,我定义了一个用户,用户名为test、密码也为test,可访问的schema 也只有TESTDB 一个。

如果我在schema.xml 中定义了多个schema,那么这个用户是无法访问其他的schema。在mysql 客户端看来则是无法使用use 切换到这个其他的数据库。

这个标签嵌套的property 标签则是具体声明的属性值,正如上面的例子。我们可以修改user 标签的name属性来指定用户名;修改password 内的文本来修改密码;修改readOnly 为true 或false 来限制用户是否只是可读的;修改schemas 内的文本来控制用户可访问的schema,同时访问多个schema 的话使用, 隔开,例如:

<property name="schemas">TESTDB,db1,db2</property>

Benchmark 属性

Benchmark:mycat 连接服务降级处理:

benchmark 基准, 当前端的整体connection 数达到基准值时, 对来自该账户的请求开始拒绝连接,0 或不设表示不限制

例如<property name="benchmark">1000</property>

usingDecrypt 属性

是否对密码加密默认0 否如需要开启配置1,同时使用加密程序对密码加密,加密命令为:

执行mycat jar 程序:

java -cp Mycat-server-1.4.1-dev.jar io.mycat.util.DecryptUtil 0:user:password

Mycat-server-1.4.1-dev.jar 为mycat download 下载目录的jar

1:host:user:password 中0 为前端加密标志

privileges 子节点

对用户的schema 及下级的table 进行精细化的DML 权限控制,privileges 节点中的check 属性是用

于标识是否开启DML 权限检查, 默认false 标识不检查,当然privileges 节点不配置,等check=false,

由于Mycat 一个用户的schemas 属性可配置多个schema ,所以privileges 的下级节点schema 节点同样可配置多个,对多库多表进行细粒度的DML 权限控制

Schema/Table 上的dml 属性描述

privileges 配置事例如下:

<user name="zhuam">

<property name="password">111111</property>

<property name="schemas">TESTDB,TESTDB1</property>

<!-- 表级权限: Table 级的dml(curd)控制,未设置的Table 继承schema 的dml -->

<!-- TODO: 非CURD SQL 语句, 透明传递至后端-->

<privileges check="true">

<schema name="TESTDB" dml="0110" >

<table name="table01" dml="0111"></table>

<table name="table02" dml="1111"></table>

</schema>

<schema name="TESTDB1" dml="0110">

<table name="table03" dml="1110"></table>

<table name="table04" dml="1010"></table>

</schema>

</privileges>

</user>

 

3,system标签

这个标签内嵌套的所有property 标签都与系统配置有关,请注意,下面我会省去标签property 直接使用这个标签的name 属性内的值来介绍这个属性的作用。

charset 属性

字符集设置。

配置属性charset

<system> <property name="charset">utf8</property> </system>

如果需要配置utf8mb2 等特殊字符集可以在

index_to_charset.properties 配置中

配置数据库短的字符集ID=字符集

例如:

224=utf8mb4

配置字符集的时候一定要坚持mycat 的字符集与数据库端的字符集是一致的,可以通过变量来查询:

show variables like 'collation_%';

show variables like 'character_set_%';

defaultSqlParser 属性

由于mycat 最初是时候Foundation DB 的sql 解析器,而后才添加的Druid 的解析器。所以这个属性用来指定默认的解析器。目前的可用的取值有:druidparser 和fdbparser。使用的时候可以选择其中的一种,目前一般都使用druidparser。

1.3 解析器默认为fdbparser,1.4 默认为druidparser,1.4 以后fdbparser 作废。

processors 属性

这个属性主要用于指定系统可用的线程数,默认值为机器CPU 核心线程数。

主要影响processorBufferPool、processorBufferLocalPercent、processorExecutor 属性。

NIOProcessor 的个数也是由这个属性定义的,所以调优的时候可以适当的调高这个属性。

processorBufferChunk 属性

这个属性指定每次分配Socket Direct Buffer (socket缓冲区)的大小,默认是4096 个字节。这个属性也影响buffer pool 的长度。如果一次性获取的数过大buffer 不够用经常出现警告,则可以适当调大。

processorBufferPool 属性

这个属性指定bufferPool 计算比例值。由于每次执行NIO 读、写操作都需要使用到buffer,系统初始化的时候会建立一定长度的buffer 池来加快读、写的效率,减少建立buffer 的时间。

Mycat 中有两个主要的buffer 池:

- BufferPool

- ThreadLocalPool

BufferPool 由ThreadLocalPool 组合而成,每次从BufferPool 中获取buffer 都会优先获取

ThreadLocalPool 中的buffer,未命中之后才会去获取BufferPool 中的buffer。也就是说ThreadLocalPool 是作为BufferPool 的二级缓存,每个线程内部自己使用的。当然,这其中还有一些限制条件需要线程的名字是由$_开头。然而,BufferPool 上的buffer 则是每个NIOProcessor 都共享的。

默认这个属性的值为: 默认bufferChunkSize(4096) * processors 属性* 1000

BufferPool 的总长度= bufferPool / bufferChunk。

若bufferPool 不是bufferChunk 的整数倍,则总长度为前面计算得出的商+ 1

假设系统线程数为4,其他都为属性的默认值,则:

bufferPool = 4096 * 4 * 1000

BufferPool 的总长度: 4000 = 16384000 / 4096

processorBufferLocalPercent 属性

前面提到了ThreadLocalPool。这个属性就是用来控制分配这个pool 的大小用的,但其也并不是一个准确的值,也是一个比例值。这个属性默认值为100。

线程缓存百分比= bufferLocalPercent / processors 属性。

例如,系统可以同时运行4 个线程,使用默认值,则根据公式每个线程的百分比为25。最后根据这个百分比来计算出具体的ThreadLocalPool 的长度公式如下:

ThreadLocalPool 的长度= 线程缓存百分比* BufferPool 长度/100

假设BufferPool 的长度为4000,其他保持默认值。

那么最后每个线程建立上的ThreadLocalPool 的长度为: 1000 = 25 * 4000 / 100

processorExecutor 属性

这个属性主要用于指定NIOProcessor 上共享的businessExecutor 固定线程池大小。mycat 在需要处理一些异步逻辑的时候会把任务提交到这个线程池中。新版本中这个连接池的使用频率不是很大了,可以设置一个较小的值。

sequnceHandlerType 属性

指定使用Mycat 全局序列的类型。0 为本地文件方式,1 为数据库方式,2 为时间戳序列方式,3 为分布式ZK ID 生成器,4 为zk 递增id 生成。

从1.6 增加两种ZK 的全局ID 生成算法。

TCP 连接相关属性

 StandardSocketOptions.SO_RCVBUF

 StandardSocketOptions.SO_SNDBUF

 StandardSocketOptions.TCP_NODELAY

以上这三个属性,分别由:

frontSocketSoRcvbuf 默认值: 1024 * 1024

frontSocketSoSndbuf 默认值: 4 * 1024 * 1024

frontSocketNoDelay 默认值: 1

backSocketSoRcvbuf 默认值: 4 * 1024 * 1024

backSocketSoSndbuf 默认值: 1024 * 1024

backSocketNoDelay 默认值: 1

各自设置前后端TCP 连接参数。Mycat 在每次建立前、后端连接的时候都会使用这些参数初始化连接。可以按系统要求适当的调整这些buffer 的大小。TCP 连接参数的定义,可以查看Javadoc。

Mysql 连接相关属性

初始化mysql 前后端连接所涉及到的一些属性:

packetHeaderSize : 指定Mysql 协议中的报文头长度。默认4。

maxPacketSize : 指定Mysql 协议可以携带的数据最大长度。默认16M。

idleTimeout : 指定连接的空闲超时时间。某连接在发起空闲检查下,发现距离上次使用超过了空闲时间,那么这个连接会被回收,就是被直接的关闭掉。默认30 分钟,单位毫秒。

charset : 连接的初始化字符集。默认为utf8。

txIsolation : 前端连接的初始化事务隔离级别,只在初始化的时候使用,后续会根据客户端传递过来的属性对后端数据库连接进行同步。默认为REPEATED_READ,设置值为数字默认3。

READ_UNCOMMITTED = 1;

READ_COMMITTED = 2;

REPEATED_READ = 3;

SERIALIZABLE = 4;

sqlExecuteTimeout:SQL 执行超时的时间,Mycat 会检查连接上最后一次执行SQL 的时间,若超过这个时间则会直接关闭这连接。默认时间为300 秒,单位秒。

心跳属性

mycat 中有几个周期性的任务来异步的处理一些我需要的工作。这些属性就在系统调优的过程中也是必不可少的。

processorCheckPeriod : 清理NIOProcessor 上前后端空闲、超时和关闭连接的间隔时间。默认是1 秒,单位毫秒。

dataNodeIdleCheckPeriod : 对后端连接进行空闲、超时检查的时间间隔,默认是300 秒,单位毫秒。

dataNodeHeartbeatPeriod : 对后端所有读、写库发起心跳的间隔时间,默认是10 秒,单位毫秒。

服务相关属性

这里介绍一个与服务相关的属性,主要会影响外部系统对mycat 的感知。

bindIp : mycat 服务监听的IP 地址,默认值为0.0.0.0。

serverPort : 定义mycat 的使用端口,默认值为8066。

managerPort : 定义mycat 的管理端口,默认值为9066。

fakeMySQLVersion

mycat 模拟的mysql 版本号,默认值为5.6 版本,如非特需,不要修改这个值,目前支持设置5.5,5.6 版本,其他版本可能会有问题。

此特性从1.6 版本开始支持。

全局表一致性检测

<property name="useGlobleTableCheck">0</property> <!-- 1 为开启全加班一致性检测、0 为关闭-->

原理通过在全局表增加_MYCAT_OP_TIME 字段来进行一致性检测,类型为bigint,create 语句通过mycat执行会自动加上这个字段,其他情况请自己手工添加。

此特性从1.6 版本开始支持。

“增加mycat 新任务,全局表定义中,需要有一个时间戳字段,每次记录的update,insert,确保

时间字段赋值,并且mycat 增加定时检测逻辑,检测记录总量,以及最新时间戳的匹配,简单

有效的发现全局表不一致的问题。/ 测试修复类/ 1.5&2.0 /12.9 /leader-us”

全局表一致性定时检测主要分为两个部分:

1. SQL 拦截部分

主要实现对所有全局表中记录进行修改的语句进行拦截,比如:

ServerParse.INSERT,

ServerParse.UPDATE,

ServerParse.REPLACE(mycat-server 不支持)

对所有对全局表的insert, update 操作进行拦截,首先判断该全局表是否存在一个记录时间戳

的内部列_mycat_op_time:

public class GlobalTableUtil{

/** 全局表保存修改时间戳的字段名,用于全局表一致性检查*/

public static final String GLOBAL_TABLE_MYCAT_COLUMN = "_mycat_op_time";

如果不存在,输出警告,哪个db 的哪个全局表没有内部列:

if(innerColumnNotExist.size() > 0){

for(SQLQueryResult<Map<String, String>> map : innerColumnNotExist){

if(tableName.equalsIgnoreCase(map.getTableName())){

StringBuilder warnStr = new StringBuilder();

if(map != null)

warnStr.append(map.getDataNode()).append(".");

warnStr.append(tableName).append(" inner column: ")

.append(GlobalTableUtil.GLOBAL_TABLE_MYCAT_COLUMN)

.append(" is not exist.");

LOGGER.warn(warnStr.toString());

return sql;

}

}

}

然后返回原始sql. 不需要进行拦截。

如果存在一个记录时间戳的内部列,那么对该insert 或者update 语句进行SQL 拦截修改:

if(sqlType == ServerParse.INSERT){

sql = convertInsertSQL(sql, tableName);

}

if(sqlType == ServerParse.UPDATE){

sql = convertUpdateSQL(sql, tableName);

}

1.1 insert语句的拦截逻辑

对所有对全局表进行insert的sql语句,进行改写,比如下面的user是全局表:

insert into user(id,name)

valueS(1111,'dig'),

(1111, 'dig'),

(1111,'dig') ,

(1111,'dig');

会被改写成:

insert into user(id,name, _mycat_op_time)

valueS(1111,'dig', 1450423751170),

(1111, 'dig', 1450423751170),

(1111,'dig', 1450423751170) ,

(1111,'dig', 1450423751170);

其中_mycat_op_time 是内部列的名称:

public static final String GLOBAL_TABLE_MYCAT_COLUMN = "_mycat_op_time";

而1450423751170 是在插入时在mycat-server上生成的一个时间戳对应的long整数(对应到数据库

是bigint)。然后该语句发送给所有db在其全局表中进行插入。

如果insert语句自带了内部列_mycat_op_time,比如:

insert into user(id,name, _mycat_op_time)

valueS(1111,'dig',13545);

那么会输出警告,并且也进行拦截改写成如下形式:

insert into user(id,name, _mycat_op_time)

valueS(1111,'dig', 1450423751170);

然后发送给所有db在其全局表中进行插入。

对mycat-server不支持的sql语句,本拦截器,不进行任何操作,直接返回原始sql。如果在拦截过程中发生任何异常,也返回原始sql语句,不进行任何修改操作。保证该拦截不会影响系统原有的健壮性。

1.2 update语句的拦截逻辑

Update语句的拦截逻辑和insert语句原理是相似的。也是判断是否有内部列。

如果没有输出警告信息,如果有则进行拦截。

对全局表user 的如下update:

update user set name='dddd',pwd='aaa'

where id=2

会被改写成:

update user set name='dddd',pwd='aaa', _mycat_op_time=1450423751170

where id=2

如果原始sql带有_mycat_op_time 那么进行警告,然后替换它的值,比如:

update user set name='dddd',pwd='aaa', _mycat_op_time=1111

where id=2;

会被改写成:

update user set name='dddd',pwd='aaa', _mycat_op_time=1450423751170

where id=2;

然后将语句发送给所有的全局表进行执行。

这样的话,如果有哪个表上的insert,update执行失败,那么内部列_mycat_op_time 的最大值,以

及全局表的记录总数就会不一致。Delete语句也一样,只是无需拦截。下面的检查机制就是根

据这个原理来操作的。

 

2. 一致性的定时检测

在MycatServer的startup中引入一个定时检查任务:

timer.schedule(glableTableConsistencyCheck(), 0L, 1000 * 1000L);

// 全局表一致性检查任务

private TimerTask glableTableConsistencyCheck() {

return new TimerTask() {

@Override

public void run() {

timerExecutor.execute(new Runnable() {

@Override

public void run() {

GlobalTableUtil.consistencyCheck();

}

});

}

};

其实现在GlobalTableUtil 类中:

该类首先获得所有的全局表:

static {

getGlobalTable(); // 初始化globalTableMap

}

其实现,参见代码。

GlobalTableUtil.consistencyCheck() 的实现,主要思路是,首先根据所有的全局表,找到对应的

PhysicalDBNode,然后找到对应的PhysicalDatasource,然后对PhysicalDatasource中的所有

db进行三项检测:

2.1 检测全局表的内部列是否存在

checker.checkInnerColumnExist();

检测的实现是通过一个SQLJob来异步操作的,对应的SQL语句为:

select count(*) as inner_col_exist from information_schema.columns where column_name='

_mycat_op_time' and table_name='user' and table_schema='db1';

如果返回的inner_col_exist 大于0,那么就表示存在内部列,如果等于0,那么就表示不存在内部

列。

如果PhysicalDatasource上某个db的全局表没有内部列,那么将这些db记录在一个list中,然后在

SQL 拦截过程中进行判断,如果是全局表,但是没有内部列,那么就输出警告,不对SQL进行

拦截改写,因为该全局表没有内部列,无需改写SQL。在第一项检测完成之后,才能进行第二

项检测。

2.2 检测全局表的记录总数

checker.checkRecordCout();

检查过程是类似的,都是通过SQLjob来完成的,只是对应的语句不一样:

select count(*) as record_count from user; (假设user表为全局表)

2.3 检测全局表的时间戳的最大值

checker.checkMaxTimeStamp();

检查过程是类似的,都是通过SQLjob来完成的,只是对应的语句不一样:

select max(_mycat_op_time) as max_timestamp from user (假设user表为全局表)

 

三项检查完成之后,就获得了如下所示的结果:

全局表的记录总数(user表为全局表,并且系统有三个db):

db1. user.record_count: 43546565

db2. user.record_count: 43546565

db3. user.record_count: 43546565

全局表的最大时间戳:

db1. user.max_timestamp: 1450578802241

db2. user.max_timestamp: 1450578802241

db3. user.max_timestamp: 1450578802241

 

然后前端,比如mycat-eye 就可以将该结果显示出来。目前直接在log中输出,也可以考虑引入像

H2这样的Java实现的嵌入式数据库来记录该结果。H2实现为仅仅一个jar包,十分适合作为

mycat-server层面的一个非文件存储方式。有一些信息如果存在在文件中,查询起来不太方

便,比如上面的检测结果就是如此。

实际的SQLJob的执行,主要参照了原有的heartbeat的实现,主要在下面两个类中:

MySQLConsistencyChecker

MySQLConsistencyHelper

具体可以参考代码,和heartbeat的实现基本是一样的。

每一次定时检查,会对所有全局表进行上述三项检测。

每一次定时检查,会对所有全局表进行上述三项检测。

总结成一句:

SQL的拦截实现记录全局表被修改时的时间戳;定时任务实现对全局表记录总数和时间戳最大值的获

取。

 

3. 如何使用全局表一致性检测

1> 在所有全局表中增加一个bigint 的内部列,列名为_mycat_op_time,(alter table t add

column _mycat_op_time bigint [not null default 0]); 同时建议在该列上建立索引(alter

table t add index _op_idx(_mycat_op_time))

2> 在对全局表进行crud时,最好将内部列当作不存在一样,也就是最好不要对内部列

update,insert等操作,不然会在Log中进行警告:不用操作内部列;

3> 因为全局表多了一个内部列,所以在对全局表进行insert时,必须携带列名,也就是insert

into t(id,name) values(xx,xx),不能使用insert into t values(xx,xx); 因为会报错:列数

不对。这是唯一的一个小问题。未来可能会fix掉。

 

分布式事务开关

<!--分布式事务开关,0 为不过滤分布式事务,1 为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2 为不过滤分布式事务,但是记录分布式事务日志-->

<property name="handleDistributedTransactions">0</property>

主要应用场景,主要为了控制是否允许跨库事务。

此特性从1.6 版本开始支持。

 

Off Heap for Mycat

此特性从1.6 版本开始支持。

<!--

off heap for merge/order/group/limit 1 开启0 关闭

-->

<property name="useOffHeapForMerge">1</property>

1.使用非堆内存(Direct Memory)处理跨分片结果集的Merge/order by/group by/limit。

2.通过server.xml 中的useOffHeapForMerge 参数配置是否启用非堆内存处理跨分片结果集

3.Mycat 内存分层管理:

a.结果集处理内存;

b.系统预留内存;

c.网络处理内存共三块。

其中网络处理内存部分全部为Direct Memory,结果集内存分为Direct Memory 和HeapMemory。

但目前仅使用Direct Memory。系统预留内存为On Heap Memory。JVM 参数,必须设置-

XX:MaxDirectMemorySize 和-Xmx

例如:-Xmx1024m -Xmn512m -XX:MaxDirectMemorySize=2048m -Xss256K -XX:+UseParallelGC

上述分层可以避免OOM 问题,以及减少Full GC 回收时间,提高mycat 响应速度。

4.使用TimeSort 和RadixSort,跨分片结果集合并排序使用PriorityQueue,其中经测试RadixSort 适合LONG,INT,SHORT,Float,Double,String 数据类型排序,性能优越。

5.Java obj 连续内存存取,二进制序列化和反序列化,使用缓存友好的数据结构Map 和Row。

6.支持内存和外存并存的排序方式,结果集排序可以达上亿规模。此时应注意:

a.此时前端和后端空闲连接超时检测时间应该设置大些,避免空闲检测关闭front 或者backend

connection,造成Mysqlclient 连接丢失时结果集无法正确。

b.设置-Xmn 值尽可能大些,新生代使用UseParallelGC 垃圾回收器,-Xss 设置512K 比较合适,物理内存足够时,MaxDirectMemorySize 尽可能设置大些,可以加快结果集处理时间,

例如:-Xmx1024m -Xmn512m -XX:MaxDirectMemorySize=2048m -Xss256k -XX:+UseParallelGC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值