`
QING____
  • 浏览: 2249826 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

MySQL Router架构实践

 
阅读更多

    MySQL Router作为InnoDB Cluster(MySQL 7.X)的一部分,它是一个轻量级的中间,可以在Application与下游的MySQL Server之间提供透明的路由方式,它主要用以解决数据库主从库集群的高可用、易于扩展性等。

 

    MySQL Router可以脱离InnoDB Cluster而单独实施,即MySQL 5.6等版本数据库仍然可以使用Router作为其中间代理曾,Router的核心原理为

    1、Router作为一个流量转发层,它的架构层面,位于Application与MySQL Servers之间。

    2、其功能角色,类似于Nginx、LVS等,MySQL Servers作为Router的“upstream”(NAT模式);Application不再直连MySQL Servers,而是与Router相连。根据Router的配置,将会把应用程序的READ、WRITE请求转发给下游的MySQL Servers。

    3、当下游有多个MySQL Servers,无论主、从,那么它可以对READ、WRITE请求进行负载均衡。(loadbalance)

    4、当下游某个Server失效时,Router可以将其从Active列表中移除,当其online后再次加入Active列表,即提供了Failover特性。

    5、当MySQL Servers集群拓扑变更时,比如增减Slaves节点,我们只需要修改Router的配置即可,无需修改Application中JDBC URL配置,因为Application配置的为Router地址而非MySQL Servers的原始地址;即“数据库集群迁移”对Application是透明的。

    6、Router支持集中式部署,即一个Group通常有多个Router节点,但是MySQL官方并没有提供集群的HA,即Router每个节点均为独立,它们之间互不通信,无Leader角色,无选举机制。那么当某个Router节点失效,Application层面需要借助MySQL Connector的高级特性,比如:failover、loadbalance等协议来实现Failover功能。简单而言,Router中间件与Connector的高级协议互相协作,才能够实现请求在Router集群之间的负载均衡、Failover等。

    7、Router中间件,本身不会对请求“拆包”(unpackage),所以我们无法在Router中间件上实现比如“SQL审计”、“隔离”、“限流”、“分库分表”等。但是Router提供了plugin机制,你可以开发自己的plugin来扩展Router的额外特性。(C语言)

    8、如果你的MySQL Servers为5.7+版本,且构建为InnoDB Cluster模式,那么Router还能基于metaCache(metaServers)机制,感知MySQL Servers的主从切换、从库增减等集群拓扑变更,而且基于变更能够实现Master自动切换、Slaves列表自动装配等。比如Master失效后,Cluster将会自动选举一个新的Master,此时Router不需要任何调整、可以自动发现此新Master进而继续为Application服务。

    9、考虑到Router集中式部署可能引入“额外的部署成本”、“性能降级”、“连接数上限”等问题,我们通常建议大家基于“Agent”方式部署,即部署在Application宿主机器上,潜在的问题就是自动化运维设施需要即备。

    10、Router通常是解决“MySQL集群规模性迁移”:比如跨机房部署、流量迁移、异构兼容,或者解决MySQL集群规模性宕机时快速切换等。如果仅仅是为了解决日常的节点增减、读写分离、Failover等,我们仍然建议使用mysql-connector-j支持的“replication”、“loadbalance”协议来实现,基于客户端,而且轻量级。

 

    MySQL Router目前已知的“局限性”:

    1、不支持比如“分库分表”、“SQL审计”等。

    2、在非InnoDB Cluster架构模式下,如果主从库拓扑变更,需要手动修改Router配置。且Router不支持“reload”,修改配置后需要重启,这在一定程度上会影响Application的服务可用性。但是Router的重启非常快,我们通过验证,通常在秒级别。(5S)。

 

    3、MySQL Router非常轻量级,与直连Servers相比,其性能损耗低于1%,我们通过压力测试,100W读写请求总耗时只增长了200多秒。不过摆在Router面前的问题,就是其对链接数的支撑能力,原则上我们一个Router节点限定在500个TCP链接。Router本身CPU、内存、磁盘消耗都极低,但是我们要求Router节点对网络IO的支撑能力应该较强,考虑到Router底层为“异步IO”,如果条件允许,我们应该构建在较高版本的Linux平台下,且给予合理的CPU资源。(目前我们线上为8Core、16G,万兆网卡)。

    备注:MySQL Router在2.1.4版本以下,内核基于select() IO模型,存在连接数500上限、较大SQL请求导致CPU过高,以及并发连接过高时Router假死等问题,建议升级到2.1.6+。

 

    4、Router对连接的管理是基于“粘性”方式,即Application与Router的一个TCP连接,将对应一个Router与MySQL Server的连接,当Application与Router的连接失效时,Router也将断开其与MySQL Server的连接;只要Router上下游网络联通性正常,那么Router将不会主动断开与Application的连接,也不会切换其与Server的连接。即当Application与Router创建一个新连接时,Router将根据负载均衡算法,选择一个Server并与其建立连接,此后将唯一绑定,直到此Server失效时触发重新选择其他Server。

 

    这就引入一个问题,如果某个连接上发生了“繁重”的SQL操作,那么将会导致下游Server伴随高负载而无法“负载均衡”,或许这就是基于TCP NAT代理模式的通病吧。比较有幸的是,我们通常使用DataSource Pool,且MySQL Connector在面对这样的问题时,也有相应的解决办法,参见下文“loadBalanceAutoCommitStatementThreshold”。

 

    5、不能设定权重,即按照权重负载均衡。

 

     MySQL Router部署方案参考(非InnoDB Cluster模式)

 

     针对一组MySQL M-S架构集群,通过有一个Master和多个Slave:

 

    1、针对Master,我们只需要一个Router集群即可,此集群接收WRITE操作。(当然也可以接收读)对于应用而言,它们统一将WRITE操作发给此Router集群,建议三个Router节点。(主要为了避免一个Router节点失效后,至少还有2个节点承载服务,当然节点数量应该与MySQL Server的请求量来综合权衡)

 

    2、考虑到不同的Application可能使用不同的slaves,即按照常规设计,不同的Application使用不同的slaves也是考虑隔离,比如某个Application因为操作不当(慢SQL)不至于将所有的slaves都压垮。那么对于Router集群而言,我们也可以按照Application或者业务组来分割,隔离力度因人而异,建议Router集群的数量不要太多,否则对Router也是浪费、此外运维Router也是一个比较繁杂的事情。

 

     针对Slaves的Router集群,每个集群建议2个节点,当然节点数可以根据slaves个数、请求量等综合考虑。

 

    Router配置参考(${mysqlrouter}/mysqlrouter.conf)

[DEFAULT]
logging_folder=/data/mysql-router/log
runtime_folder=/data/mysql-router/run
data_folder=/data/mysql-router/data

[logger]
level = INFO
[routing:router_rw]
bind_address=0.0.0.0
bind_port=3306
destinations=127.0.0.1:3306,127.0.0.1:3406
client_connect_timeout=6
connect_timeout=3
max_connections=2048
##如果你的master为单节点master,可以使用read-only模式
##当需要master切换时,手动修改此配置文件并重启
mode=read-write
protocol=classic

[routing:router_ro]
bind_address=0.0.0.0
bind_port=4306
destinations=127.0.0.1:4306,127.0.0.1:4307
client_connect_timeout=6
connect_timeout=3
max_connections=1024
mode=read-only
protocol=classic

 

     对于READ、WRITE两种操作,对应两种“mode”,因为Router不对请求拆包,所以它无法判断请求的读写类型,我们只能在配置文件中,分别为读写设定不同的配置:读写使用绑定不同的端口,比如示例中“3306”端口接收到的请求都会转发给master,“4306”端口接收的请求会转发给slaves。当然具体“destinations”中是master还是slave地址,由你来决定,最好保持对应。

 

    原则上,“destinations”中可以指定多个Servers地址,以“,”分割。

 

    1、对于read-write模式:将采用“首个可用”算法,优先使用第一个server,当第一个server(即3306)不可达时,将会Failover到第二个server(3307);依次进行。如果都不可达,那么此端口上的请求将会被中断,不可用,且此时Router将不可用(主要是此port将不能服务)。(需要注意,此算法只遍历一次列表,即逐个验证destinations中的Server,不会循环)

 

       特别注意,一旦所有的Servers依次验证且不可用后,Router将不能继续服务,内装状态设定为aborted,即使此后Servers恢复上线,也不能继续对Client提供服务,因为它不会与Servers保持心跳检测;对于Router而言,直接拒绝Client连接请求,只有重启Router节点才能解决。(我认为这是个Router完全可以解决的问题,不知道为什么却如此设计)

 

    2、对于read-only模式:将采用“轮询”算法,依次选择server新建连接,如果某个Server不可达,将会重试下一个Server,如果所有的Server都不可达,那么此端口上的请求将中断,即READ操作将不可用。同时Router将会持续与每个Server保持心跳探测,当恢复后重新加入Active列表,此后那些新建连接请求将可以分发给此Server。

 

    但是比较遗憾,Router不会将已有的连接重新分配给“新加入”列表的Server,比如Router有2个Server地址(S1,S2),某时刻S1不可达,那么在S1上粘性的客户端连接也将被断开,新建连接将会全部在S2上,此后S1恢复正常,那么在S2上的旧的连接将不会迁移到S1上,此时S1只会接收新的连接,如果没有新连接请求,那么S1将会在一段时间看起来是“不提供服务”的。为了解决此问题,我们要求Connection Pool有管理“连接生命周期”的相关控制,比如一个connection被创建X秒以后在返回连接池时应该被主动关闭,这个参数在tomcat-jdbc-pool中为“maxAge”。

 

 

    如果你的应用程序中,部署方式是单Master、多Slaves(而不是多Master方式或者metaCache + MySQL Cluster架构),我们完全可以在承接“master”请求的Router节点上,也配置为“read-only”模式,那么此单master节点失效重启后,可以不需要重启Router节点即可继续服务。

 

    因为Router不会对TPC拆包,所有“read-write”、“read-only”并不会干扰实际的SQL执行结果,严格来说,这两种mode映射两种“路由算法”:“首个可用”、“轮询”;除此之外,再无特殊含义。(仅限:单Master、多Slave模式,常规HA架构)

 

    Application接入方案

 

    1、mysql-connector-j版本至少在5.1.27以上,建议为5.1.43+。短期内不建议升级为mysql-connector-j 8.x。

    2、连接池组件,优选tomcat-jdbc-pool,建议为8.0.x+,通常与你的tomcat版本互相兼容即可。建议为8.5+。

    3、建议使用JDBC replication协议:此协议有非常多的高级特性,可以认为是客户端级的路由组件,支持“负载均衡”、“failover”等。JDBC URL中地址使用Router集群的地址,Router集群的高可用将借助于replication协议实现,当某个Router节点失效,replication协议可以将请求Failover到URL列表中的其他Router节点。

 

<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql:replication://.../test"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="maxIdle" value="12"/>
    <property name="minIdle" value="2"/>
    <property name="maxActive" value="32"/>
    <property name="maxWait" value="6000"/>
    <property name="initialSize" value="2"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testOnReturn" value="true"/>
    <!-- 必须为true -->
    <property name="defaultAutoCommit" value="true"></property>
    <property name="removeAbandoned" value="true"/>
    <property name="removeAbandonedTimeout" value="60"/>
    <property name="validationQuery" value="SELECT 1"/>
    <property name="validationInterval" value="30000"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis" value="30000"/>
    <property name="minEvictableIdleTimeMillis" value="300000"/>
    <!-- 此参数很重要,建议1分钟 -->
    <property name="maxAge" value="60000"/>
    <property name="jmxEnabled" value="true"/>
</bean>

 

     我们需要特别注意“maxAge”、“defaultAutoCommit”、“testOnBorrow”参数,适度兼容Router的局限性才能更好的发挥作用。

 

    4、JDBC URL范式

jdbc:mysql:replication://address=(type=master)(host=mr1)(port=mp1),address=(type=master)(host=mr2)(port=mp2),address=(type=slave)(host=sr1)(port=sp1)../database

 

    根据上文约定,良好架构下,针对WRITE操作的Router集群应该有3个节点,那么我们需要在URL中指定三个“type=master”的Router地址;此外“type=slave”的地址为接收READ操作的Router节点地址,需要多个。

 

    根据replication协议的设计原理,对于WRITE、READ操作将会在相应的Router节点之间“负载均衡”,默认策略为“轮询”;当其中某个Router失效,replication协议提供了Failover机制,将会把请求路由到同一type的其他Router节点。

 

    此外有几个可以参考的参数,我们配合replication协议:

    1)autoReconnect:设置为false,遵循默认值。

    2)failOverReadOnly:此参数只会在autoReconnect为true时生效,建议保持默认值“true”。

    3)roundRobinLoadBalance:此参数只会在autoReconnect为true、failOverReadOnly为false时生效,建议保持默认值。

    4)readFromMasterWhenNoSlaves:当“type=slave”的所有地址都不可达时,是否可以将read请求转发给master,默认值为“false”,这个值根据实际情况设定,如果你的master可以承载所有的read请求,可以设置为true。

    5)loadBalanceStrategy:可选值为“random”、“bestResponseTime”、“serverAffinity”,默认值为“random”。

    6)loadBalanceAutoCommitStatementThreshold:当请求状态为“autoCommit”时,在一个连接上操作一定次数的请求后,触发“负载均衡”,选在其他Server。(参见源码)。

    7)allowMasterDownConnections:默认值为false,在replication协议中,如果Master无法连接时是否允许Client创建或者获取连接(包括获取Slave的连接)。“false”表示当Master无法连接时,将不能创建任何连接,包括Slave读操作。在基于Router集群时,建议设置为true。

    8)allowSlaveDownConnections:默认为false,同上。

  • 大小: 101.5 KB
分享到:
评论

相关推荐

    mysql最佳实践

    ### MySQL最佳实践详解 #### 一、MySQL简介与特点 MySQL是一种关系型数据库管理系统(RDBMS),它与其他知名的关系型数据库如Oracle、SQL Server、DB2等并驾齐驱,在开源领域内尤其受到广泛欢迎。MySQL以其高效稳定...

    3-2、明溪源-金融行业MySQL高可用实践-1214-v1.01

    具体实施时,可以采用主从结构结合中间件的方式,如MySQL Router,来实现业务访问的负载均衡和故障切换。同时,利用MHA或InnoDB Cluster等工具来确保数据的一致性和业务的连续性。在遇到网络分区或数据中心故障时,...

    MySQL大佬姜承尧49完整课程笔记,进阶涨薪必看,内含MySQL配置文件

    MySQL是世界上最受欢迎的关系型数据库管理系统之一,尤其在Web应用程序中被广泛应用。姜承尧作为知名的MySQL专家,他的课程深入浅出地讲解了MySQL的高级概念和技术,帮助DBA(数据库管理员)和开发者提升技能,从而...

    20191214-金融行业MySQL高可用实践-明溪源-Gdevops1

    随着MySQL版本的升级,Group Replication(InnoDB Cluster)成为新的选择,尤其适合MySQL 8.0+,它提供了自动选主、轻量级中间件MySQL Router、灵活的一致性策略和自动探活功能。然而,Group Replication也存在部署...

    MySQL数据库高可用架构探索.pdf

    在MGR架构中,MySQL Router作为轻量级中间件,帮助应用与数据库之间的通信,实现读写分离和高可用。例如,应用可以直接连接到Router,Router会自动识别并转发写操作到主节点,读操作到从节点。 另一方面,爱可生...

    58同城mysql分库分表实践

    为了解决这一问题,58同城的技术中心分享了他们在MySQL数据库上的分库分表实践,这是一个非常有价值的技术实践,可以帮助理解如何在大数据环境下扩展MySQL数据库。 首先,文档提出了几个基本概念,包括分片...

    MySQL与PostgreSQL数据库高可用分析实践.pptx

    另外,MySQL InnoDB Cluster利用Group Replication提供更高级别的高可用性,通过MySQL Shell进行集群管理和MySQL Router实现负载均衡和故障转移。 PostgreSQL的高可用性也依赖于复制技术,但其机制有所不同。例如,...

    mysql高并发解决方案

    可以使用中间件实现,例如MySQL Proxy或MySQL Router。 3. **分库分表**:水平拆分(Sharding)将大数据量的表分成多个小表,分散到多个数据库服务器上,以提高查询速度。可以采用一致性哈希算法或范围分片策略。 ...

    基于vue+node.js+mysql的校园资产管理系统源码+数据库

    【系统架构】 这个校园资产管理系统采用现代Web开发技术栈,包括前端的Vue.js、后端的Node.js以及关系型数据库MySQL。Vue.js是轻量级的前端框架,以其组件化开发和虚拟DOM特性深受开发者喜爱;Node.js基于...

    基于 SpringBoot + Mybatis Plus + Shiro + mysql + redis构建的智慧云智能教育平台

    Shiro + mysql + redis + sharding-jdbc + canal构建的智慧云智能教育平台,基于数据驱动视图的理念封装 element-ui,即使没有 vue 的使用经验也能快速上手,提供 lambda 、stream api 、webflux 的生产实践。...

    jeecg-boot-masters开箱即用的vue加spring加mysql项目

    《Jeecg-Boot-Masters:Vue+Spring+MySQL一站式开发详解》 Jeecg-Boot-Masters项目是一个集成了Vue.js、MySQL...通过深入学习和实践该项目,开发者不仅能掌握前端与后端的协同开发,还能对微服务架构有更深入的理解。

    mysql-7 (1).pdf

    总之,本课程旨在使学员全面掌握MySQL的性能调优技巧,包括服务器硬件和系统层面的优化、数据库设计和SQL优化,以及高可用性架构如主从复制和读写分离,最终实现MySQL数据库高效稳定运行。通过理论学习与实践操作,...

    开源基础架构和集群最佳实践

    ### 开源基础架构和集群最佳实践 #### 一、测试环境准备 在开始任何实践之前,需要准备一个稳定的测试环境。根据题目中的描述,我们使用两台CentOS 6.5虚拟机作为测试平台。 ##### 1、测试环境交代 - **主机1**:...

    移动电商弹性云架构设计.pptx

    总结来说,移动电商的弹性云架构设计涵盖了APP端的混合架构、服务端的SOA设计、基于容器的虚拟化技术以及相应的实践策略,旨在提供一个高性能、高可用和高度可扩展的电商平台,以应对瞬息万变的市场环境和大规模的...

    【毕设项目】基于SpringBoot+Mybaitsplus+Mysql+Vue的智慧校园管理系统源码+文档.zip

    开发者可以通过Vue Router进行页面路由管理,Vuex进行状态管理,提高应用的可维护性。 5. **智慧校园管理**: 这个系统的具体功能可能包括但不限于:学生信息管理、教师信息管理、课程安排、成绩管理、考勤记录、...

    vue、flask、mysql前后端分离的小项目.zip

    Vue.js、Flask 和 MySQL 是三...这个小项目是学习和实践前后端分离架构的好例子,开发者可以通过它了解如何整合Vue.js、Flask和MySQL来创建一个完整的Web应用。同时,这个项目也适合初学者用来提升自己的全栈开发技能。

    MySQL5.7.18下载和安装过程图文详解

    此外,为确保系统的安全性,建议定期更新MySQL到最新版本,并遵循最佳实践进行数据库管理和维护。 总之,MySQL 5.7.18的下载和安装是一个相对直观的过程,通过遵循上述步骤,即使是初学者也能顺利完成。在安装过程...

    前端vue后端koa数据库采用的mysql开发完整的前后端项目

    在本项目中,我们涉及到的是一个完整的前端与后端开发流程,使用了现代Web开发的主流技术栈。...通过学习和实践,开发者可以更好地理解现代Web应用的架构和工作流程,为今后的项目开发打下坚实基础。

    毕业设计vue+node.js+mysql校园二手交易网(SPA).zip

    该项目是一个基于Vue.js、Node.js和MySQL数据库的校园二手交易网站,主要面向大学生...通过完成此项目,开发者不仅能熟练掌握Vue.js、Node.js和MySQL的使用,还能了解SPA架构的优缺点,以及如何构建一个完整的Web应用。

    基于springboot+mysql+vue的职工管理系统.zip

    同时,Vue CLI提供了快速搭建项目结构的能力,Vue Router则用于处理页面路由,Vuex则用于管理全局状态,使得前端代码组织有序,易于维护。 此外,本系统采用前后端分离的架构,前端通过API与后端进行通信,实现了...

Global site tag (gtag.js) - Google Analytics