Mycat分库分表核心技术分析

一、线程模型

1.一、Reactor多线程前端

1.二、处理流程mysql

1) NIOAccetpor中的Selector只接收SocketChannelaccept事件;
2) 
NIOReactor[]数组中依次获取一个NIOReactor;
3) 将此
SocketChannel放到对应NIOReactor中的Queue中;
4) 
NIOReactor新建的Thread,不断循环将Queue中的SocketChannel取出并注册到当前NIOReactor关联的Selector上面;
5) 
不断循环Selector返回的SelectionKey进行数据读取;
6) 
DirectByteBufferPoll分配一块内存(trunk=4k);
7) 
读取SocketChannel中的数据,若是一个trunk能够读完数据则进行认证、mysql协议解析,encode、并调用对应的handler处理。不然计算报文的长度根据size分配足够的内存,并将以前读取的数据copy进来,继续读取直至读完。sql

1.三、流程图数据库

1.四、优势后端

1) 一个NIOAcceptor(聚合了一个Selector,一个线程)能够处理成百上千的客户端链接,每当有一个新的客户端链接时,就从NIOReactor[]数组中顺序获取一个NIOReactor,当达到数组上限时从新返回0,基本保障了NIOReactor间的负载均衡。
2) 
经过NIOReactor[]线程组实现了串行化线程水平并行执行,线程之间没有交集,充分利用多核提高并行处理能力。
3) 
NIOReactor[]线程组互不影响,起到故障隔离做用。
4) 
报文的读取、解析、编码、以及后续Handler的执行,始终都在一个NIOReactor IO线程上面操做,避免了线程上下文切换和并发修复的风险。数组

1.五、缺点网络

1) 维护性差:IO线程和handler业务线程为同一个线程,一旦handler处理(认证、解析、PS渲染、SQL解析、SQL路由)出现延迟,这些延迟毛刺定位难度很大。多线程

1.六、思考并发

1、为何不使用主从Reactor?
2
、为何或怎么能够把IO线程和业务Handler分开?负载均衡

二、内存管理

DirectByteBufferPool启动时向系统申请固定数量(PROCESSORS * 20),大小(512 * 4096)同样的连续内存空间用于建立ByteBufferPageByteBufferPage被切分为固定大小的trunk(4096)经过BitSet位图进行内存的分配和回收,1表明已使用,0表明未使用,在每一个ByteBufferPage上面经过AtomicBoolean实现并发控制。

2.一、分配流程

1) 根据size计算须要的trunk数量,块连续分配,size<4K则分配一个trunk;
2) 
根据上次分配的Page+1,依次从ByteBufferPage[]中取出一个进行分配,报错分配分配相对均衡,同时必定程度上缓解了线程间的竞争。
3) 
分配时先对ByteBufferPage经过AtomicBoolean进行加锁,找到符合数量(BitSet0)的连续空间,经过ByteBufferlimit()position()以及slice()进行分配,同时将对应的BitSet位图置为1,若是找不到则去下个Page中分配;
4) 
若是都没有空间,则再分配异常,再没有则使用HeapByteBuffer

2.二、优势

1) DirectByteBuffer的分配和释放比堆内慢10-20倍,进行池化能够快速分配内存;
2) 
池化技术可使对象复用,下降GC频率。
3) 
trunk块大小相同,BitSet位图内存分配和回收简单;
4) 
作为全局数据,经过设置ByteBufferPage[]数量,缓解多线程环境下的锁竞争;

2.三、缺点

1) 一次性申请完成以后,不能动态扩展;
2) 
固定大小内存,管理的粒度很粗,碎片较大;

2.四、Netty内存管理

Netty内存池的层级结构主要分为,ArenaChunkListChunkPage、SubPage
Arena
:表明一个内存区域,内存池由Arena[]数组组成,分配时每一个线程按照轮训策略选择一个Arena分配。一个Arena由两个PoolSubPageChunkList双向链表组成。
ChunkList
:由多个Chunk组成的双向链表,可动态变化。
Chunk
:每一个Chunk由默认由2048Page组成。
Page
:大小固定,默认8K,经过彻底二叉树管理Page的分配和释放。
SubPage
:大小不固定,又分为tinySubPage,区间[16,512)smallSubPage区间[512,4096),经过位图分配和释放。

三、Druid SQL Parser

代码结构:

1Parser:将SQL转换成AST(抽象语法树),包括Parser(语法解析)和Lexer(词法解析)
2
AST(Abstract Syntax Tree)
3
Visitor:遍历AST的工具
4
、执行流程:词法解析(SQL词库) -> 语法解析(校验是否符合语法逻辑,如from 后面要跟表名) -> 输出AST

 

四、链接池

4.一、定时任务

1) 后端链接检测:SQL执行超时(300s)检查、Idle检查;
2) 
前端链接检测:Idle检查(默认30min);
3) 后端链接健康心跳检测:链接是否正常(被对端关闭,网络断开重连等),维持最小链接;
4) 
数据节点DataHost心跳检测:检测datasource是否可用;
5) 
全局表一致性检测:数据量是否一致;

五、优化和将来

5.一、优化

1) 聚焦而不是膨胀,核心功能和业务需求以前的平滑;
2) 提高统一内存池管理效率,缓解多线程分配时的锁竞争,减小内存碎片;
3) 
杂乱的ScheduledExecutorService定时任务(10个)打乱了NIOReactor串行化设计思想,形成了没有必要的线程上下文切换,可统一管理这些定时任务,参考Netty中的时间轮定时任务;

5.二、将来

一、多维度、立体化、全方位监控体系;
二、便捷、易用的管控运维平台;
3
、分布式数据库(动态扩容、Percolator分布式事务);

 

Ref:

http://www.javashuo.com/article/p-wtfscydu-cy.html

https://www.jianshu.com/p/8d894e42b6e6

https://www.jianshu.com/p/2652686a43eb

相关文章
相关标签/搜索