Spring+Hibernate+MySQL的主从分离/读写分离问题
在搭建后台WebAPI框架时遇到MySQL的主从(Master/Slave)分离问题,这里记录一下,遇到相似问题的小伙伴可以参考一下
首先简单说明一下问题由来,MySQL可以支持主从配置,实现数据备份和负载均衡等。
原理是主服务器通过复制把数据同步到从服务器上,可以支持一对多。
主服务器可以读和写,而从服务器只能读。
相比采用MySQL Cluster来实现的分布式部署,这个整体上相对比较简单。
但是要利用主从服务器来降低负载,提高DB性能,这就产生一个主从分离/读写分离的问题。
最笨的方法就是针对Master和Slave写不同的代码,或者写同一套代码配不同服务器。
这个是强烈不推荐的,扩展性和可维护性比较差。
粗略研究了一下,有如下方案:
MySQL Proxy
在Clinet端和DB之间的中间代理,可以支持读写分离。
如果可以实现的话,这个方案个人认为其实是最好的,可以实现Client端和DB端解耦。
然而似乎存在很多问题(比如不支持事务?比如MySQL Proxy本身的问题?等)。
利用MySQL的ReplicationDriver驱动
这个似乎和Hibernate有所冲突,一直报错
使用Spring提供的AbstractRoutingDataSource来动态配置DataSource
本人实在能力有限,前两个方案没有实现,只实现了这个方案
利用第三种方案结合Spring的自定义注解和AOP,来比较方便的在代码中实现指定DataSource,达到读写分离的目的。
但是本质上这种方案还是要配置不同的DataSource,需要在实际的业务代码中实现。
如果有更好的方法,请小伙伴一定要教我一下。
需要注意的问题点
1.对于WebAPI,一个请求一旦配置了一个DataSource后就无法再更改了,要更改的话似乎要涉及到事务处理(这点尚不明确)。
2.DataSource最好在Control层配置。一个API如果有写操作就连接MasterDB,只有读操作就连接SlaveDB。
3.没有注解的情况默认连接MasterDB
4.多个SLAVE时,不要指定到具体哪个SLAVE,随机选择一个SLAVE的DataSource即可。
代码块
代码块语法遵循标准markdown代码,例如:
@Controller
@RequestMapping(value = "/test")
public class TestController extends BaseController {
@RequestMapping(value = "/testmaster", method = {RequestMethod.POST, RequestMethod.GET })
@ResponseBody
@TargetDataSource(name="SLAVE")
public String onTestSlave(HttpServletRequest request, HttpServletResponse response) {
//具体业务
return "result";
}
@RequestMapping(value = "/testslave", method = {RequestMethod.POST, RequestMethod.GET })
@ResponseBody
@TargetDataSource(name="MASTER")
public String onTestMaster(HttpServletRequest request, HttpServletResponse response) {
//具体业务
return "result";
}
}
@TargetDataSource 为自定义注解
具体代码待续…