数据库读写分离及问题

简介

  对于数据存储层高并发问题,最先想到的可能就是读写分离,在网站访问量大并且读写不平均的情况下,将存储分为master,slave两台,所有的写都路由到master上,所有的读都路由到slave上,然后master和slave同步。如果一台salve不够,可以加多台,比如一台master,3台slave。对于什么是读写分离,以及读写分离有什么好处,这里不再叙述,有兴趣的可以参考这里 。

在设计读写分离的时候,有几种解决方案:

1. 将读写分离放在dao层,在dao层, 所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于业务层是透明的。

2. 将读写分离放在ORM层,比如mybatis可以通过mybatis plus拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。

3. 放在代理层,比如MySQL-Proxy,这样针对整个应用程序都是透明的。

对于绝大多数情景,读写分离都适用,但是读写分离有一个问题是master slave同步,这个同步是会有一定延迟,因此有几个场景还是要注意的:

场景一

考虑下面一个用户注册场景。

boolean addUserSuccess = userDao.addUser(registUser);
if (addUserSuccess) {
    cachedThreadPool.execute(() -> {
        EmailService.SendActivateEmail(userId);
    });
}
public static void SendActivateEmail(int userId) {
    User user = userDao.getUser(userId);
    String userName = user.getUserName();
    String userEmail = user.getUserEmail();
    String subject = "...";
    String body = "...";
    //调用邮件服务发邮件

}

如上,当新用户注册,在注册完成后,会发一封激活邮件,新增用户是insert,发邮件获取用户是select ,如果master slave存在延迟,有可能在这个时候获取不到用户。

情况二

对于分布式服务系统,都会有一些独立的子服务,比如用户服务,订单服务,这些服务通过http或者rpc访问, 如下是用户服务下的两个接口。

userservice.xx.com/user/userinfo       post请求,用户新增或者更新用户

userservice.xx.com/user/userinfo/1    get请求,用于获取用户信息

这是两个接口服务,一个用于更新用户数据,一个用户获取数据,如果手机APP有一个操作是修改用户名,在调用更新用户接口修改用户名后,紧接着调用获取用户信息的接口,两个请求间隔短,而如果同步延迟,就有可能读取到脏数据。

如何避免

对于上面第一种情况

1. 我们在可以在dao的方法中,再加一个参数,比如:

public User getUser(int userId, boolean isMaster)

业务层决定要在哪个库操作。

2. 根据具体的业务类型,将读写标志位放到线程上下文中。比如对于注册用户的操作,可以在开始处理的时候,在线程上下文中放入一个标志位master,在所有的dao 方法内,判断该标志位,如果是master,则从master读取。这样读写分离是由具体的业务场景决定的。

对于上面第二种情况

1. 简单的方法,就是在请求参数中再加一个参数,服务端根据参数决定要在哪个库操作, 这样增加了前端的一些工作量。

2. 复杂一点的,可以在服务端处理,当修改了用户信息后,可以在redis或者memcache中新增一条Id记录,5秒过期,每次请求的时候,先到memcache中判断一下,对应的id是否存在,如果存在读master, 否则slave。只是这样无形之中增加了服务端的开销。

总结

其实数据延迟没有那么严重,基本都是秒级的,对于上面第二个场景,可能两个请求来回,数据就已经同步好。不会出现脏读的情况,但是在一些特殊的场景下,比如网络抖动,新加字段,可能数据同步延迟会变大,此时master slave的数据会出现不一致,而如果业务上出现上面的两种情景,即insert/update/delete后立刻select,就有可能读不到或者脏读。所以具体把读写分离放在哪一层,还是要根据业务类型和实际情况来决定。

时间: 2024-08-03 19:50:02

数据库读写分离及问题的相关文章

新春好跑步,以及数据库“读写分离”的点滴考虑

新春的好日子: 小风吹来: 花一样的味道: 满满的幸福滋味. 迈开步子在宽敞的马路上跑步,步伐轻盈,多么美好的事情. 跑步总是枯燥的,只有奔跑奔跑: 跑步是孤独的,每个人的都有自己的节奏: 跑步的时候总爱瞎想,昨天和一些同学聊到了数据库的"读写分离". 在我有限的认识中,我一直认为数据库"读写分离",是为了提升数据库的瓶颈,因为数据库写总是相对比较少,而读取可能总是比较多,甚至高几个数量级. 比如一个电子商务网站,把某一个产品上架,可能一个月才需要写一次,但是每天都

