当前位置: 首页 > 科技观察

浅谈PhxSQL的设计与实现理念(下)

时间:2023-03-20 12:52:24 科技观察

开源地址https://github.com/tencent-wechat/phxsql摘要PhxSQL是一个MySQL集群,在Zookeeper层面提供强一致性和高可用。PhxSQL完全兼容MySQL,建立在简单且逻辑可证明的一致性模型之上,架构、部署和运维都非常简单。文章还讨论了PhxSQL与相关技术方案的区别,并比较了它们的优缺点。文章比较长,正文分为两章。上一章主要讲了why,也就是我们为什么要做PhxSQL,我们为什么要做。下一章重点介绍whynot,也就是为什么我们不支持某些特性,比如多主多写,分库分表,和Galera和MySQLGroupReplication的对比等等。文本PhxSQL[22]自发布以来受到了很多关注。作为一个热爱技术的码农,感谢大家的关心和支持,欢迎一切以技术为出发点的讨论。在“Showyouthecode”之后,我们在这里谈谈PhxSQL的设计和实现理念,同时回答大家提出的一些问题。1.什么是PhxSQL?PhxSQL是一个通过Paxos保证强一致性和高可用的MySQL集群。PhxSQL基于Paxos的一致性和MySQL的binlog管道。主要原理很简单:Paxos选择宿主机host并将本地MySQL设置为可写的MySQL宿主机,在MySQLbinlog写入过程中拦截binlog流,发送给Paxos,形成全局的binlog流备机。设置本地MySQL创建一个只读的MySQL备机。MySQL备机从全局binlog中拉流,重放执行,使主备MySQL保持一致。针对常见的业务场景,PhxSQL提供了两个服务端口:强一致性读写端口(ReadWritePort)和只读端口(ReadonlyPort);对于需要数据强一致性的业务,通过ReadWritePort读写;只需要读取能力但不需要最新数据的读取请求(比如一些时序对账服务),可以通过ReadonlyPort读取,只要有一半以上的机器在工作并连接,PhxSQL就可以正常工作。2、PhxSQL的“强一致性”和“高可用”是什么级别?许多MySQL集群解决方案都声称具有强一致性和高可用性。PhxSQL在这方面有何不同?著名的Zookeeper提供了强一致性和高可用性。一致性有很多级别,从强到弱:Strict(严格一致性)、Linearizable(线性一致性)[1]、Sequential(序列一致性)[2]、Causal(因果一致性)、Eventual等。请参考具体定义参考。严格一致性只是一个理论模型。根据相对论,由于信息的传播速度不可能超过光速,因此在实践中几乎不可能实现严格的一致性。线性一致性的理论定义非常复杂。以一种不太严谨和直观的方式,任何客户端都可以阅读其他客户端编写的最新内容。这也是大家普遍理解的强烈共识。Zookeeper的强一致性指的是“线性一致性”[3]。高可用是指只要有一半以上的机器在工作并相互连接,就可以正常工作,并保证线性一致性的质量。PhxSQL的强一致性指的是“线性一致性”,高可用是指只要有一半以上的机器在工作并相互连接,就可以在线性一致性的质量下工作。即PhxSQL提供了和Zookeeper一样的强一致性和高可用!PhxSQL提供了和Zookeeper一样的强一致性和高可用!PhxSQL提供了和Zookeeper一样的强一致性和高可用!重要的事情说三遍:)。可以使用PhxSQL作为Zookeeper,比如选主!在数据库事务隔离方面,PhxSQL支持最高级别的serializable。在性能方面,PhxSQL提供了明显优于MySQL的半同步写入性能和几乎相同的读取性能[22]。细心的读者可能已经注意到,与通常的“高可用、强一致性”的顺序相反,在本节的标题中,有意将“强一致性”放在了“高可用性”的前面。这里需要澄清一个误解。谈到高可用,有时会有意无意地忽略或降低一致性。严格来说,可用性和一致性必须放在一起讨论,满足一致性要求前提下的可用性才有意义。打个不严谨的比方,一致性好比汽车的“安全性”,易用性就是汽车的“易用性”。如果一辆汽车号称“实用性”好,可以连续工作10年,却只字不提“安全性”,那么这辆车的质量就值得怀疑。3.为什么要做PhxSQL?虽然现在有很多NoSQL和NewSQL系统,还有多主多写的MySQL集群,支持分库分表的MySQL集群,但是传统的MySQL主备同步方案还是有很多新系统没有的优势无法匹配。MySQL主备支持完整的SQL、全局事务、宿主机可重复读、可序列化级别的事务隔离,在金融、账务等关键业务中具有重要价值。同时,将现有的复杂MySQL应用迁移到新的不兼容系统的成本也很高。但是MySQL传统的主备方案也有它的缺点。最明显的是主机故障后的自动换主和新旧主数据的一致性(以及换主后衍生出的主从一致性,各备机之间的一致性,这里不再讨论此处详述),也就是所谓的一致性和可用性。为了解决这个问题,有传统的流派:使用Zookeeper,etcd,或者其他第三方检测心跳,选举master,切换。修改MySQL客户端以使其识别新主机。或者为了让传统的MySQL客户端无需修改就能感知到新主机,部署一个MySQL代理服务器,将连接到自己的MySQL客户端请求透明转发给新主机。为了减少master和backup之间的数据滞后,从而减少oldmaster失效以及当一个backup升级为新master时,新老master之间,新master和其他master之间的差异backups,很多方案都是基于master和backup的同步机制。已经完成了许多有用的工作。比如semi-sync等待大部分备机响应,通过优化线程和网络,多通道主备机,并行执行binlogpipeline等方式来最小化主备机差异。备用机器。如果任何时候master和backup是完全一致的,那么随时换master就是强一致的。这句话的另外一个意思就是,如果不能保证任何时候主备完全一致,那么当有持续更新时,随时变化的主控就不能保证强一致性。传统派的另一个分支是用更可靠的SAN代替MySQL本地磁盘。当MySQL主机出现故障时,将SAN连接到备机提供服务。当SAN出现故障时怎么办?需要跨机房部署怎么办?意识到传统类型的局限性,新发布了Galera和MySQLGroupReplication。除了号称提供强一致性和高可用性外,它还支持master-master多点写入等吸引人的新特性。世界上只有少数经过理论验证和实际测试的共识算法:两阶段提交(2PC)、Paxos[4]、Raft[5]、ZookeeperAtomicBroadcast(ZAB)[3]、ViewstampedReplication[5]等。2PC虽然可以保证一致性,但是当主机出现故障时就无法工作,存在可用性问题。目前Paxos和Raft被业界广泛认可和应用。2PC一般是在前两者的帮助下使用的。这里的一个小建议是:如果一个分布式系统声称支持线性一致性级别的强一致性和高可用性,请先检查它使用的一致性算法。如果是新算法,检查其形式证明或逻辑证明。因此,为了支持线性一致性和高可用,同时完全兼容MySQL,我们在MySQL的基础上应用Paxos来设计开发PhxSQL。4、PhxSQL的设计原则是什么?从实际需求出发,除了前面提到的强一致、高可用、完全兼容MySQL这三个明显且必要的设计原则外,我们还提出以下三个原则。4.1.简单且逻辑上可证明的一致性模型这可能是将PhxSQL与其他解决方案明显区分开来的一个特征。只有经过逻辑证明的模型才是可靠的,基于可靠模型的系统也是可靠的。PhxSQL一致性模型建立在两个前提上:Paxos保证一致性。每个人都可以接受这一点。如果每台MySQL机器的binlog都一致,那么每台MySQL机器之间的数据就是“一致的”。这个假设有点争议。例如,即使binlog流是一致的,由于binlog格式不同,备机replay流的配置不同,主备机之间、不同备机之间的数据也会有不同程度的“差异”。例如,一条与当前时间相关的记录插入操作。某些应用程序可以容忍这种不一致,而其他应用程序则不能。在这里,PhxSQL保证了一致的管道,将格式和配置的自由留给应用程序和DBA根据具体场景来确定。在最严格的配置下,如果binlog一致,数据就会一致。在这两种情况下,PhxSQL的一致性模型使用Paxos使得master机写入Paxos的binlog流水与备机从Paxos拉取的binlog流水保持一致,从而保证了MySQL数据的一致性。我们将单独提供详细的证明过程。模型和证明过程很简单,你也可以看完源码试试:)。但是即使模型是正确的,PhxSQL是否正确地实现了模型?通俗地说,没有bug。编码人员知道这是一个巨大的挑战。从算法和模型到正确实现之间的差距是巨大的。例如,正确实施Paxos具有挑战性[7]。为了尽量减少bug,我们选择了简单易懂、应用广泛的Paxos作为共识协议。为了实现Paxos的“生产”级别,三个主要编码人员独立实现了Paxos。三套Paxos在各自测试正确性后,作为一组Paxos独立节点进行互操作,检查正确性。最后,集体实现一个发布版本的PhxPaxos[21]!除了单元测试和系统测试外,测试环境还独立高频率随机重启机器,并对网络数据包进行乱序、延时、重复等,对系统进行全面测试。可能有读者会问,Paxos速度慢,网络延迟大,为什么PhxSQL不做一个“优化”的版本呢?Paxos有多种版本,例如FastPaxos[19]和EPaxos[20]。但这些都是Paxos,遵循Paxos的基本操作,所做的改变都经过严格形式化或逻辑证明。PhxPaxos严格按照Paxos算法[4]实现,没有任何更改或“优化”。PhxPaxos正常写操作的网络延迟是一个网络RTT,这已经是任何算法理论上可以达到的最快速度。现在,对于PhxSQL来说,切换主机是一个很常见也很容易的操作,就像往MySQL中插入一条数据一样。4.2.对MySQL侵入最小的原则MySQL是一个庞大且快速发展的生态系统,需要保证MySQL在PhxSQL和官方MySQL的兼容性和可升级性。这使得MySQL应用程序可以快速迁移到PhxSQL并在其上运行。这也使得PhxSQL能够快速响应官方MySQL的升级,将PhxSQL中的老版本MySQL升级到新的官方MySQL,从而获得新的特性、性能、稳定性和安全性的提升。这就要求PhxSQL中的MySQL对官方的MySQL尽量少改动。其实PhxSQL版本的MySQL只改变了三个小地方:修改了binlog插件接口中某个函数的参数;新增MySQL启动时检查MySQL本地binlog文件的插件功能,并在MySQL协议中透传增加真实客户端IP,兼容授权功能(如果应用不需要修改).这几个改动很小,而且几乎是一个稳定的过程,所以PhxSQL中的MySQL可以在MySQL官方升级后无缝升级。事实上,我们正在和MySQL社区沟通,希望将这些改动融入到正式版中,让PhxSQL在未来能够充分使用MySQL正式版,同时也让更多人更容易采用PhxSQL。(a)(b)图2:PhxSQL对MySQL的关键修改。(a)是MySQL。(b)是PhxSQL中的MySQL。PhxSQL修改了after_flush函数的参数,增加了MySQL启动时调用的before_recovery函数。也是这个原因,我们没有把PhxSQLProxy和PhxBinlogSvr放到MySQL进程中,因为这样可以减少模块的数量。为保证兼容最广泛使用的MySQL单机版本,在事务层和存储层没有任何干预和修改。4.3.简单的架构、部署和运维在满足需求的前提下,简单的架构有很多好处,比如开发、维护、诊断、维护、可靠性等都更容易。PhxSQL只有3+1个模块。PhxSQL中的MySQL是必需的。PhxBinlogSvr负责全局binlog存储和同步、master选举、集群成员管理等关键功能。在很多MySQL主备集群方案中,通过Zookeeper、etcd、心跳检测、Agent等来承担选主的功能。PhxSQLProxy作为传统MySQL客户端访问PhxSQL中MySQL服务的代理,使得PhxSQL主变更操作对传统MySQL客户端透明。在其他集群方案中,一般会使用代理MySQL代理或者虚拟网关VIP来屏蔽传统MySQL客户端改变集群的master操作,提供透明访问。可选模块是PhxSQLclientlib,修改了MySQL客户端库中的连接初始化函数,允许传入一个集群的PhxSQLProxy列表,这样当一个PhxSQLProxy没有响应时,会自动访问其他可用的PhxSQLProxy来进一步提高可用性。开发者可以直接链接PhxSQL客户端库。PhxSQL的部署和运维非常简单。部署时,只要在目标机器上安装PhxSQL,并在配置中指定集群机器的IP列表,PhxSQL就可以运行。换master的操作已经从运维层面转移到了PhxSQL的正常工作流程中。通常,MySQL集群发生master变更后,可能需要进行数据一致性检查和人肉“闪回”(这可能会违反一致性保证,导致“幻读”);失败“闪退”导致需要清空某个MySQL重新拉取数据备份,流水等,这些耗时、繁重、容易出错的操作在PhxSQL中是完全没有必要的。至于集群成员的热升级和热变更,就更简单了。PhxSQL支持rolling-update,可以逐步升级每台机器。变更集群成员指的是向集群中添加机器、退出机器、更换机器(原子操作)。在保证强一致性和高可用的前提下,热变更(不停止服务器的变更)是非常困难的。PhxSQL通过在Paxos中实现成员变更来解决这个困难。PhxSQL提供了变更操作命令。在新机器上安装并启动PhxSQL后(要求MySQL已经加载了较新的数据备份),您可以在现有集群中一键引入新机器、移除旧机器或两者。这三个操作都是原子操作!新机器会自动跟风。想想看,是不是相当于Zookeeper支持成员热变,是不是很激动人心的功能?PhxSQL在同步层使用Paxos,自然支持多数据中心、多机房的部署。两地三中心部署不成问题。向下。对于PhxSQL来说,多数据中心多机房部署和在机房部署没有区别。PhxSQL的性能取决于大多数机器之间的网络延迟。5.为什么要开源?作为热爱技术的程序员,我们相信开源技术可以让世界变得更美好。从我们日常开发使用的Emacs/Vim、GCC、GDB,到间接为大众提供社交、电商、信息服务的Linux、Apache、MySQL、PHP,再到大众使用的Android对于每天的交流和娱乐,开源是整个互联网的基石,为世界提供了许多至关重要且不可或缺的基础服务。我们充分享受到了开源带来的技术进步、经济发展和社会进步。我们也希望开源的PhxSQL能够回馈社区,帮助更多需要帮助的人。此外,我们希望通过开源来更好地改进PhxSQL。我们欢迎来自志愿者的技术讨论和贡献。我们承诺开源的PhxSQL会一直更新。除了一些与内部运维支撑系统集成的功能(PhxSQL将这些功能抽象成插件,我们已经为内部运维支撑系统实现了这些插件),开源版本和内部版本将保持不变持续的。6.PhxSQL的局限性在不完美的世界里,完美是不存在的。我们坦率地指出了PhxSQL的两个局限性:6.1。MySQL宿主机执行SQLDDL命令(如建库建表命令)时可能存在一致性风险。由于MySQL的innodb引擎不支持DDL回滚,如果宿主机在innodb中commit了这条DDL命令,但是这条命令的binlog在到达PhxSQL拦截点之前已经down了,那么这条DDLbinlog会在全局binlog中丢失,所以备用机器将不会收到此二进制日志。为了保证线性一致性,可序列化级别的事务隔离,以及“最小侵入MySQL”的原则,我们不想提前修改MySQL源码和拦截DDL命令。考虑到DDL命令使用频率较低,我们计划在PhxSQLProxy中加入巡检和后续审计告警。也欢迎大家提出更好的解决方案。6.2.在写请求量很大的系统中,MySQL备机可能会落后很多;如果此时主机挂机,备机暂时无法提升为新的主机,导致系统一段时间不可写。为了保证线性一致性,读取最新数据的请求(通过ReadWritePort发起的读取请求)也会失败;需要等待至少一台standby机器完成tracking并提升为master后,才能响应读取最新数据的请求。对于不需要读取最新数据的请求(通过ReadonlyPort发起的请求),可以从任意一台备机执行,但不保证线性一致性。(注:PhxSQL保证无论MySQL主机的流量领先MySQL备机多少,MySQL主机的binlog流量与全局的binlog流量是一致的,不会造成数据丢失或破坏线性一致性。)一个潜在的问题有了这个模型。事实上,不仅是MySQL主备,任何多副本系统,只要每次写操作不等待所有副本返回,就会出现类似的部分副本掉队的问题;而那些等待所有副本返回的模式,在耗时和可用性方面还有一个问题。好消息是MySQL5.7版本实现了并行复制机制,显着提升了备机流水性能。PhxSQL即将支持MySQL5.7,对于写请求量大的场景,可以很大程度上避免备机赶上流水的情况。说完why,敬请期待《PhxSQL设计和实现哲学》下一章:whynot,就是为什么我们不支持多主多写,分库分表,以及与Galera和MySQLGroupReplication等的对比。