死磕数据库系列(九):MySQL 读写分离详解
上一期我们学习了:死磕数据库系列(八):MySQL 主从同步详解 ,当业务量到达一定程度时,数据库的负载压力就会随之越来越明显,这个时候我们就面临如何解决这个问题的困境。我们发现其实数据库大部分的负载压力源于读,而不是写,所以,读写分离技术就随之出现。
但是,有一些技术同学可能对于“读写分离”了解不多,认为数据库的负载问题都可以使用“读写分离”来解决。这其实是一个非常大的误区,我们要用“读写分离”,首先应该明白“读写分离”是用来解决什么样的问题的,而不是仅仅会用这个技术。
读写分离概述
读写分离的基本原理
基本的原理是让主数据库处理事务性增、删、改操作(INSERT、DELETE、UPDATE),而从数据库处理 SELECT 查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
为什么要读写分离
- 面对越来越大的访问压力,单台的服务器性能成为瓶颈,需要分担负载。
- 因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。
- 但是数据库的“读”(读10000条数据可能只要5秒钟)。
- 所以读写分离,解决的是,数据库的写入,影响了查询的效率。
什么时候要读写分离
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。
MySQL读写分离的基础
实现方式主要基于 mysql 的主从复制,通过路由的方式使应用对数据库的写请求只在master上进行,读请求在slave上进行。
实现读写分离的原理与方案
1、基于 MySQL proxy 代理的方式
在应用和数据库之间增加代理层,代理层接收应用对数据库的请求,根据不同请求类型转发到不同的实例,在实现读写分离的同时可以实现负载均衡。
实现原理
开源方案
MySQL的代理常见的是mysql-proxy、cobar、mycat、Atlas等。这种方式对于应用来说,MySQL Proxy是完全透明的,应用则只需要连接到MySQL Proxy的监听端口即可。当然,这样proxy机器可能成为单点失效,但完全可以使用多个proxy机器做为冗余,在应用服务器的连接池配置中配置到多 个proxy的连接参数即可。
- mysql-proxy是一个轻量的中间代理,是官方提供的mysql中间件产品可以实现负载平衡,读写分离,failover等,依靠内部一个lua脚本实现读写语句的判断。项目地址:https://github.com/mysql/mysql-proxy ,该项目已经六七年没有维护了,官方也不建议应用于生成环境。
- cobar是阿里提供的一个中间件,已经停止更新。项目地址:httphttps://github.com/alibaba/cobar
- mycat的前身就是cobar,活跃度比较高,完全使用java语言开发。项目地址:https://github.com/MyCATApache/Mycat-Server,该项目当前已经有8.3k的点赞量。
- moeba(变形虫)是阿里工程师陈思儒基于java开发的一款数据库读写分离的项目(读写分离只是它的一个小功能),与MySQL官方的MySQL Proxy相比,作者强调的是amoeba配置的方便(基于XML的配置文件,用SQLJEP语法书写规则,比基于lua脚本的MySQL Proxy简单)。下载地址:https://sourceforge.net/projects/amoeba/。
- Atlas奇虎360的一个开源中间代理,是在mysql官方mysql-proxy 0.8.2的基础上进行了优化,增加一些新的功能特性。项目地址: https://github.com/Qihoo360/Atlas,该项目当前已经有4.4k的点赞量。
基于应用内路由的方式
基于应用内路由的方式即为在应用程序中实现,针对不同的请求类型去不同的实例执行sql。
- 实现原理
- 实现方案
基于spring的aop实现: 用aop来拦截spring项目的dao层方法,根据方法名称就可以判断要执行的sql类型(即是read还是write类型),进而动态切换主从数据源。类似项目有:
多数据源切换:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter
基于 mysql-connector-java 的 jdbc 驱动方式
- 实现原理
使用mysql驱动Connector/J
的可以实现读写分离。即在jdbc的url中配置为如下的形示:
jdbc:mysql:replication://master,slave1,slave2,slave3/test