【转】mysql数据库读写分离数据同步

转载请注明来源:mysql数据库读写分离数据同步 mysql数据库读写分离数据同步 我是用了两个xp(一个主的,一个从的)的系统测试成功的,linux系统我也做测试了,没有成功,不过我想我所遇到的问题是同一个问题,xp下的可以成功,linux下的应该也可以成功,稍候会测试,然后更新结果! PS:刚测试了下linux 可以同步成功,主服务器是xp,从服务器是centos,可以成功. 例: A机器 192.168.0.2 B机器 192.168.0.3 两个机器可以ping通,互相访问 先配置主服务

spring+mybatis利用interceptor(plugin)兑现数据库读写分离

使用spring的动态路由实现数据库负载均衡 系统中存在的多台服务器是“地位相当”的,不过,同一时间他们都处于活动(Active)状态,处于负载均衡等因素考虑,数据访问请求需要在这几台数据库服务器之间进行合理分配, 这个时候,通过统一的一个DataSource来屏蔽这种请求分配的需求,从而屏蔽数据访问类与具体DataSource的耦合: 系统中存在的多台数据库服务器现在地位可能相当也可能不相当,但数据访问类在系统启动时间无法明确到底应该使用哪一个数据源进行数据访问,而必须在系统运行期间通过某种条

161920、使用Spring AOP实现MySQL数据库读写分离案例分析

一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况).通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master.这样的话就减轻了一台服务器的压力. 在进行读写分离案

asp.net实现数据库读写分离(SQLSERVER2005,ORACLE)【转】

很多时间我们肯定希望数据库的读写与程序是分离,这样可以提高业务量同时提高服务器性能,下面我来以SQL Server 2005为实例来介绍数据库读写分离方法,大家可参考. 下面我们重点介绍Sql Server 2005是如何实现负载均衡的. Sql Server 2005的新特性 SQL Server 2005对端到端(P2P)拓扑结构上事务性的复制加强了支持.P2P的拓扑结构支持无限的发布服务器,它们彼此之间可以互相交换事务. P2P拓扑是SQL Server的一个巨大进步.现在,多端点服务器可

大型网站架构演进(5)数据库读写分离

在使用缓存后,使大部分的数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(包括未命中缓存的,和缓存过期的)和全部的写操作需要访问数据库,当网站的访问量继续增加后,数据库会因为负载压力过高导致成为网站的性能瓶颈. 目前大部分的主流数据库都提供了主从热血功能,通过配置两台数据库的主从关系,可以将一台数据库服务器的数据同步到另一台服务器上,网站利用数据库的这一功能,可以实现数据库的读写分离,从而改善数据库的负载压力. 应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据

使用Spring AOP实现MySQL数据库读写分离案例分析

一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况).通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master.这样的话就减轻了一台服务器的压力. 在进行读写分离案

yii2数据库读写分离配置

原文链接:Yii中文网(yii-china.com)-yii2数据库读写分离配置 简介 数据库读写分离是在网站遇到性能瓶颈的时候最先考虑优化的步骤,那么yii2是如何做数据库读写分离的呢?本节教程来给大家普及一下yii2的数据库读写分离配置. 两个服务器的数据同步是读写分离的前提条件,但这不在yii2读写分离教程内,yii2的数据库读写分离配置,仅仅实现了在主库读写,在从库查询,那么我们首先要配置主从服务器的数据同步.详情查看linux数据库主从同步配置 配置 主从服务器数据库同步完成之后,我们

Spring + Mybatis项目实现数据库读写分离

主要思路:通过实现AbstractRoutingDataSource类来动态管理数据源,利用面向切面思维,每一次进入service方法前,选择数据源. 1.首先pom.xml中添加aspect依赖 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </depen

MariaDB数据库读写分离实现(二):amoeba的使用

本文接上一篇博客:MariaDB数据库读写分离实现(一):mysql-proxy的使用 http://sohudrgon.blog.51cto.com/3088108/1608605 我们将mysql-proxy停止,在节点node5上安装amoeba,测试实现数据库的读写分离. 一.amoeba的简介     Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注分布式数据库 proxy 开发.座落于Clien