分享

MySQL Cluster数据分布/分区,两阶段提交协议及事务资源

 Kitsdk 2014-03-16

MySQL Cluster数据分布/分区,两阶段提交协议及事务资源

MySQL Cluster数据分布和分区

数据分布
  • MySQL Cluster自动分区数据表(也可能使用用户自定义分区),将数据分布到分区中.
  • 一个数据表被划分到多个Data Node分区中,数据在分区中被”striped”
  • 主键的hashing决定哪个分区拥有数据(自动分布)
  • 对主键的一部分进行hashing也是可能的(适合sharding和数据局部性)
分区和数据分布
  • 如果有两个数据节点(DATA NODE 1和DATA NODE 2),每个数据表都被分到两个分区中.
  • subid是主键.对主键subid进行的hashing决定分区.当然对主键的一分部分(part of PK)进行hashing也是可能的.
    -奇数主键(绿色部分)
    -偶数主键(红色部分)

partition1

副本(Replicas)
  • 为了提供冗余和快速故障转移,分区之间是同步复制的.
  • 最常用的是用两个副本(两份数据)
    - 使用1个,2个,3个,4个副本也都是可能的
    - NoOfReplicas=2

    replicas2
    replicas23
  • 分区间的同步复制是从主分区(PRIMARY)到辅助分区(SECONDARY)
    - 当有一个变更(下图实体圆心表示变更)发生在P0的时候,它将同步复制到S0
    - 这个变更在事务commit的时候被持久化
    - P0或S0将被更新,或什么都不做
    partition 22
数据分布 – 磁盘日志记录(disk logging)
  • 数据在commit之后会在主内存中(main memory)
    - 但是改变(changes)是REDO日志记录的(REDO LOGGED),而REDO日志是每N毫秒(推荐1000ms)刷新到磁盘

    • 由TimeBetweenGlobalCheckpoints参数控制
    • 类似innodb-flush-log-at-trx_commit=2

    - 数据同时被checkpoint到磁盘

  • 磁盘日志记录使得恢复一个完全失败的cluster成为可能
节点组(Node groups)
  • 共享同样数据的节点属于同一个节点组
  • 一个节点组包含节点数等于副本数.(下图使用NoOfReplicas=2)
    node groups1
  • 两个副本-四个数据节点
    • 四个数据节点-四个分区-两个副本
    • 四个节点和两个副本–>两个节点组
      - 节点组数目 = 总节点数 / 副本数
    replicas33
  • 三个副本-三个数据节点
    • 三个数据节点-三个分区
      - 更多的副本,“写”更慢
    • 三个节点和三个副本–>一个节点组(这种方式不常用)
      - 两个副本是惯例
    replicas_3_3
  • 副本使用建议
    • 推荐使用两个副本- 性能和可用性是最好的折衷
    • 三个或四个副本写比较慢,使用这种方式部署相对更少
    • “写”成本
      - 1个副本(没冗余): cost X
      - 2个副本: cost 2X
      - 三个副本: cost 3X
验证数据分布

用法:
ndb_desc -c connect_string tbl_name -d db_name [-p]

mysql> select * from ndbtest.tbl;
+---+
| a |
+---+
| 3 |
| 6 |
| 5 |
| 1 |
| 2 |
| 4 |
+---+
6 rows in set (0.01 sec)

mysql>
ndb_desc

两阶段提交协议

关于数据节点
  • 每个节点都有一个活动的Transaction Coordinator(TC)
    - 每个事务都是从TC开始
    - 一个事务包含一个或是多个操作(select/insert/update/delete)
  • 每个节点都有1-4个Local Query Handlers(LQH)
    - 执行操作
  • ACC保存一个哈希表(hash table)
    - 主键和唯一索引
  • TUP保存数据记录
    - ACC的hash索引链接到TUP中的记录
view data node
两阶段提交协议(2PC)
  • 2PC便于实现同步复制
    • 确保主分区和辅助分区的数据修改的一致性
    • 行级别”锁”
  • 2PC由两个阶段组成
    • 准备阶段(Prepare Phase)
      - 获取“锁”
      - 更新到阴影复制(shadow copy)
    • 提交阶段(Commit Phase)
      - 使阴影复制成真的复制(real copy)
      - 释放”锁”
  • 2PC协议仅仅参与update/delete/insert操作
  • “读”操作不是2PC的(否则会非常慢,没什么意义)
