• MyCat头脑风暴


    高并发高可用架构演进 :

       数据库、应用于一体➡数据库与应用分离➡数据库根据业务将表分到不同的库中➡同一张表进行读写分离➡表中数据根据需求分表

       其中Mycat数据库中间件起到了读写分离,分库,分表的作用

    1.解决的问题

      读写分离 (Mysql主从复制)/分库分表 ➡ 多数据源  ➡ Java程序需要进行多个数据源的切换 / Java程序与MySQL紧耦合 —— Java程序与数据库解耦

       高可用 ➡ 集群与容错机制  高并发 ➡ 分库+分表 —— 解决高并发高可用对数据库的压力

    2.怎样解决

      Mycat通过配置文件搭建一个逻辑数据库,向外暴露一个Mycat的访问接口[解耦] ,而底层通过多个数据节点DataNode(一个DataNode对应一个DataHost,而一个DataHost保证其高可用搭建读写分离集群writeHost,readHost(一主一从/双主双从)) [高可用],通过<table dataHost="">节点将不同业务的表分发到不同的库中,分散数据库压力,而相同表中数据量大时会遇到瓶颈,所以此时将表中数据根据<table rule="">根据分片规则分发到多个表中(不同库的不同的表),提高查询等的效率[高并发]

      而所有这些操作都在Mycat内部解决,对于Java程序来说完全透明,和平常一样进行SQL的传输即可,Mycat接到SQL语句,对其进行拦截,后根据配置的一系列分库分表规则等进行解析SQL,分析SQL(分片分析,缓存分析,路由分析......),分发到后台的物理数据库,得到结果对结果进行整合后传回

     3.如何使用

      开发步骤 : 分析业务制定出分片规则等后配置好配置文件 --> 启动对应的物理数据库 -->使用Mycat执行建表操作

    • 读写分离 ➡同一个DataHost的主从复制

           

    <dataNode name="dn1" dataHost="host1" database="testdb" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="1"
        writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100" >
      <heartbeat>select user()</heartbeat>
      <!-- can have multi write hosts -->
      <writeHost host="hostM1" url="192.168.140.128:3306" user="root" password="123123">
        <!-- can have multi read hosts -->
        <readHost host="hostS1" url="192.168.140.127:3306" user="root" password="123123" />
      </writeHost>   
      <writeHost host="hostM2" url="192.168.140.126:3306" user="root" password="123123">     <!-- can have multi read hosts -->     <readHost host="hostS2" url="192.168.140.125:3306" user="root" password="123123" />   </writeHost> </dataHost>

    负载均衡类型,目前的取值有4 种:

    (1) balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。

    (2) balance="1",全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载均衡。

    (3) balance="2",所有读操作都随机的在 writeHost、readhost 上分发。

    (4) balance="3",所有读请求随机的分发到 readhost 执行,writerHost 不负担读压力

    #writeType="0": 所有写操作发送到配置的第一个writeHost,第一个挂了切到还生存的第二个#writeType="1",所有写操作都随机的发送到配置的 writeHost,1.5 以后废弃不推荐#writeHost,重新启动后以切换后的为准,切换记录在配置文件中:dnindex.properties 。
    #switchType="1": 1 默认值,自动切换。 # -1 表示不自动切换 # 2 基于 MySQL 主从同步的状态决定是否切换。
    • 分库  ➡ 表分到不同的库中
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">
      <!--制定规则,customer表分到dataNode2库中-->
      <table name="customer" dataNode="dn2" ></table> </schema>
    <dataNode name="dn1" dataHost="host1" database="orders" /> <dataNode name="dn2" dataHost="host2" database="orders" />
    <dataHost name="host1" maxCon="1000" minCon="10" balance="0"   writeType="0" dbType="mysql" dbDriver="native" switchType="1"   slaveThreshold="100">   <heartbeat>select user()</heartbeat>   <!-- can have multi write hosts -->   <writeHost host="hostM1" url="192.168.140.128:3306" user="root" password="123123">
      </writeHost> </dataHost> <dataHost name="host2" maxCon="1000" minCon="10" balance="0"   writeType="0" dbType="mysql" dbDriver="native" switchType="1"   slaveThreshold="100">   <heartbeat>select user()</heartbeat>   <!-- can have multi write hosts -->   <writeHost host="hostM2" url="192.168.140.127:3306" user="root" password="123123">   </writeHost> </dataHost>
    • 分表  ➡ 数据分到不同的表中(不同的表又在不同的库中) ➡分表基于分库,但多张表是同一种表
    schema.xml
    <
    schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1">   <!--制定规则,customer表分到dn1,dn2两个库中,并且其中的数据根据mode_rule规则分配-->   <table name="customer" dataNode="dn1,dn2" rule="mod_rule"></table> </schema>
    rule.xml
    #在 rule 配置文件里新增分片规则 mod_rule,并指定规则适用字段为 customer_id,
    #还有选择分片算法mod-long(对字段求模运算),customer_id 对两个节点求模,根据结果分片
    #配置算法 mod-long 参数 count 为 2,两个节点
    <tableRule name="mod_rule">
      <rule>
        <columns>customer_id</columns>
        <algorithm>mod-long</algorithm>
      </rule>
    </tableRule>
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod"> <!-- how many data nodes -->   <property name="count">2</property> </function>
      •  E-R表 : 主表进行了分片,其子表也需要根据关联字段进行分片
    <table name="orders" dataNode="dn1,dn2"    rule="mod_rule" >
      <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
    </table>
      • 全局表 : 全局表数据量少,变动不频繁,且很多表都需要其 ➡ 通过数据冗余实现其可以与任意一张表进行关联 ➡ 多个分库中都创建一个全局表,且数据变动一致
    <table name="orders" dataNode="dn1,dn2"    rule="mod_rule" >
      <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id" />
    </table>
    <table name="dict_order_type" dataNode="dn1,dn2" type="global" ></table>
      • 分片规则
        • 取模    根据物理数据库数量进行取模轮询分配
        • 分片枚举   适用于根据固定数量固定值进行分配
        • 范围约定(值/日期)

     

      • 全局序列

          表中数据ID自增带来的问题 : 进行了分表,每个表中ID进行自增,会导致出现重复ID,所以,此时自增ID不可取,MyCat对这种情况做了几种解决方案

          1) 本地文件

            MyCat本地保存一个文件,其中记录ID值,每次新增数据时从此文件中取

            优 本地文件读取效率高

            缺 : 当此台Mycat宕机后,启用另一台Mycat时无法获取之前那个本地文件中的ID值,也就无法决定接下来的ID值

          2) 数据库方式 

            在一个数据库中维护一个ID表,每次新增时查此表,但每次新增都查表,会很浪费IO效率极低,所以Mycat会预加载一部分到内存中,这样大部分序列都是在内存年中完成的。这样用完之后再向数据库请求一段,当此台MyCat宕机后,另一台MyCat重新请求一段序列,而之前的序列不管用完或者没用完都不会再管,这样就不会产生冲突

            优将ID值放到了数据库中,与MyCat状态无关 , 避免了MyCat宕机带来的问题

              以一段序列加载进内存的策略来进行ID值分配,提高了效率,减少了IO

          3) 时间戳方式

            时间戳避免了ID冲突问题,但此ID值过长,浪费空间

          4)自定义ID序列

            Java程序中新增时根据业务指定ID 

            利用Redis单线程原子性incr来生成序列

            缺 这些自定义ID都需要在Java代码中指定ID实现,又增加了耦合度,所以不推荐

  • 相关阅读:
    在Vue.js中使用Stylus预处理器
    前端面试问题(JavaScript)
    前端面试问题(CSS3)
    前端面试问题(HTML5+Http+web)
    VUE2中文文档:组件基础篇
    VUE2中文文档:语法基础笔记
    transition动画效果初识(实例)
    Centos5.2升级openssh7.4p1
    解决python升级导致pip无法使用
    使用jenkins时因为脚本权限问题执行项目失败
  • 原文地址:https://www.cnblogs.com/ying-dong/p/12778686.html
Copyright © 2020-2023  润新知