时间:2021-07-01 10:21:17 帮助过:22人阅读
<property name="useGlobleTableCheck">0</property>
<!-- 0 为本地文件方式,1 为数据库方式,2 为时间戳序列方式,3 为分布式ZK ID 生成器,4 为 zk 递增 id 生成。 -->
<property name="sequnceHandlerType">1</property>
<!-- 数据服务占用端口 -->
<property name="serverPort">8066</property>
<!-- 管理占用端口, 类似show @@cache;等管理命令必须使用此端口登陆才能正常使用. -->
<property name="managerPort">9066</property>
<!-- 连接的空闲超时断开时间 -->
<property name="idleTimeout">300000</property>
<!-- 内网使用默认即可, 应该没人拿来外网访问 -->
<property name="bindIp">0.0.0.0</property>
<!-- 查询返回结果集长度报警阈值, 超过日志输出警告 -->
<property name="frontWriteQueueSize">4096</property>
<!-- 系统可用的线程数,默认值为机器 CPU 核心线程数, 可适当调高 -->
<property name="processors">32</property>
<!-- 分布式事务开关 -->
<property name="handleDistributedTransactions">0</property>
useGlobleTableCheck 含义
全局表用于存放字典类低频增删改及数据量不大的表, 供给join使用.
开启后需要手动在配置成全局表的表结构里增加_mycat_op_time字段, 如果是通过mycat发送的建表语句, 则会自动改写增加该字段.
原理是拦截CUD语句, 自动改写给_mycat_op_time字段加入当前时间戳的值.
然后通过定时器定时执行
1 | select count(*) as record_count from user; |
两个查询, 然后对比所有节点上全局表返回结果是否一致, 从而完成一致性检测.
当然, 这个配置只能检测, 不能自动修复, 只是帮助我们及时发现问题.
sequnceHandlerType 含义
全局ID生成方式, 用于数据库自增主键.
使用数据库自带的主键自增功能, 在跨库跨节点分片中可能出现insert后返回不准确的问题.
所以需要使用自增主键的话, 必须使用Mycat提供的自增策略.
0是禁止使用的, 因为每次重启服务后ID会重置.
1是使用数据库表实现, 将起始ID和步长存放在数据库中, 每次读取步长量的ID并更新ID起始值, 用完再来.
2本地时间戳方式, 64位ID, 太长了, 我反正不会用…
3分布式 ZK ID 生成器, 依然是64位ID, 好处是高吞吐量并且保证机房内极限状态获取17年不重复.
4Zk 递增方式, 没用过不知道.
这里只讲一下2的配置, 大部分人的选择.
1 | CREATE TABLE MYCAT_SEQUENCE (name VARCHAR(50) NOT NULL,current_value INT NOT |
全部删掉sequence_db_conf.properties里的内容, 然后添加
1 | GLOBAL=test_dn |
这里就是刚刚insert的两条数据里对应的表绑定datahost, datahost是啥后面会讲到.
handleDistributedTransactions
0 为不过滤分布式事务 1 为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤)2 为不过滤分布式事务,但是记录分布式事务日志
官方说明有点难理解, 害我测试了一下才明白. 过滤等于是禁用的意思.
0就是开启分布式事务, 1是禁止分布式事务, 如果事务内操作的都是全局表则不禁用. 2是开启分布式事务同时开启日志.
1 | <user name="root"> |
这个用于配置登陆使用的用户, schemas则是填入开放访问的多个分片合并出来的虚拟表的虚拟库, 允许填入多个, 逗号隔开. 里面填入的内容在后面马上会讲到的schema.xml文件里配置.
server.xml的关键配置及含义到这就讲完了.
schema.xml
首先讲一下我模拟实现的需求, 有sys_user、sys_role、sys_order三个表.
根据功能进行垂直分库后, 分成了两个库.sys_user、sys_role所在的user库和sys_order所在的order库.user库放在192.168.1.56(后简称56)这台服务器上, order库放在localhost本地.
然后考虑sys_order表数据量增大, 进行了水平分片, 于是又产生了一个order2库.
最后为了进一步增加可用性, 又增加了两台服务器分别作为56和localhost的从库, 进行读写分离, 主库只负担写入, 从库只负责读去.
以上就是下面这段配置实现的效果.
1 | <schema name="userOrder" checkSQLschema="false" sqlMaxLimit="1000"> |
<dataHost /> 表示节点主机, 一个节点主机不代表一台主机, 可以配置多台主机, 即多个<writeHost />.balance属性表示负载均衡类型, 0为不开启. 1为除了 readHost, 空闲的writeHost也参与Select的负载均衡. 2为Select在所有readHost、writeHost上随机分发. 3为Select操作只在writeHost内的readHost上随机分发.
可见1是用于双主同步模式, 而3才是用于完全读写分离模式, 所以只有3能满足刚刚模拟的需求.
writeType已废弃, 用switchType替代, 默认值即可.
switchType属性表示是否开启自动切换, 需要读写分离的话必须开启, 默认1不开启.
2为开启, 开启后heartbeat心跳检测语句必须改为show slave status, 这里其实就帮你做了可用性验证.
当同步线程出问题挂掉后, 还继续在从库查询必然会出BUG, 所以根据心跳检测返回可决定是否切换从库进行查询.
heartbeat属性上面已经提到过了, 就是字面含义, 用来检测被代理的物理库的活性. 所使用的语句不考虑读写分离的节点, 可以使用select 1这种来替换.
<writeHost />标签用于配置物理库连接数据, 很好理解.<readHost />子标签用于配置读写分离后负责读的物理库连接数据.
<dataNode /> 表示分片节点, 用于配置和主机节点的绑定关系.
根据之前模拟的需求, 如果sys_order库不进行水平分片的话, 那么<dataNode />节点就只有两个, 一个user、一个order.sys_order分片之后多出一个物理库order2, 所以有了第三个<dataNode />.
<schema /> 在讲server.xml中提到了一次, 这里就是使用分片组合成虚拟表的虚拟库.checkSQLschema="false"属性是用来兼容DB工具访问的属性, 设为true才兼容类似Navicat的访问, 我开启后使用Navicat访问依然出现各种问题, 一度让我以为我哪里配置出问题, 浪费了一两个小时, 所以不用理它.
<table/ > 标签就是配置由分片节点组成虚拟表, 如果组成虚拟表的分片节点只有一个, 那么sql的执行就只是进行了一次转发, 如果配置了多个, 那么sql就需要经过Mycat的改写, 比如说根据Id查Order, 因为sys_order表进行了水平分片, 所以没人知道对应这个Id的数据在哪个分片上, 所以需要改写到两个分片上去查询.
不过Mycat加入了热点缓存机制TableID2DataNodeCache, 缓存主键命中的路由, 下次再查询该主键就会直接命中该路由.
更新下TableID2DataNodeCache的解释, 根据最近的测试发现, 它只能根据主键进行单表的路由缓存, 即使我们使用了<childTable />标签来开启ER Join功能,TableID2DataNodeCache也无法在我们使用ER Join时提供路由缓存服务, 按道理说, 既然单表可以根据主键缓存路由, 那么ER Join 同样可以啊, 既然是ER Join说明是单库的Join而非跨节点的, 那么使用条件中的主键缓存路由是没有问题的.
<table/ > 另外还有一个属性type="global", 可以将一张表设置为全局表, 设置以后macat会保证该表在所有节点上的一致性, 使其在任何节点上需要被join是可以直接在库内提供数据支持, 而不需要跨库跨节点, 从而提升查询效率, 全局表的更新每次都会把数据同步到所有节点且不支持水平分片, 所以一般建议用于数据字典表, 类似省市区表、业务类型表等更新频率低数据量不大的表.
dataNode属性就是用来绑定分片的了, 可绑定多个, 已多次提到.
primaryKey 告知Mycat分片对应物理表的主键, 方便进行路由计算.
autoIncrement 开启主键自增, 主键自增需要的配置上面也讲过了.
<childTable /> 这个子表标签, 我花了些功夫才理解是什么意思.
官方说是用来实现ER Join, 通俗理解就是用来实现分片后的表之间进行的join并保证效率.
试想看看, 当表水平分片后, 数据都不知道在哪个分片里, 然后还要跟另外一个库里的表去join查询, 这特么只能把全表查出来才能通过代码完成join操作了吧, 但是这样还谈什么高可用.
所以官方用了一个比较鸡贼的方式, 还是用之前模拟的需求来举例.
首先根据用户Id对sys_user和sys_order分片, 通过配置子表的方式告知从属关系及外键关系, 然后在insert新order时, 会根据用户Id查询找到该用户所在分片, 然后把这个order也insert到同一个分片上去, 从而以后查询用户及用户下所有订单时的join可以直接在同一个库中用最普通的join完成. 这样及实现了join的需求, 也不会有性能问题.
但是又带来了两个个问题, 第一必须两张表都水平分片才能使用该功能. 第二不能使用垂直分片, 即sys_user和sys_order的分片必须在同一个库中.
rule属性就是用来配置分片规则的了, 取值对应马上开始讲的最后一个配置文件.
啊啊啊, 终于到了最后一个配置文件.
rule.xml
1 | <tableRule name="rule2"> |
里面<tableRule/ >标签的name属性就是填入schema.xml里<table/ >标签里的rule属性的值.
可以看到该配置文件中<tableRule/ >有很多个, 子标签<columns />里放的是用于分片的字段, <algorithm />则是调用的分片方法. 取值对应文件下方的<function />标签.
sharding-by-intfile 枚举分片, 通过配置partition-hash-int.txt完成按固定条件分片, 例如按国家、省份或地区分片.
"mod-long 求模分片, 按分片字段的值十进制求模分片.
rule1 固定hash分片. 求模分片的高阶版, 用分片字段的二进制低 10 位进行计算, 直接求模如果有10个分片, 当连续insert 1到10时就会依此分片到10个分片里, 使用此规则可避免此情况, 降低跨库跨节点事务的性能消耗.
但是如果你的分片就只有两三个, 就还不如直接求模了, 降低运算量.
auto-sharding-long 按分片字段范围分片, 在autopartition-long.txt配置范围规则, 例如: 0-1000000=0, 表示分片字段值在这个范围内分片到第一个节点.
sharding-by-pattern 求模+范围组合模式, 求模同时控制数据落点. 范围是这是求模之后余数的范围.
sharding-by-prefixpattern 截取指定位数字母转ASCII码再求模+范围分片方式.
sharding-by-substring 使用者自行指定分片, 根据分片字段的值配置截取位置获得的结果来分片, 结果必须是数字.
sharding-by-date 按天分片, 变态增量数据专用之一, 可使用sPartionDay属性设置多少天分一片.
暂时实践到的分片规则就这么多, 常用的也差不多就这些了, 还支持很多其他分片规则, 具体可在官方用户手册中查看.
Mycat功能细化做的很不错, 颗粒度扣得很细, 基本上能想到的业务场景都能够配置出来, 不过这也带来一个问题, 就是需要掌握的配置量就比较庞大了, 不说能记住, 起码都必须过一遍脑子, 知道有这么些个玩意儿和原理, 这样在遇到需求时才能联想到mycat是否能够配得出来, 遇到问题时才能快速分析找到问题点, 或者说最大限度上预防出问题.
苦逼归苦逼, 但是也只有熟练掌握了数据库中间件的原理思维, 并且能熟练运用这些数据库中间件, 你才有资格说你已经能够驾驭高可用微服务了.
辞职了, 最近又要开始找工作了, 最后祝自己顺利吧!Thanks for your reading。
原文:大专栏 Mycat数据库中间件上手实践及分布式事务和读写分离实现
Mycat数据库中间件上手实践及分布式事务和读写分离实现
标签:bin beat 组成 attr lan 打开 找工作 登陆 阅读