简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

17 篇文章 0 订阅
3 篇文章 0 订阅

前言

最近我们的APP在线用户越来越多,接口的响应速度也是越来越慢,经过运维排查发现是由于并发查询太多导致的数据库压力比较大,架构师经过调研给出了数据库读写分离的解决方案,为了快速解决问题,我们最终采用AOP技术实现了数据库读写分离方案。

目录

  1. 什么是数据库读写分离以及为什么要读写分离?
  2. 数据库读写分离实现方式及优缺点分析
  3. 用AOP实现的数据库读写分离方案
  4. 总结

什么是数据库读写分离以及为什么要读写分离?

数据库读写分离,顾名思义就是将数据库的读操作和写操作分开。

传统项目架构中,所有的操作都在同一个数据库执行,在并发量很小的时候这并不会出现什么问题,但是在并发量很大时单个数据库就会出现性能问题。

假设单个数据库的QPS为1000,数据库的并发量为2000,狼多肉少的情况下接口响应速度变慢也就不足为怪了。

数据库读写分离方案的出现就是为了解决这个问题的。

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

项目采用数据库读写分离方案之后共有4个数据库,其中1个主数据库和3个从数据库,主从之间采用binlog文件的方式进行数据同步。主数据库负责处理所有的写操作,从数据库异步进行数据同步;所有的读操作会平均分散到3个从数据库上执行。

数据库读写分离之后,主数据库处理写操作,多个从数据库组成集群共同提供查询服务,原本大并发量的查询操作将被平均分到3个数据库上,从而降低了每个数据库的并发,提升额查询效率;同时还将数据做了冗余备份,增加了系统的抗风险能力。

数据库读写分离实现方式及优缺点分析

根据解决方式所在的层面不同,数据库读写分离主要有3种解决方案:

1、应用层面

实现方式主要是在应用层加一个数据源路由层,将查询操作路由到从库,将写入操作路由到主库。

优点:方案实现起来比较轻便、路由策略可自由控制,扩展性强。

缺点:功能有限,个人要实现完整的方案难度较大,且该方案与代码强耦合,跨语言不通用。

2、中间件层面

实现方式是在应用和数据库之间加一层代理,由代理来转发操作请求。像阿里的MyCat、360的Atlas、美团的DBProxy等都是此类实现方案。

优点:解决方案与应用层代码解耦,通用性较好。

缺点:应用和数据库之间增加了代理层,连接由直连改为代理会导致性能有所下降。

3.数据库驱动层面

实现方式是提供一个支持数据库读写分离的驱动。像Mysql自带的ReplicationDriver驱动、当当开源的Sharding-JDBC、淘宝开源的TDDL等解决方案都是基于数据库驱动层面实现的。

优点:功能丰富、集成方式较简单,应用层面改动较小。

缺点:需使用特定数据库驱动,扩展性较低。

用AOP实现的数据库读写分离方案

采用这个方案一是因为足够轻便,不需要额外增加什么东西;二是因为AOP技术门槛较低,实现起来比较快速。

先介绍一下我们项目的技术背景,项目采用SpringBoot框架开发,采用Mybatis作为ORM层,请求的调用链一般就是Controller调用Service,Service调用Mapper。

方案架构图:

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

主要原理:

一般来讲,我们对于方法的命名会遵循一定的规范,比如插入方法我们会以insert或者save等关键字开头,更新方法我们会以update或edit等关键字开头,查询方法则会以select或find等关键字开头。这种命名习惯可以很好的达到代码自解释性,让人一眼就能望文知意。

我们正好可以利用这个特点来自定义一个AOP切面切到所有Service实现类里的所有方法,再根据方法开头的关键字来切换不同的数据源,最终达到写入操作路由到主数据库,查询操作路由到三台从库的目的。

实现步骤:

1、定义并配置好主数据库和从数据库数据源信息。

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

2、将Mybatis默认使用的数据源改成我们自定义的可动态切换的RoutingDataSource。

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

在RoutingDataSource里,我们将关键字与数据源一一对应起来存入map,key-value对应关系:

write->writeDatasource

read0->read1Datasource

read1->read2Datasource

read2->read3Datasource

3、继承Spring框架的AbstractRoutingDataSource抽象类自定义一个RoutingDataSource类,并实现determineCurrentLookupKey方法,该方法就是我们实现数据源切换的关键所在。

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

determineCurrentLookupKey方法中,我们从DataSourceContext中获取数据源对应的key值。

4、看一下DataSourceContext里面的逻辑:

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

在DataSourceContext里我们定义了一个ThreadLocal变量用来保存该线程所使用的的数据源信息,并且对外提供了两个切换数据源的方法switchToReadDatasource和switchToWriteDatasource。

5、最后来看一下AOP切面类:

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

我们使用@Before注解定义2个切入点,在方法执行前进行切换数据源的增强处理。

在拦截到以select、get、find等关键字开头的读方法时我们切换至读数据源,拦截到以insert、update、delete等关键字开头的写方法时我们切换至写数据源。

写个测试类来测试一下:

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

我们先插入一条数据、再来读取这条数据,看下执行结果:

简单好用!利用Spring AOP技术10分钟实现一个数据库读写分离方案

可以看到,对于insert操作程序自动切换到了write数据源,对于select操作程序又随机切换到了read2数据源。

总结

一般来讲大部分项目都是读多写少,数据量和并发量上去之后,单个数据库往往会面临比较大的性能压力,数据库读写分离方案正好适用于这种读多写少的应用场景

读写分离更多的是扩展了数据库的读能力,多个数据库共同分担读操作可以显著提高系统并发能力。

任何方案有优点肯定也会有缺点,读写分离也不例外。读写分离需要对数据库进行主从架构的改造,增加了系统的复杂性,同时主从之间数据同步也会存在延时,对于需要查询精确数据的业务来说可能并不合适。

对于轻量级的业务来讲,如果需要快速实现数据库的读写分离可以采用AOP自己实现读写分离方案;如果有足够的人力和技术,可以从系统层面对项目进行读写分离的改造,个人倾向于采用驱动层的一些开源解决方案,如Sharding-JDBC。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值