2PC第一阶段-准备阶段(Prepare Phase)
  • insert into t1(id,data) values(1,’hello’)
    - 两个数据节点,主键hash到主分区P0
    - update/delete操作也适用
  • 2PC协议从主键所指向的主分区P0的TC开始
    prepare phase1
    • TC从对整个主键进行hash运算(md5sum)开始
      - md5sum(PK)
      - 这样可以得到128位的hash值,分成INDEX_HASH(前64位)和PARTITION_HASH(后64位)
      - 事实上会进行进一步的运算

      • PARTITION = PARTITION_HASH % NO_OF_PARTITIONS
      • INDEX_POS = INDEX_HASH % NO_OF_BUCKETS

      - 实际使用了LH*3算法

    • 这样MySQL Cluster就知道了涉及到哪个节点和分区
    • insert into t1(id,data) values(1,’hello’)
      - INDEX_POS=23
      - PARTITION=P0
  • 在局部的LQH做准备
    prepare_phase_lqh
  • 插入ACC的哈希表(hash table),并将记录写入TUP(给记录分配空间)
    - 现在索引入口(index Entry)就被锁定了

    prepare phase_3
  • 将PREPARE消息发送给辅助分区(S0)的其它LQH,并做同样的事情
    prepare_phase_4
  • 将PREPARE OK消息发回给TC
send_prepare_ok
2PC第二阶段-提交阶段(Commit Phase)
  • 首先给远程的LQH(REMOTE LQH)发送COMMIT消息
    - 释放锁定,简化错误处理,等待“锁”的操作可以很快继续

    commit_phase1
  • 发送COMMIT给P0的LQH
    - 释放“锁”

    commit_phase_2
  • 发送COMMIT OK给TC
    commit_phase_3
  • 发送COMMIT ACK给应用
    commit_phase_4
2PC的失败处理(Failure Handling)
  • 如果事务协调器(Transaction Coordinator)失败了,另一个TC会接管
  • 新的TC会要求节点发送来自失败的TC的未完成事务(outstanding transactions)的清单列表
  • 新的TC会
    - 终止准备阶段(Prepare Phase)的事务
    - 强制提交事务(如果另外的节点已经看到了COMMIT消息)

    • 失败的节点在恢复的时候会获得变更(changes)

事务资源

事务定时器(Transaction Timers)
  • 死”锁”检测–等待”锁”
    - 如果一个事务为”锁”等待太长时间,它会被终止

    • TransactionDeadLockDetectionTimeout=3000[ms]
  • 不活动的事务–正在拥有”锁”
    - 如果一个事务拥有“锁“的时间太长,它会被终止

    • TransactionInactiveTimeout=60000[ms]

    - 不要设置TransactionInactiveTimeout=0

关于”锁”(Locking)
  • 使用的隔离级别是Committed Read
    - 这意味着一个事务将可读到上一次提交的数据,除非是它自己修改这个数据
  • “锁”是在准备阶段(Prepare Phase)获取,在提交阶段(Commit Phase)释放
事务和操作记录(Transaction and Operation Records)
  • 每个事务都要求事务记录-Transaction Record(TR)
    - 在它开始的时候
    - 由MaxNoOfConcurrentTransactions控制
  • 每个操作(Operation)都要求有一个在TC的Operation Record(OR,操作记录)和一个在LQH的Local Operation Record(LOR,局部操作记录)
    - 它属于哪个事务
    - 操作类型
    - 由MaxNoOfConcurrentOperations和MaxNoOfLocalOperations控制
  • 假设:
    - MaxNoOfConcurrentTransactions=3
    - MaxNoOfConcurrentOperations=3
    - MaxNoOfLocalOperations=4

    • 那么默认局部操作(Local Ops)就会比并发操作(Conc Ops)多10%
  • 查询:
    - insert into t1(id,data) values(1,’x');

    • 一次事务
    • 一次操作
事务开始(准备阶段)
  • insert into t1(id,data) values(1,’x');
    transaction_start_prepare_phase
  • 在TC分配一个事务记录
    allocate_transaction_record_at_tc
  • 在TC分配一个操作记录
    allocate_operation_record_tc
  • 在LQH分配一个局部操作记录(Local Operation Record)
    allocate_lor
  • 有很多并行的事务(parallel transactions)
    parallel_transactions
  • 失效切换的错误维度,TRs/ORs不够
    wrongly_dimensioned
  • 事务和操作的参数
    - MaxNoOfConcurrentTransactions=2 X <max_threads>
    - MaxNoOfConcurrentOperations=MaxNoOfConcurrentTransactions X
    - MaxNoOfLocalOperations=1.1 X MaxNoOfConcurrentOperations

    • 默认就是1.1X
    • 很少需要改变这个参数

Comments are closed.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多