细说PhxSQL的简单三层架构。对于每一个节点,部署3个模块(PhxSQLProxy、MySQL、PhxBinlogSvr)。多个节点上的PhxBinlogSvr组成一个可靠的日志存储集群和可靠的Master信息存储集群;PhxBinlogSvr同时承担Agent的责任。PhxSQLProxy负责请求的透传。Master结点上的PhxSync负责将MySQL的Binlog发送到PhxBinlogSvr。
PhxSQL基本架构从Proxy(PhxSQLProxy),PhxSync,PhxBinlogSvr细说
Proxy(PhxSQLProxy)
01-请求透传
Proxy的请求透传分两种:
1)读写端口请求透传:Slave节点收到的请求透传给Master节点执行。Master节点收到的请求直接透传给本机MySQL执行。
2)只读端口请求透传:Master节点收到的请求透传给Slave节点执行。
Slave节点收到的请求直接透传给本机MySQL执行。
02-高性能
Proxy接管了MySQL Client的请求,为了使整个集群的读写性能接近单机MySQL,Proxy使用协程模型提高自身的处理能力。
Proxy的协程模型使用开源的Libco库。Libco库是微信团队开源的一个高性能协程库,具有以下特点:
1)用同步方式写代码,实现异步代码的性能。
2)支持千万级的并发连接。
03-完全兼容MySQL
为了已有的应用程序能够不做任何修改就能迁移到PhxSQL,Proxy需兼容MySQL的所有功能。
1)兼容MySQL事务
MySQL事务管理基于连接,同一个事务的所有请求通过同一个连接通信。在事务处理中连接丢失,事务将被rollback。(http://dev.mysql.com/doc/refman/5.6/en/innodb-autocommit-commit-rollback.html)
Proxy使用1:1连接模型完全兼容MySQL事务。每当MySQL Client发起一个连接到Proxy,Proxy都会相应的发起一个连接到MySQL。两条连接中,任意一个中断,另外一个也相应断开,对应的事务会被rollback。
2)兼容MySQL权限
MySQL的权限管理基于(用户,源IP)对,源IP是通过socket句柄反查获取。当请求通过Proxy连接到MySQL时,源IP为Proxy本地IP,权限管理会出现异常。
Proxy利用MySQL协议HEAD保留字段透传真实源IP到MySQ,MySQL再从HEAD保留字段获取正确的源IP进行权限管理。
PhxSync
PhxSync的功能和MySQL的semisync插件类似。经过调研,对semisync插件的接口做少量的调整,就可以使用这些插件接口来实现PhxSync。
PhxSync功能:
1)正常运行时提交Binlog
MySQL在正常写入或者更新数据时,会调用after_flush接口。PhxSync插件通过实现after_flush接口将MySQL新写入的Binlog提交到本机的BinlogSvr,由本机BinlogSvr通过Paxos协议同步到BinlogSvr集群。
2)重启时校准本地Binlog
MySQL在重启时通过查询BinlogSvr集群判断本地Pending Binlog的状态。如果Pending Binlog未复制到BinlogSvr集群则从本地删除,保持本地的Binlog数据和BinlogSvr集群的Binlog数据一致。
由于MySQL没有提供在重启时的插件接口,为了后续维护方便,在MySQL代码层抽象出了一个新插件接口before_binlog_init用于校准Binlog。上述对after_flush接口的调整,和新增的before_binlog_init接口已经提交补丁给MySQL官方。
PhxBinlogSvr
PhxBinlogSvr主要负责存储Binlog和Master信息的维护。在数据复制阶段,通过Paxos协议保证PhxBinlogSvr各节点的数据一致性。(下文称PhxBinlogSvr为BinlogSvr)
01-PhxPaxos库
BinlogSvr使用PhxPaxos库进行数据的复制。PhxPaxos库是微信团队开源的Paxos类库,具有以下特性:
1)保证各节点的数据一致。
2)保证集群机器超过一半存活还能服务。
3)高性能。
4)功能完善。
5)稳定性经过大规模验证。
6)接口方便易用。
02-BinlogSvr异常情况处理
1)防止Slave的节点提交数据
当旧Master在提交数据时由于网络问题数据包被卡在网络,且新Mater已经成功切换时,或者人为错误直接往Slave节点的MySQL写入数据时,则会出现Slave节点提交数据的情况。多节点同时提交数据会出现BinlogSvr的Binlog数据和MySQL存储的Binlog数据不一致的情况。BinlogSvr存储了集群内的Master信息。当其收到MySQL提交的数据时,可根据Master信息拒绝非Master节点的提交。
2) 防止Master提交错误数据
在某些情况下,Master可能会重新发送数据或者发送错误数据。譬如在网络不好的情况下Master由于提交数据超时而重发数据。磁盘发生故障或者数据被错误回滚或者修改的时候,Master会提交错误的数据。
BinlogSvr使用乐观锁机制来防止Master的异常提交。在MySQL提交数据给BinlogSvr时,以本机MySQL已经执行的GTID为乐观锁,提交的内容为(本机MySQL已经执行的最新GTID,本次要提交的Binlog)。BinlogSvr通过检查请求中(本机MySQL已经执行的最新GTID)和自身保存的最新GTID是否匹配来拒绝重新发送或者异常发送的数据。
支持MySQL原生复制协议
为了让Slave能从BinlogSvr获取Binlog,最好的方式就是BinlogSvr支持MySQL原生的复制协议,这样不用对Slave做任何修改。 
Master管理
BinlogSvr除了存储MySQL的Binlog数据,还存储了Master信息。同时还承担了Agent的角色,负责监控MySQL的状态,必要时发起选举自己为Master的投票。
BinlogSvr通过Paxos协议进行Master选举,选举成功后成为Master并拥有租约。通过Paxos协议选举保证了最终只产生一个Master且每个节点记录了一致的Master信息。

